Rcpp::message() ?

Created on 21 Mar 2021  路  26Comments  路  Source: RcppCore/Rcpp

I wonder if Rcpp::message() should exist. Rcpp::warning() forwards to Rf_warning(); since there is no Rf_message(), the new function would take care of calling base::message() from R.

All 26 comments

I am not sure I understand what you are writing about.

Are you suggesting we need to add Rcpp::message() and implement it via a call to the R function message() ?

If so, why? What current problem does this solve?

If RSQLite needs a message() you can probably implement a local one, just how you have a local XPtr header as I re-noticed the other day (and is that something we should clean up together) ?

Of course I could roll this myself, I'd rather not. I really think emitting a message from C/C++ code should be easier than the status quo.

The XPtr.h workaround was for an IDE I no longer use.

Ok, now at least I know what we are talking about :) Net additions are easiest; no side effects to existing code. I may have looked into that at some point myself: the (possible) absense of a genuine C API is a spot of bother but we do go via the R API in one or two other places.

So having now established that "yes, we could" the burden is now on you to convince Team Rcpp why we should, and burden ourselves with the test and maintenance work going forward. We're listening.

I really think emitting a message from C/C++ code should be easier than the status quo. There are various ways to solve this:

  1. introduce a C API in R base
  2. solve this in Rcpp and cpp11 via an R call (as proposed here)
  3. implement directly in user libraries

Unless this is solved here first, I'll eventually go with the third option and propose PRs.

I still don''t understand.

  • the "1." we have no control over as we're not R Core
  • the "3." is orthogonal to what we do here and everybody can do as they please in their packages; simply not an issue for us.

So has it taken us five messages to establish that you are proposing a C++ function with static instantiation of an R function you want to call?

And you still have not addressed the question in my previous post: _Why would we need this_ ?

I hear you're hesitant to take on new code, perhaps because that's more of a liability than an asset. If I contribute, I add tests and can respond to questions regarding the new code.

Personally, I think we need this

  • for symmetry: I typed Rcpp::message() without thinking and was genuinely surprised by the CI failure
  • because the alternative is a mess: three or more lines of code that could be a simple call to <whatever_namespace>::message()

Please decide if this is enough motivation, and if it's a good fit for this package. There's no hurry.

(Thanks for the fast responses!)

Less fast response now as we have to sleep sometimes too :)

I completely agree on the need for symmetry, I think I wanted it once or twice too.

So how do we do it then? I presume you may have looked into the R code? We could do the _verboten_ thing and hitting a hidden API, or we could do the simple thing via Rcpp::Function (and document that it'll be slower). Thoughts?

I had a very very quick look and there is R_ShowMessages() but on first attempt is not yet suppressable:

> Rcpp::cppFunction("void foo(std::string s) { R_ShowMessage(s.c_str()); }")
> foo("The quick brown fox")
The quick brown fox
> suppressMessages(foo("The quick brown fox"))
The quick brown fox
> 

And the reason maybe the logic in src/library/base/R/message.R.

So ... dunno: do we need two, an (unconditional) Rcpp::message() and a (suppressable) Rcpp::message2() (or another name...) that goes via Rcpp::Function() to reap these goodies?

We can do un-suppressible messages today via cerr or the equivalent. Should we stick with the approach via Function only?

And ignore R_ShowMessage() ? Hm. That one is so cheap to add that I feel like we should (for that very reason of being cheap).

So your motivation, which, even ten or so messages in, you don't seem have made clear is that you want a printing / messaging mechanism that can be silenced via suppressMessages() ? Is that it? In that case a function wrapper it is.

Using Rcpp::Rcerr or Rcout does not show the text is a highlighted colour. Using R_ShowMessages does. Picture below (and I have to be a little careful to generalize as I am running colorout here for kicks):

image

Yeah, I'd think that Rcpp::message() should mimic base::message(). I looked at R_ShowMessage(), but messages that can't be suppressed feel terrible no matter how cheap.

Maybe Rcpp::message() and Rcpp::show_message() ?

I think we should just call base::message

I am also puzzled by what R_ShowMessage() is there for then :-/ Oh well.

Ok, let's wrap base::message as Rcpp::message() then.

Looking at the R sources, it looks like R_ShowMessage() exists primarily for applications embedding R; in theory, an application embedding R could provide their own ptr_R_ShowMessage() implementation to decide what to do when R shows a message via R_ShowMessage().

https://github.com/wch/r-source/blob/210076051305661d27393f790cb4a43e63a97715/src/unix/system.c#L74

However, these "message"s are different from what is exposed to users via base::message(); that is, condition objects of class "message" which write to stderr by default.

A truly minimal implementation is here: https://github.com/RcppCore/Rcpp/commit/8992d83c8a8559821619c1ca2863a46110f40b53

I am currently rubbing my chin pondering how I would test for suppressMessage() working in a wrapper around (which it does, I am just not quite sure yet how to operationalize the test... Can one capture messages?

(Looks like one can. Nice.)

You also have tinytest::expect_message.

Hah. Mark and I were DMing and that did not come up. Paging the good Dr @markvanderloo ...

I guess it affirms that there was a message. Nice. Will add. From the session in which I was noodling:

> expect_message( foo("ABC") )
----- PASSED      : <-->
 call| expect_message(foo("ABC")) 
> 

And more:

> expect_message(message("asdf"), "ASDF")
----- FAILED[xcpt]: <-->
 call| expect_message(message("asdf"), "ASDF")
 diff| Found 1 message(s) of class 'message', but not matching 'ASDF'. 
 diff| Showing up to three messages:
 diff| Message 1 of class <simpleMessage, message, condition>:
 diff| 'asdf'

When did the classed messages appear? Would we have to condition this? I think I am fine with the one-liner I just added, but good thinking...

I think that's a 4.0+ feature, but I was just pointing out that expect_message is able to match patterns too, which should also work for R < 4.0.

True, true, but I did it "in longhand" by calling capture,output myself. All good, methinks.

Thanks for taking this on!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zhiruiwang picture zhiruiwang  路  6Comments

sgsokol picture sgsokol  路  7Comments

ivan-krukov picture ivan-krukov  路  8Comments

wch picture wch  路  7Comments

kevinushey picture kevinushey  路  6Comments