[Rd] stopifnot -- eval(*) inside for()
Martin Maechler
m@ech|er @end|ng |rom @t@t@m@th@ethz@ch
Mon Apr 1 12:00:02 CEST 2019
>>>>> Suharto Anggono Suharto Anggono via R-devel
>>>>> on Sun, 31 Mar 2019 15:26:13 +0000 writes:
> Ah, with R 3.5.0 or R 3.4.2, but not with R 3.3.1, 'eval'
> inside 'for' makes compiled version behave like
> non-compiled version.
Ah.. ... thank you for detecting that " eval() inside for()" behaves
specially in how error message get a call or not.
Let's focus only on this issue here.
I'm adding a 0-th case to make even clearer what you are saying:
> options(error = expression(NULL))
> library(compiler)
> enableJIT(0)
> f0 <- function(x) { x ; x^2 } ; f0(is.numeric(y))
Error in f0(is.numeric(y)) (from #1) : object 'y' not found
> (function(x) { x ; x^2 })(is.numeric(y))
Error in (function(x) { (from #1) : object 'y' not found
> f0c <- cmpfun(f0) ; f0c(is.numeric(y))
so by default, not only the error message but the originating
call is shown as well.
However, here's your revealing examples:
> f <- function(x) for (i in 1) {x; eval(expression(i))}
> f(is.numeric(y))
> # Error: object 'y' not found
> fc <- cmpfun(f)
> fc(is.numeric(y))
> # Error: object 'y' not found
I've tried more examples and did not find any difference
between simple interpreted and bytecompiled code {apart
from "keep.source=TRUE" keeping source, sometimes visible}.
So I don't understand yet why you think the byte compiler plays
a role.
Rather the crucial difference seems the error happens inside a
loop which contains an explicit eval(.), and that eval() may
even be entirely unrelated to the statement in which the error
happens [above: The error happens when the promise 'x' is
evaluated, *before* eval() is called at all].
> Is this accidental feature going to be relied upon?
[i.e. *in stopifnot() R code (which in R-devel and R 3.5.x has
had an eval() inside the for()-loop)]
That is a good question.
What I really like about the R-devel case: We do get errors
signalled that do *not* contain the full stopifnot() call.
With the newish introduction of the `exprs = { ... ... }` variant,
it is even more natural to have large `exprs` in a stopifnot() call,
and when there's one accidental error in there, it's quite
unhelpful to see the full stopifnot(..........) call {many lines
of R code} obfuscating the one statement which produced the
error.
So it seems I am asking for a new feature in R,
namely to temporarily say: Set the call to errors to NULL "in
the following".
In R 3.5.x, I had used withCallingHandlers(...) to achieve that
and do even similar for warnings... but needed to that for every
expression and hence inside the for loop and the consequence
was a relatively large slowdown of stopifnot().. which
triggered all the changes since.
Whereas what we see here ["eval() inside for()"] is a cheap
automatic suppression of 'call' for the "internal errors", i.e.,
those we don't trigger ourselves via stop(simplError(...)).
More information about the R-devel
mailing list