[R-pkg-devel] Error checking in an independent C code and printing (perror, printf, etc.)
Ivan Krylov
kry|ov@r00t @end|ng |rom gm@||@com
Wed Sep 7 11:58:33 CEST 2022
On Wed, 7 Sep 2022 18:32:46 +1200
"Jiří Moravec" <jiri.c.moravec using gmail.com> wrote:
> I was hoping that you will tell me that R takes control of the C's
> stderr and stdout.
> That would make stuff easier. But I guess that is not really possible.
While there is fopencookie() in GNU libc, on other POSIX-compatible
platforms the only relatively portable option is to replace file
descriptors 0,1,2 with pipes and read those pipes from a thread. And on
Windows there can be multiple C runtime libraries running in the same
process, which makes taking over stdout/stderr extra hard.
> First time using the dreadful "goto", looks like it makes sense to
> free resources.
"goto cleanup" is a fine pattern in a language like C which lacks
both destructors and deferred execution.
> It still looks a bit ugly compared to simple "throw" (i.e., too much
> code noise),
> and I now understand where the Java's checked exceptions are coming
> from. And somehow, now that I am thinking about it, I am getting used
> to it.
But if you'd like to "throw" from compiled code in an R package, the
Rcpp package can help you with that: it forms a layer between R and
your code that would catch the exception (letting the stack unwinding
process run the destructors to prevent the leaks) and convert it into
an R error condition. Common R types are also wrapped in C++ classes
with convenient STL-like accessors.
> I hope I am responding correctly ("respond all") and not spamming
> people.
Cc'ing the list is the right idea. On some lists it's considered
wrong to send replies anywhere but to the list, but reply-all
including the senders themselves seems to work fine here.
> Particularly, when to use PROTECT() is not clear (new SEXP objects,
> but not required if they are just interfaced with INTEGER(), REAL()
> or VECTOR_ELT).
If you can prove there won't be any allocations (including those done
by R for its own purposes when you call some API function) between the
creation of the new SEXP and the return from the function, you can omit
the PROTECT() call. A simpler and perhaps safer rule is to always
PROTECT() the allocations. I don't think it will cost you much in
performance, though it's possible I'm mistaken.
> The overview:
> https://stat.ethz.ch/pipermail/r-devel/attachments/20120323/a13f948a/attachment.pdf
> was also really helpful and should be IMHO part of official
> documentation.
"Writing R Extensions" could use some improvements, that's true. For
example, "serialise a SEXP to my C callback" is a very useful function
which I think should be a part of public R API, but it's not mentioned
there at all. On the other hand, my package that uses the
R_InitOutPStream and R_Serialize entry points seems to have passed the
CRAN review. A table of all public entry points including short
descriptions and whether they allocate could be very useful.
Unfortunately, if an outsider like me were to write it, some core
member would still have to spend time reviewing it.
> An example how to work with named list (e.g., an S3 class), where
> subsetting is done by name and not by position,
> would be really useful.
Hmm. For attributes and S4 slots, there's {GET,SET}_ATTR and
{GET,SET}_SLOT, but I don't see such a quick shortcut for
subsetting by name. Based on searching the R source, I think you could
use SEXP index = PROTECT(match(GET_NAMES(list), mkChar("name"), 0)); to
obtain an INTSXP vector of indices matching the names, 1-based (or 0 if
there was no match).
Rcpp offers a very convenient operator[](const std::string & name) that
does a similar thing: it obtains the names of the object, then compares
each of them to the name being looked up.
--
Best regards,
Ivan
More information about the R-package-devel
mailing list