Skip to content

Wishlist: 'quietly' argument for .onAttach() / .First.li b()

6 messages · Liaw, Andy, Martin Maechler, Brian Ripley +2 more

#
From: Bill Dunlap
Thanks!  This looks like a good alternative.  What do others think of this
approach?

Andy
#
AndyL> From: Bill Dunlap
>> On Thu, 13 Apr 2006, Prof Brian Ripley wrote:
>>
>> > On Thu, 13 Apr 2006, Peter Ruckdeschel wrote:
>> >
    >> > > Hi R-devels,
    >> > >
    >> > > in "Writing R extensions" as well as in the help > >
    >> to .onAttach(), you mention that one could > > use this
    >> function to issue a start-up message/banner > > for the
    >> package.
    >> > >
    >> > > My little wish for Easter:
    >> > >
    >> > > a 'quietly'-type argument for .onAttach() /
    >> .First.lib() which is > > passed through by functions > >
    >> require() and library() respectively, > > and by means of
    >> which one could optionally > > suppress this start-up
    >> message/banner .
    >> > >
    >> > > Is this hard to do?
    >> >
    >> > I believe so (and think we have been here before).  The
    >> documented > call sequence is
    >> >
    >> > .onLoad(libname, pkgname) > .onAttach(libname, pkgname)
    >> >
    >> > the same as .First.lib.  There is no way to add an
    >> argument here, as > many existing packages do not support
    >> it.  Beyond that, how would you > pass the argument in?
    >> Namespaces and packages are often > loaded/attached
    >> implicitly as a result of loading other packages.
    >> >
    >> > I did think you could make use of an option to decide
    >> whether to the > print the message or not, but I have
    >> always assumed that those who did > want a banner
    >> probably did not want it suppressed.
    >> 
    >> If the .onAttach() used message() instead of cat() to
    >> display the banner message then you could use
    >> suppressMessages(require("randomForest")) to squelch the
    >> message.

Very nice thought and proposal!

    AndyL> Thanks!  This looks like a good alternative.  What do
    AndyL> others think of this approach?

I think we should recommend to use message(.) instead of cat(.)
inside in .onAttach() or .First.lib() functions.

Martin

    >> ---------------------------------------------------------------------
    >> Bill Dunlap Insightful Corporation bill at insightful dot
    >> com 360-428-8146
    >> 
    >> "All statements in this message represent the opinions of
    >> the author and do not necessarily reflect Insightful
    >> Corporation policy or position."
#
On Thu, 13 Apr 2006, Liaw, Andy wrote:

            
I used an alternative approach myself. This allows the user
enable/disable the banner text quite easily.

.onAttach <- function(libname, pkgname) {
    if (verbose <- getOption("verbose")) {
        ...
        desc <- packageDescription(pkgname)
        cat(sprintf("%s, version %s", desc$Title, desc$Version), "\n")
        cat(sprintf("Type library(help=%s) to see package documentation",
                    libraryPkgName(pkgname)), "\n")
    }
}

----------------------------------------------------------
SIGSIG -- signature too long (core dumped)
#
I carefully did not suggest the use of option 'verbose', as that is used 
in many other places.  In particular, with your proposal, you cannot have 
the message without a lot of chatter from library() (and although that has 
a 'verbose' argument, it is often called implicitly, and rarely with 
that argument set).

Similarly for Bill Dunlap's proposal: suppressMessages would squelch all 
messages from the call, not just the one from your package's startup code.
Now, at present there may not be any, but that could well change as 
message() gets more widely used.
On Thu, 13 Apr 2006, Paul Roebuck wrote:

            

  
    
1 day later
#
On Fri, 14 Apr 2006, Prof Brian Ripley wrote:

            
Fair enough. 'Course I preferred the implicit 'quietly' argument
so the 'verbose' option works perfectly in that case. Possibly a
minority view on the subject, but I don't care for packages being
"chatty" myself except when explicitly asked to be so by the user.
I found Bill's suggestion a bit scary myself; suppressing messages
when dealing with loading packages seems a bit like disabling the
compiler's warning messages - a bad idea. But it was a novel approach.

Given what you said above, do you favor the suggestion to use
message() instead of cat() for the purpose of .onAttach() startup
messages? I've seen message() before in the manpages but never saw
any documentation on how or when it might be considered appropriate
to use. Why would one want to represent a simple non-error message
as a condition in the first place?
----------------------------------------------------------
SIGSIG -- signature too long (core dumped)
#
Paul Roebuck <roebuck at mdanderson.org> writes:
What's the use case where this would be scary?  suppressMessages
doesn't supress warnings or errors, just messages.  If the info to be
communicated to the user is important enough that it would be "scary"
to not see it, then shouldn't it sent as a a warning or an error?
(I know the question wasn't directed at me, but...)

Yes.
Because it allows another developer to have control over those
messages.  That's the beauty of the condition system in R.  

Right now, developers can choose to allow or suppress messages sent
via message().  With a small change, developers could have a lot more
control.  The message code could define a restart that would allow a
developer-specified function to handle the message.  This could be
useful, for example, to log all messages to a file.

Here's an example of what I'm thinking about:

## Add a 'custom' restart to message().  Here, we'll add it by
## creating a wrapper, mymessage()
mymessage <- function(..., domain=NULL) {
    withRestarts(withCallingHandlers(message(..., domain=domain),
                                     message=function(m) signalCondition(m)),
                 custom=function(m, f) f(m))
    invisible(NULL)
}


## Here is a test function
doit <- function() {
    mymessage("Welcome to the 'doit' function!")
    return(123)
}


## Here is an example message handler.  Here, you could write messages
## to a file, send them as email to your friends or enemies, etc.
## For the example, we'll just prepend 'MSG:'
msgLogger <- function(m) cat(paste("MSG:", conditionMessage(m)), "\n")


## Finally, call the doit function and customize how messages are
## handled.
withCallingHandlers(doit(),
                    message=function(m) {
                        invokeRestart("custom", m, msgLogger)
                    })

MSG: Welcome to the 'doit' function! 
[1] 123


For anyone still with me:

* If there was much concern about squelching "important" messages by
  accident, then one could define a new subclass of simpleMessage, say
  startupMessage or blatherMessage, and then suppress just those.

* This use case of handling messages could also be addressed with a
  logging system like Python's logging module.  Basically, it would
  allow users to install log handlers, set priorities, etc.

Thanks for listening,

+ seth