Martin Maechler
2017-May-15 08:39 UTC
[Rd] stopifnot() does not stop at first non-TRUE argument
>>>>> 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
Serguei Sokol
2017-May-15 10:48 UTC
[Rd] stopifnot() does not stop at first non-TRUE argument
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
Serguei Sokol
2017-May-15 11:14 UTC
[Rd] stopifnot() does not stop at first non-TRUE argument
I see in the archives that the attachment cannot pass.
So, here is the code:
8<----
stopifnot_new <- function (...)
{
mc <- match.call()
n <- length(mc)-1
if (n == 0L)
return(invisible())
Dparse <- function(call, cutoff = 60L) {
ch <- deparse(call, width.cutoff = cutoff)
if (length(ch) > 1L)
paste(ch[1L], "....")
else ch
}
head <- function(x, n = 6L) x[seq_len(if (n < 0L) max(length(x) +
n, 0L) else min(n, length(x)))]
abbrev <- function(ae, n = 3L) paste(c(head(ae, n), if (length(ae) >
n) "...."), collapse = "\n ")
pfr <- parent.frame()
for (i in 1L:n) {
cl.i <- mc[[i + 1L]]
r <- eval(cl.i, pfr)
if (!(is.logical(r) && !anyNA(r) && all(r))) {
msg <- if (is.call(cl.i) && identical(cl.i[[1]],
quote(all.equal)) &&
(is.null(ni <- names(cl.i)) || length(cl.i) == 3L ||
length(cl.i <- cl.i[!nzchar(ni)]) == 3L))
sprintf(gettext("%s and %s are not equal:\n %s"),
Dparse(cl.i[[2]]), Dparse(cl.i[[3]]), abbrev(r))
else sprintf(ngettext(length(r), "%s is not TRUE",
"%s are not all TRUE"),
Dparse(cl.i))
stop(msg, call. = FALSE, domain = NA)
}
}
invisible()
}
8<----
Best,
Serguei.
Le 15/05/2017 ? 12:48, Serguei Sokol a ?crit :> 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
>
Maybe Matching Threads
- stopifnot() does not stop at first non-TRUE argument
- stopifnot() does not stop at first non-TRUE argument
- stopifnot() does not stop at first non-TRUE argument
- stopifnot() does not stop at first non-TRUE argument
- stopifnot() does not stop at first non-TRUE argument