I am using a variant of stopifnot a lot. can I suggest that base R extends its functionality? I know how to do this for myself. this is a suggestion for beginners and students. I don't think it would break anything. first, I think it would be more useful if it had an optional character string, so users could write stopifnot( is.matrix(m), "m is not a matrix" ) this would mean that stopifnot would have to detect whether the last argument is a string. (I think stopifnot should have had only one condition, and one should have used all() to test multiple conditions, but this is a bridge that was already crossed.) upon failure, stopifnot should print the character string. that's it. A second enhancement would be a "smart string", which knows that everything inside {{...}} should be evaluated. stopifnot( is.matrix(m), "m is not a matrix, but a {{class(m)}}" ) my own programming variant looks even nicer, is.matrix(m) %or% "m is not a matrix but a {{class(m)}}" but requesting base R to add the %and% and %or% (or, better yet, 'and' and 'or') operators by default would be pushing my luck. /iaw ---- Ivo Welch (ivo.welch at gmail.com)
On Wed, Aug 21, 2013 at 12:11 AM, ivo welch <ivo.welch at anderson.ucla.edu> wrote:> I am using a variant of stopifnot a lot. can I suggest that base R > extends its functionality? I know how to do this for myself. this is > a suggestion for beginners and students. I don't think it would break > anything. > > first, I think it would be more useful if it had an optional character > string, so users could write > > stopifnot( is.matrix(m), "m is not a matrix" )How is this better/nicer/more preferable than, say, if (!is.matrix(m)) stop("m is not a matrix") ? I think stopifnot() is mostly meant for regression tests and sanity checks, and should not be used instead of stop() if you want nicely formatted error messages. -Deepayan> this would mean that stopifnot would have to detect whether the last > argument is a string. (I think stopifnot should have had only one > condition, and one should have used all() to test multiple conditions, > but this is a bridge that was already crossed.) upon failure, > stopifnot should print the character string. that's it. > > > A second enhancement would be a "smart string", which knows that > everything inside {{...}} should be evaluated. > > stopifnot( is.matrix(m), "m is not a matrix, but a {{class(m)}}" ) > > > my own programming variant looks even nicer, > > is.matrix(m) %or% "m is not a matrix but a {{class(m)}}" > > but requesting base R to add the %and% and %or% (or, better yet, 'and' > and 'or') operators by default would be pushing my luck. > > /iaw > > > ---- > Ivo Welch (ivo.welch at gmail.com) > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel
R. Michael Weylandt <michael.weylandt@gmail.com>
2013-Aug-20 20:06 UTC
[Rd] Extending suggestion for stopifnot
On Aug 20, 2013, at 14:41, ivo welch <ivo.welch at anderson.ucla.edu> wrote:> A second enhancement would be a "smart string", which knows that > everything inside {{...}} should be evaluated.I think one the HTML templating libraries (whisker or mustache or some such) provides something not unlike this. Perhaps take a look.> > stopifnot( is.matrix(m), "m is not a matrix, but a {{class(m)}}" ) > > > my own programming variant looks even nicer, > > is.matrix(m) %or% "m is not a matrix but a {{class(m)}}" > > but requesting base R to add the %and% and %or% (or, better yet, 'and' > and 'or') operators by default would be pushing my luck.Does %or% throw an error or is this wrapped in something else? The former seems rather perl-ish, but the latter might suggest you look into the || and && operators if you only know their single counterparts. Michael> > /iaw > > > ---- > Ivo Welch (ivo.welch at gmail.com) > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel
On Tue, Aug 20, 2013 at 11:41 AM, ivo welch <ivo.welch at anderson.ucla.edu> wrote:> I am using a variant of stopifnot a lot. can I suggest that base R > extends its functionality? I know how to do this for myself. this is > a suggestion for beginners and students. I don't think it would break > anything. > > first, I think it would be more useful if it had an optional character > string, so users could write > > stopifnot( is.matrix(m), "m is not a matrix" ) > > this would mean that stopifnot would have to detect whether the last > argument is a string. (I think stopifnot should have had only one > condition, and one should have used all() to test multiple conditions, > but this is a bridge that was already crossed.) upon failure, > stopifnot should print the character string. that's it. > > > A second enhancement would be a "smart string", which knows that > everything inside {{...}} should be evaluated. > > stopifnot( is.matrix(m), "m is not a matrix, but a {{class(m)}}" )I think using a function (in this case paste) is cleaner: paste("m is not a matrix, but a", class(m)) It avoids adding a new convention ("evaluate everything between {{ }}") and has additional arguments.> > > my own programming variant looks even nicer, > > is.matrix(m) %or% "m is not a matrix but a {{class(m)}}"In R you can write it as is.matrix(m) || stop("m is not a matrix but a ", class(m)) Examples: m = 1> is.matrix(m) || stop("m is not a matrix but a ", class(m))Error: m is not a matrix but a numeric> m = matrix(0,2,2) > is.matrix(m) || stop("m is not a matrix but a ", class(m))[1] TRUE But the construct if (!is.matrix(m)) stop("m is not a matrix but a ", class(m)) is more readable for people not used to Pearl.
> my own programming variant looks even nicer, > is.matrix(m) %or% "m is not a matrix but a {{class(m)}}"But it does not act nicely. All %anything% constructs have the same precedence, that of %*%. Hence x==3 %or% "x is not three" is parsed as x == ( 3 %or% "x is not three" ) which is not what I think you want. Use standard functional notation, e.g., ensureThat(condition, message), and you don't get into parsing trouble. Bill Dunlap Spotfire, TIBCO Software wdunlap tibco.com> -----Original Message----- > From: r-devel-bounces at r-project.org [mailto:r-devel-bounces at r-project.org] On Behalf > Of ivo welch > Sent: Tuesday, August 20, 2013 11:42 AM > To: r-devel at r-project.org List > Subject: [Rd] Extending suggestion for stopifnot > > I am using a variant of stopifnot a lot. can I suggest that base R > extends its functionality? I know how to do this for myself. this is > a suggestion for beginners and students. I don't think it would break > anything. > > first, I think it would be more useful if it had an optional character > string, so users could write > > stopifnot( is.matrix(m), "m is not a matrix" ) > > this would mean that stopifnot would have to detect whether the last > argument is a string. (I think stopifnot should have had only one > condition, and one should have used all() to test multiple conditions, > but this is a bridge that was already crossed.) upon failure, > stopifnot should print the character string. that's it. > > > A second enhancement would be a "smart string", which knows that > everything inside {{...}} should be evaluated. > > stopifnot( is.matrix(m), "m is not a matrix, but a {{class(m)}}" ) > > > my own programming variant looks even nicer, > > is.matrix(m) %or% "m is not a matrix but a {{class(m)}}" > > but requesting base R to add the %and% and %or% (or, better yet, 'and' > and 'or') operators by default would be pushing my luck. > > /iaw > > > ---- > Ivo Welch (ivo.welch at gmail.com) > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel
> first, I think it would be more useful if it had an optional character > string, so users could write > > stopifnot( is.matrix(m), "m is not a matrix" ) >Another option is to just generate better error messages automatically, e.g.:> library(assertthat) > x <- 1:10 > assert_that(is.matrix(x))Error: x is not a matrix Hadley -- Chief Scientist, RStudio http://had.co.nz/
On 08/20/2013 11:41 AM, ivo welch wrote:> A second enhancement would be a "smart string", which knows that > everything inside {{...}} should be evaluated. > > stopifnot( is.matrix(m), "m is not a matrix, but a {{class(m)}}" )a variant with more traditional syntax might be if (!is.matrix(m)) stopf("m is not a matrix, but a '%s'", class(m)) or stopifnotf(is.matrix(m), "m is not a matrix, but a '%s'", class(m)) where stopf is analogous to sprintf but signalling the corresponding condition (perhaps taking the opportunity to strwrap to getOption("width")). This would work well with gettextf to allow for translation. An imperfect implementation (call. is incorrect, for example) is .msg <- function(fmt, ..., domain=NULL, width=getOption("width")) ## Use this helper to format all error / warning / message text { txt <- strwrap(gettextf(fmt, ..., domain=domain), width=width, exdent=2) paste(txt, collapse="\n") } stopf <- function(..., call.=FALSE) { stop(.msg(...), call.=call.) } stopifnotf <- function(test, fmt, ...) { if (!test) stopf(fmt, ...) } One might also wish to expose the condition class system, along the lines of .textf <- ## a variant of .makeMessage function(fmt, ..., width = getOption("width"), domain = NULL, appendLF = FALSE) { txt <- gettextf(fmt, ..., domain = domain) msg <- paste(strwrap(txt, width = width, indent = 2, exdent = 2), collapse="\n") if (appendLF) paste0(msg, "\n") else msg } .condition <- function(fmt, ..., class, call = NULL) { msg <- .textf(fmt, ...) if (is.null(call)) msg <- paste0("\n", msg) class <- c(class, "condition") structure(list(message=msg, call = call), class=class) } stopf <- function(fmt, ..., class. = "simpleError", call. = TRUE, domain = NULL) { call. <- if (is.logical(call.) && 1L == length(call.) && call.) sys.call(-1) else NULL cond <- .condition(fmt, ..., domain = domain, class = c(class., "error"), call = call.) stop(cond) } warnf <- function(fmt, ..., class. = "simpleWarning", call. = TRUE, domain = NULL) { ## does not support immediate., but options(warn=1) supported call. <- if (is.logical(call.) && 1L == length(call.) && call.) sys.call(-1) else NULL cond <- .condition(fmt, ..., domain = domain, class = c(class., "warning" ), call = call.) warning(cond) } messagef <- function(fmt, ..., class. = "simpleMessage", domain = NULL, appendLF = TRUE) { cond <- .condition(fmt, ..., domain = domain, appendLF = appendLF, class = c(class., "message")) message(cond) } -- Computational Biology / Fred Hutchinson Cancer Research Center 1100 Fairview Ave. N. PO Box 19024 Seattle, WA 98109 Location: Arnold Building M1 B861 Phone: (206) 667-2793