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.

options(error = expression(NULL))
library(compiler)
enableJIT(0)
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

Is this accidental feature going to be relied upon?


"Details" section of 'stopifnot' documentation in current R 3.6.0 alpha 
(https://svn.r-project.org/R/branches/R-3-6-branch/src/library/base/man/stopifnot.Rd)
 has this.

  Since \R version 3.6.0, \code{stopifnot()} no longer handles potential
  errors or warnings (by \code{\link{tryCatch}()} etc) for each single
  expression but rather aims at using the correct
  \code{\link{sys.call}(<n>)} to get the most meaningful error message in
  case of an error.  This provides considerably less overhead.

I think part of the first sentence starting from "but rather" should be removed 
because it is not true.


The next paragraph:

  Since \R version 3.5.0, expressions \emph{are} evaluated sequentially,
  and hence evaluation stops as soon as there is a \dQuote{non-TRUE}, as
  indicated by the above conceptual equivalence statement.
  Further, when such an expression signals an error or
  \code{\link{warning}}, its \code{\link{conditionCall}()} no longer
  contains the full \code{stopifnot} call, but just the erroneous
  expression.

As I said earlier 
(https://stat.ethz.ch/pipermail/r-devel/2019-February/077386.html), the last 
sentence above is not entirely true. It may say something like:
Furher, when such an expression signals an error, stopifnot() in R 3.5.x makes 
its conditionCall() the erroneous expression, but no longer since R 3.6.0.


Is it OK that, for
do.call(stopifnot, list(exprs = expression())) ,
the whole expression object is taken as one?


End portion from running
example(stopifnot)
in R 3.5.0:
stpfnt> stopifnot(all.equal(pi, 3.141593),  2 < 2, all(1:10 < 12), "a" < "b")
Error in eval(ei, envir) : pi and 3.141593 are not equal:
  Mean relative difference: 1.102658e-07

To me, "in eval(*)" is rather surprising and annoying and doesn't add clarity. 
Yes, stop() gives the same. But, in this case, just "Error", like in R before 
version 3.5.0, feels better to me. If
stop(simpleError(msg, call = if(p <- sys.parent()) sys.call(p)))
were used in 'stopifnot', just "Error" would be given in this case.

--------------------------------------------

 wrote:

 Subject: Re: [Rd] stopifnot
 To: r-devel@r-project.org
 Date: Thursday, 7 March, 2019, 3:43 PM

[...]

As far as I can see, full stopifnot(...) call can only appear from an error 
that happens during evaluation of an argument of 'stopifnot'. Because the error 
is not raised by 'stopifnot', the call in the error has nothing to do with how 
'n' is computed in sys.call(n-1) , or even with use of sys.call(n-1) itself.

if(n > 1) sys.call(n-1)
that I proposed previously was aimed to be like
sys.call(-1)
in 'stopifnot' in R 3.5.x. Negative number counts back from current frame. The 
value of 'n' is sys.nframe() or (sys.nframe()-3). In my patch, 
stopifnot(exprs=*) drives stopifnot(...) call via 'eval'. I found that frames 
were generated for
stopifnot (exprs) -> eval -> eval (.Internal) -> stopifnot (...)
>From stopifnot (...) , reaching stopifnot (exprs) takes 3 steps back.


[...]

options(error = expression(NULL))
library(compiler)
enableJIT(0)
f <- function(x) for (i in 1) x
f(is.numeric(y))
# Error: object 'y' not found
fc <- cmpfun(f)
fc(is.numeric(y))
# Error in fc(is.numeric(y)) : object 'y' not found

The above illustrates what happens in current 'stopifnot' without 
'withCallingHandlers' or 'tryCatch'. For error during 'for', non-compiled and 
compiled versions are different. It surprised me.

[...]


With my revised patch, the 'else' clause for 'cl' gives
call("expression", exprs) .
For
do.call(stopifnot, list(exprs = expression())) ,
the whole expression object is taken as one.

do.call(stopifnot, list(exprs = expression(1==1, 2 < 1, stop("NOT GOOD!\n"))))
Error in do.call(stopifnot, list(exprs = expression(1 == 1, 2 < 1, stop("NOT 
GOOD!\n")))) : 
  expression(1 == 1, 2 < 1, stop("NOT GOOD!\n")) are not all TRUE

To be the same as in R 3.5.x, the 'else' can be
as.call(c(quote(expression), as.expression(exprs)))

--------------------------------------------
On Wed, 6/3/19, Martin Maechler <maech...@stat.math.ethz.ch> wrote:

Subject: Re: [Rd] stopifnot

r-project.org
Cc: "Martin Maechler" <maech...@stat.math.ethz.ch>
Date: Wednesday, 6 March, 2019, 3:50 PM

>>>>> Martin Maechler 
>>>>>    on Tue, 5 Mar 2019 21:04:08 +0100 writes:

>>>>> Suharto Anggono Suharto Anggono 
>>>>>    on Tue, 5 Mar 2019 17:29:20 +0000 writes:

[...]

    >> After thinking again, I propose to use
    >>         stop(simpleError(msg, call = if(p <- sys.parent()) sys.call(p)))

    > That would of course be considerably simpler indeed,  part "2 a" of these:

    >> - It seems that the call is the call of the frame where stopifnot(...) 
is evaluated. Because that is the correct context, I think it is good.
    >> - It is simpler and also works for call that originally comes from 
stopifnot(exprs=*) .

    >> - It allows shortcut ('assert') to have the same call in error message 
as stopifnot(exprs=*) .

    > That may be another good reason in addition to code simplicity.

    > I will have to see if this extra simplification does not loose
    > more than I'd want.


    >> Another thing: Is it intended that
    >> do.call("stopifnot", list(exprs = expression()))
    >> evaluates each element of the expression object?

    > ??  I really don't know.  Even though such a case looks
    > "unusual" (to say the least), in principle I'd like that
    > expressions are evaluated sequentially until the first non-TRUE
    > result.  With a concrete example, I do like what we have
    > currently in unchanged R-devel, but also in R 3.5.x, i.e., in
    > the following, not any "NOT GOOD" should pop up:

    >> stopifnot(exprs = expression(1==1, 2 < 1, stop("NOT GOOD!\n")))
    > Error: 2 < 1 is not TRUE
    >> do.call(stopifnot, list(exprs = expression(1==1, 2 < 1, stop("NOT 
GOOD!\n"))))
    > Error in do.call(stopifnot, list(exprs = expression(1 == 1, 2 < 1, 
cat("NOT GOOD!\n")))) : 
    > 2 < 1 is not TRUE
    >> 

    > Hmm, it seems I do not understand what you ask above in your
    > "Another thing: .."


    >> If so, maybe add a case for 'cl', like
    >>         else if(is.expression(exprs))
    >>         as.call(c(quote(expression), exprs))

    > that seems simple indeed, but at the moment, I cannot see one example
    > where it makes a difference ... or then I'm "blind" .. ???

    > Best,
    > Martin

Some more testing of examples lead me to keep the more
sophisticated "computation" of 'n'  for the  sys.call(n-1).

Main reason:  If one of the expression is not all TRUE, I really
don't want to see the full 'stopifnot(....)' call in the printed
error message.
I do want to encourage that  stopifnot()  asserts many things
and so its own call should really not be shown.

Also I really wanted to commit something, notably also fixing
the  stopifnot(exprs = T)  bug,  so R-devel (rev >= 76203 ) now
contains a simpler and much faster  stopifnot() than previously
[and than the R 3.5.x series].

I agree that the final decisions on getting a call (or not --
which was a very good idea by you!) and which parent's call
should be used  may deserve some future tinkering..

Thank you again, Suharto Anggono,
[[elided Yahoo spam]]


Martin

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to