From m@ech|er @end|ng |rom @t@t@m@th@ethz@ch  Thu Jun  6 16:06:53 2019
From: m@ech|er @end|ng |rom @t@t@m@th@ethz@ch (Martin Maechler)
Date: Thu, 6 Jun 2019 16:06:53 +0200
Subject: [Rd] stopifnot
In-Reply-To: <23797.18263.920601.137937@stat.math.ethz.ch>
References: <1923928808.6775475.1559227522953.ref@mail.yahoo.com>
 <1923928808.6775475.1559227522953@mail.yahoo.com>
 <23797.18263.920601.137937@stat.math.ethz.ch>
Message-ID: <23801.7677.483926.52379@stat.math.ethz.ch>

>>>>> Martin Maechler 
>>>>>     on Mon, 3 Jun 2019 18:14:15 +0200 writes:

>>>>> Suharto Anggono Suharto Anggono 
>>>>>     on Thu, 30 May 2019 14:45:22 +0000 writes:
>>>>> Suharto Anggono Suharto Anggono 
>>>>>     on Thu, 30 May 2019 14:45:22 +0000 writes:

    >> Here is a patch to function 'stopifnot' that adds 'evaluated' argument and makes 'exprs' argument in 'stopifnot' like 'exprs' argument in 'withAutoprint'.

    >> --- stop.R	2019-05-30 14:01:15.282197286 +0000
    >> +++ stop_new.R	2019-05-30 14:01:51.372187466 +0000

    > [..........]

    > Thank you, Suharto.

    > I've looked at the patch and tested it a bit, and also (re)read
    > your April 15 remarks (cited below).  I now agree that my hacks to
    > enable dealing with "language objects" (typically class
    > 'expression')  'exprs' has remained hackish and hence not
    > working in all cases,  and that it may be a better idea to add
    > a new logical argument (as in other functions) which has to be
    > "switched" and then leads somewhat simpler and more robust code.

    > OTOH, of course, this is an API change would typically not go into the R
    > 3.6.x series ... and I have no idea if it would affect much more
    > than R's own tests/reg-tests-* ...

    > Even though the argument name 'evaluated' was chosen for
    > withAutoprint(), I don't find it a very good name anymore, and -
    > if the change should happen - would probably prefer something
    > like 'is.language' or 'expr.is.language' or similar..

    > Could we get any other readers' opinions ?

[none ..]

In the mean time, I've seen a nicer solution:  If have to add
yet another argument to stopifnot() to make this cleaner, I'm
now pretty sure we should rather use that new argument  to pass
an "expression-alike" object instead of unevaluated expressions.

I'm calling it `exprObject`  for now (and ditch the `evaluated=FALSE`).
With that the new code becomes even cleaner and easier to understand:

stopifnot <- function(..., exprs, exprObject, local = TRUE)
{
    n <- ...length()
    if((has.e <- !missing(exprs)) || !missing(exprObject)) {
	if(n || (has.e && !missing(exprObject)))
	    stop("Only one of 'exprs', 'exprObject' or unnamed expressions, not more")
	envir <- if (isTRUE(local)) parent.frame()
		 else if(isFALSE(local)) .GlobalEnv
		 else if (is.environment(local)) local
		 else stop("'local' must be TRUE, FALSE or an environment")
	E1 <- if(has.e && is.call(exprs <- substitute(exprs))) exprs[[1]]
	cl <- if(is.symbol(E1) &&
		 E1 == quote(`{`)) {
		  exprs[[1]] <- quote(stopifnot) ## --> stopifnot(*, *, ..., *) :
		  exprs
	      }
	      else
		  as.call(c(quote(stopifnot),
			    if(!has.e) exprObject else as.expression(exprs)))
        names(cl) <- NULL
	return(eval(cl, envir=envir))
    }
    ## else   use '...' (and not 'exprs') :

   [............ code unchanged from here to the end .. ............]
   [............ code unchanged from here to the end .. ............]
}



[Rd] stopifnot
Martin Maechler