On 7 January 2012 at 18:40, Romain François wrote: | Le 07/01/12 18:36, Douglas Bates a écrit : | > On Sat, Jan 7, 2012 at 10:55 AM, Dirk Eddelbuettel<e...@debian.org> wrote: | >> On 7 January 2012 at 10:04, Douglas Bates wrote: | >> | 2012/1/7 Romain François<rom...@r-enthusiasts.com>: | >> |> Le 06/01/12 20:46, Douglas Bates a écrit : | >> |> | >> |>> On Fri, Jan 6, 2012 at 1:12 PM, Dirk Eddelbuettel<e...@debian.org> wrote: | >> |>>> | >> |>>> On 6 January 2012 at 12:59, Douglas Bates wrote: | >> |>>> | On Fri, Jan 6, 2012 at 12:39 PM, John Chambers<j...@stat.stanford.edu> | >> |>>> wrote: | >> |>>> |> The "Rf_" part of the API in particular is ugly and somewhat of an | >> |>>> add-on | >> |>>> |> forced in a few examples by the use of some common names in the macro | >> |>>> files. | >> |>>> | | >> |>>> | But, as it stands, that is a requirement when using Rcpp. | >> |>>> | >> |>>> Where? I can think of one propagated use, which is at the bottom of the | >> |>>> try/catch structure where we use ::Rf_error. But the commonly used | >> |>>> macros | >> |>>> hide it, and we could/should obviously wrap this. | >> |>>> | >> |>>> Otherwise, and especially since the 'Rcpp sugar' initiative took off, I | >> |>>> don't | >> |>>> really touch any ::Rf_* myself anymore. Inside the Rcpp code base, sure. | >> |>>> But | >> |>>> not really in user-facing stuff and Rcpp applications. | >> |>> | >> |>> I didn't make myself clear. What I meant was that it is not possible | >> |>> to use asInteger in Rcpp and count on the name being remapped to | >> |>> Rf_asInteger. | >> |>> | >> |>>> | I think of the Rf_ part as more due to the fact that C doesn't have a | >> |>>> | concept of namespaces so anything in the R API is at the top level | >> |>>> | namespace leading to some conflicts. | >> |>>> | >> |>>> Agreed. But speaking stylistically, for the same reason that we prefer | >> |>>> C++ | >> |>>> versions of C header files (eg cstdint over stdint.h, cstdio over | >> |>>> stdio.h, | >> |>>> ...) I am with John on the preference for C++ idioms when given a choice. | >> |>> | >> |>> I suppose I could have just checked whether Rcpp::as<int> calls | >> |>> Rf_asInteger. If so, everything is cool. Unfortunately, I haven't | >> |>> been able to find that specialization. | >> |>> | >> |> as lives in the inst/include/Rcpp/as.h file, and we have to follow template | >> |> wizardry: | >> |> | >> |> it starts from : | >> |> | >> |> template<typename T> T as( SEXP m_sexp) { | >> |> return internal::as<T>( m_sexp, typename | >> |> traits::r_type_traits<T>::r_category() ) ; | >> |> } | >> |> | >> |> with T=int, so we end up calling this one: | >> |> | >> |> template<typename T> T as( SEXP x, ::Rcpp::traits::r_type_primitive_tag ) { | >> |> if( ::Rf_length(x) != 1 ) throw ::Rcpp::not_compatible( | >> |> "expecting a single value" ) ; | >> |> const int RTYPE = ::Rcpp::traits::r_sexptype_traits<T>::rtype ; | >> |> SEXP y = PROTECT( r_cast<RTYPE>(x) ); | >> |> typedef typename ::Rcpp::traits::storage_type<RTYPE>::type | >> |> STORAGE; | >> |> T res = caster<STORAGE,T>( *r_vector_start<RTYPE,STORAGE>( y ) ) | >> |> ; | >> |> UNPROTECT(1) ; | >> |> return res ; | >> |> } | >> |> | >> |> | >> |> which does the magic. There is no calls to asInteger. | >> | | >> | Which, to me, is the disadvantage. The asInteger function is brief, | >> | understandable, flexible and well-tested. This may look transparent | >> | to you but not to many others. | >> | >> It is however templated and valid for more types than just integer--it covers | >> everything mapped by the r_type_primitive type so that the caster can be | >> invoked. | > You got it backwards, Dirk. The asInteger function converts any kind | > of SEXP that it can make sense of to an integer scalar so it is fully | > general, which is why I prefer it. | > | > int asInteger(SEXP x) | > { | > int warn = 0, res; | > | > if (isVectorAtomic(x)&& LENGTH(x)>= 1) { | > switch (TYPEOF(x)) { | > case LGLSXP: | > return IntegerFromLogical(LOGICAL(x)[0],&warn); | > case INTSXP: | > return INTEGER(x)[0]; | > case REALSXP: | > res = IntegerFromReal(REAL(x)[0],&warn); | > CoercionWarning(warn); | > return res; | > case CPLXSXP: | > res = IntegerFromComplex(COMPLEX(x)[0],&warn); | > CoercionWarning(warn); | > return res; | > case STRSXP: | > res = IntegerFromString(STRING_ELT(x, 0),&warn); | > CoercionWarning(warn); | > return res; | > default: | > UNIMPLEMENTED_TYPE("asInteger", x); | > } | > } else if(TYPEOF(x) == CHARSXP) { | > res = IntegerFromString(x,&warn); | > CoercionWarning(warn); | > return res; | > } | > return NA_INTEGER; | > } | Right. I'm sold. I'll have a look at how to squeeze it in.
I am a bit perplexed. The as<> template is (if I may abuse database lingo) "many to many": a SEXP contained an opaque type get matched to one of several R base types, using template magic. But asInteger is only "many-to-one" as it can return int only, given the opaque SEXP. We gain about a nanosecond per invocation as per the microbenchmark we posted. Is that really worth a rewrite? I don't care either way, I just think we may have other open tickets... Dirk -- "Outside of a dog, a book is a man's best friend. Inside of a dog, it is too dark to read." -- Groucho Marx _______________________________________________ Rcpp-devel mailing list Rcpp-devel@lists.r-forge.r-project.org https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel