[Rd] stopifnot() does not stop at first non-TRUE argument

Serguei Sokol sokol at insa-toulouse.fr
Mon May 15 12:48:41 CEST 2017


Hello,

I am a new on this list, so I introduce myself very briefly:
my background is applied mathematics, more precisely scientific calculus
applied for modeling metabolic systems, I am author/maintainer of
few packages (Deriv, rmumps, arrApply).

Now, on the subject of this discussion, I must say that I don't really understand
Peter's argument:

     >>> To do it differently, you would have to do something like
     >>>
     >>> dots <- match.call(expand.dots=FALSE)$...
     >>>
     >>> and then explicitly evaluate each argument in turn in the caller
     >>> frame. This amount of nonstandard evaluation sounds like it would
     >>> incur a performance penalty, which could be undesirable.
The first line of the current stopifnot()
n <- length(ll <- list(...))
already evaluates _all_ of the arguments
in the caller frame. So to do the same only
on a part of them (till the first FALSE or NA occurs)
cannot be more penalizing than the current version, right?

I attach here a slightly modified version called stopifnot_new()
which works in accordance with the man page and
where there are only two additional calls: parent.frame() and eval().
I don't think it can be considered as real performance penalty
as the same or bigger amount of (implicit) evaluations was
already done in the current version:

> source("stopifnot_new.R")
> stopifnot_new(3 == 5, as.integer(2^32), a <- 12)
Error: 3 == 5 is not TRUE
> a
Error: object 'a' not found

Best,
Serguei.


Le 15/05/2017 à 10:39, Martin Maechler a écrit :
>>>>>> Hervé Pagès <hpages at fredhutch.org>
>>>>>>      on Wed, 3 May 2017 12:08:26 -0700 writes:
>      > On 05/03/2017 12:04 PM, Hervé Pagès wrote:
>      >> Not sure why the performance penalty of nonstandard evaluation would
>      >> be more of a concern here than for something like switch().
>
>      > which is actually a primitive. So it seems that there is at least
>      > another way to go than 'dots <- match.call(expand.dots=FALSE)$...'
>
>      > Thanks, H.
>
>      >>
>      >> If that can't/won't be fixed, what about fixing the man page so it's
>      >> in sync with the current behavior?
>      >>
>      >> Thanks, H.
>
> Being back from vacations,...
> I agree that something should be done here, if not to the code than at
> least to the man page.
>
> For now, I'd like to look a bit longer into a possible change to the function.
> Peter mentioned a NSE way to fix the problem and you mentioned switch().
>
> Originally, stopifnot() was only a few lines of code and meant to be
> "self-explaining" by just reading its definition, and I really would like
> to not walk too much away from that original idea.
> How did you (Herve) think to use  switch()  here?
>
>
>
>      >> On 05/03/2017 02:26 AM, peter dalgaard wrote:
>      >>> The first line of stopifnot is
>      >>>
>      >>> n <- length(ll <- list(...))
>      >>>
>      >>> which takes ALL arguments and forms a list of them. This implies
>      >>> evaluation, so explains the effect that you see.
>      >>>
>      >>> To do it differently, you would have to do something like
>      >>>
>      >>> dots <- match.call(expand.dots=FALSE)$...
>      >>>
>      >>> and then explicitly evaluate each argument in turn in the caller
>      >>> frame. This amount of nonstandard evaluation sounds like it would
>      >>> incur a performance penalty, which could be undesirable.
>      >>>
>      >>> If you want to enforce the order of evaluation, there is always
>      >>>
>      >>> stopifnot(A) stopifnot(B)
>      >>>
>      >>> -pd
>      >>>
>      >>>> On 3 May 2017, at 02:50 , Hervé Pagès <hpages at fredhutch.org>
>      >>>> wrote:
>      >>>>
>      >>>> Hi,
>      >>>>
>      >>>> It's surprising that stopifnot() keeps evaluating its arguments
>      >>>> after it reaches the first one that is not TRUE:
>      >>>>
>      >>>> > stopifnot(3 == 5, as.integer(2^32), a <- 12) Error: 3 == 5 is
>      >>>> not TRUE In addition: Warning message: In stopifnot(3 == 5,
>      >>>> as.integer(2^32), a <- 12) : NAs introduced by coercion to integer
>      >>>> range > a [1] 12
>      >>>>
>      >>>> The details section in its man page actually suggests that it
>      >>>> should stop at the first non-TRUE argument:
>      >>>>
>      >>>> ‘stopifnot(A, B)’ is conceptually equivalent to
>      >>>>
>      >>>> { if(any(is.na(A)) || !all(A)) stop(...); if(any(is.na(B)) ||
>      >>>> !all(B)) stop(...) }
>      >>>>
>      >>>> Best, H.
>      >>>>
>      >>>> --
>      >>>> Hervé Pagès
>      >>>>
>      >>>> Program in Computational Biology Division of Public Health
>      >>>> Sciences Fred Hutchinson Cancer Research Center 1100 Fairview
>      >>>> Ave. N, M1-B514 P.O. Box 19024 Seattle, WA 98109-1024
>      >>>>
>      >>>> E-mail: hpages at fredhutch.org Phone: (206) 667-5791 Fax: (206)
>      >>>> 667-1319
>      >>>>
>      >>>> ______________________________________________
>      >>>> R-devel at r-project.org mailing list
>      >>>> https://urldefense.proofpoint.com/v2/url?u=https-3A__stat.ethz.ch_mailman_listinfo_r-2Ddevel&d=DwIFaQ&c=eRAMFD45gAfqt84VtBcfhQ&r=BK7q3XeAvimeWdGbWY_wJYbW0WYiZvSXAJJKaaPhzWA&m=JwgKhKD2k-9Kedeh6pqu-A8x6UEV0INrcxcSGVGo3Tg&s=f7IKJIhpRNJMC3rZAkuI6-MTdL3GAKSV2wK0boFN5HY&e=
>      >>>>
>      >>>
>      >>
>
>      > -- Hervé Pagès
>
>      > Program in Computational Biology Division of Public Health Sciences
>      > Fred Hutchinson Cancer Research Center 1100 Fairview Ave. N,
>      > M1-B514 P.O. Box 19024 Seattle, WA 98109-1024
>
>      > E-mail: hpages at fredhutch.org Phone: (206) 667-5791 Fax: (206)
>      > 667-1319
>
>      > ______________________________________________
>      > R-devel at r-project.org mailing list
>      > https://stat.ethz.ch/mailman/listinfo/r-devel
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



More information about the R-devel mailing list