From luke at stat.uiowa.edu  Sat Mar 12 05:03:52 2005
From: luke at stat.uiowa.edu (Luke Tierney)
Date: Sat Mar 12 05:04:17 2005
Subject: [Rd] delay() has been deprecated for 2.1.0
In-Reply-To: <4D99275E380CA94F998977EDACE548DC0625CE@extas2-hba.tas.csiro.au>
References: <4D99275E380CA94F998977EDACE548DC0625CE@extas2-hba.tas.csiro.au>
Message-ID: <Pine.LNX.4.61.0503112145500.18283@itasca2.stat.uiowa.edu>

On Sat, 12 Mar 2005 Mark.Bravington@csiro.au wrote:

> Uh-oh... I've just written a bunch of code for 'mvbutils' using 'delay', and am worried by the statement that "there should be no way to see a <promise:...> object in R". At present, it's possible to check whether 'x' is a promise via e.g. 'class( .GlobalEnv$x)'. This will be different to 'class( x)' if 'x' is a promise, regardless of whether the promise has or has not been forced yet. This can be very useful; my recent code relies on it to check whether certain objects have been changed since last being saved. [These certain objects are originally assigned as promises to load from individual files. Read-accessing the object keeps it as class 'promise', whereas write-access creates a non-promise. Thus I can tell whether the individual files need re-saving when the entire workspace is saved.]

Relying on undocumented features when designing a package is not a
good idea.  In this case the feature of env$x returning a promise
contradicts the documentation and is therefore a bug (the
documentation says that env$x should behave like the corresponding
get() expression, and that forcec promises and returns their values).

>
> The has-it-changed test has been very valuable to me in allowing fast handling of large collections of large objects (which is why I've been adding this functionality to 'mvbutils'); and apart from is-it-still-a-promise, I can't think of any other R-level way of testing whether an object has been modified. [If there is another way, please let me know!]
>
> Is there any chance of retaining *some* R-level way of checking whether an object is a promise, both pre-forcing and post-forcing? (Not necessarily via the 'class( env$x)' method, if that's deemed objectionable.)

This would not be a good idea.  The current behavior of leaving an
evaluated promise in place is also not a documented feature as far as
I can see.  It is a convenient way of implementing lazy evaluation in
an interpreter but it has drawbacks.  One is the cost of the extra
dereference.  Another is the fact that these promises keep alive their
environments that might otherwise be inaccessible and hence available
for GC.  These environments might in turn reference large data
structures, keeping them alive.  At this point it seems too complicated
to deal with this in the interpreter, but a compiler might be able to
prove that a promise can be safely discarded.  (In fact a compiler
might be able to prove that a promise is not needed in the first
place).

There are other possible approaches that you might use, such as active
bindings (see the help for makeActiveBinding).  If that won't do we
can look into developing a suitable abstraction that we can implement
and document in a way that does not tie the hands of the internal
implementation.

Best,

luke

> Mark Bravington
> mark.bravington@csiro.au
>
>
> 	-----Original Message-----
> 	From: r-devel-bounces@stat.math.ethz.ch on behalf of Duncan Murdoch
> 	Sent: Sat 12/03/2005 3:05 AM
> 	To: r-devel@stat.math.ethz.ch
> 	Cc: Gregory Warnes; David Brahm; Torsten Hothorn; Nagiza F. Samatova
> 	Subject: [Rd] delay() has been deprecated for 2.1.0
>
>
>
> 	After a bunch of discussion in the core group, we have decided to
> 	deprecate the delay() function (which was introduced as "experimental"
> 	in R 0.50).  This is the function that duplicates in R code the
> 	delayed evaluation mechanism (the promise) that's used in evaluating
> 	function arguments.
>
> 	The problem with delay() was that it was handled inconsistently (e.g.
> 	sometimes you would see an object displayed as <promise:...>,
> 	sometimes it would be evaluated); it tended to be error-prone in usage
> 	(e.g. this was the cause of the bug that makes the curve() function
> 	create a "pu" object in the global environment); and it was generally
> 	difficult to figure out exactly what the semantics of it should be in
> 	order to be consistent.
>
> 	delay() has been replaced with delayedAssign().  This new function
> 	creates a promise and assigns it into an environment.  Once one more
> 	set of changes is made and delay() is gone, there should be no way to
> 	see a <promise: ...> object in R:  as soon as the object is accessed,
> 	it will be evaluated and you'll see the value.
>
> 	A few packages made use of delay().  I have replaced all of those uses
> 	with delayedAssign().  The most common usage was something like the QA
> 	code uses:
>
> 	assign("T", delay(stop("T used instead of TRUE")),
> 	                  pos = .CheckExEnv)
>
> 	This translates to
>
> 	delayedAssign("T", stop("T used instead of TRUE"), eval.env =
> 	.GlobalEnv, assign.env = .CheckExEnv)
>
> 	In most cases the "eval.env = .GlobalEnv" argument is not necessary
> 	(and in fact it is often a bug, as it was in curve()).  The
> 	environment where the promise is to be evaluated now defaults to the
> 	environment where the call is being made, rather than the global
> 	environment, and this is usually what you want.
>
> 	Package writers who use delay() will now get a warning that it has
> 	been deprecated.  They should recode their package to use
> 	delayedAssign instead.
>
> 	Examples from CRAN of this (I am not sure if this list is exhaustive):
>
> 	exactRankTests, genetics, g.data, maxstat, taskPR, coin
>
> 	I have cc'd the maintainers of those packages.
>
> 	If you want a single code base for your package that works in both the
> 	upcoming R 2.1.0 and older versions, this presents a problem: older
> 	versions don't have delayedAssign.  Here is a workalike function that
> 	could be used in older versions:
>
> 	delayedAssign <- function(x, value,
> 	                eval.env = parent.frame(),
> 	                assign.env = parent.frame()) {
> 	 assign(x, .Internal(delay(substitute(value), eval.env)),
> 	           envir = assign.env)
> 	}
>
> 	Because this function calls the internal delay() function directly, it
> 	should work in R 2.1.0+ as well without a warning, but the internal
> 	function will eventually go away too, so I don't recommend using it in
> 	the long term.
>
> 	Sorry for any inconvenience that this causes.
>
> 	Duncan Murdoch
>
> 	______________________________________________
> 	R-devel@stat.math.ethz.ch mailing list
> 	https://stat.ethz.ch/mailman/listinfo/r-devel
>
> ______________________________________________
> R-devel@stat.math.ethz.ch mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

-- 
Luke Tierney
Chair, Statistics and Actuarial Science
Ralph E. Wareham Professor of Mathematical Sciences
University of Iowa                  Phone:             319-335-3386
Department of Statistics and        Fax:               319-335-3017
    Actuarial Science
241 Schaeffer Hall                  email:      luke@stat.uiowa.edu
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu


[Rd] delay() has been deprecated for 2.1.0
Luke Tierney