[Rcpp-devel] Idiom for accessing scalars
Romain François
romain at r-enthusiasts.com
Sat Jan 7 18:40:49 CET 2012
Le 07/01/12 18:36, Douglas Bates a écrit :
> On Sat, Jan 7, 2012 at 10:55 AM, Dirk Eddelbuettel<edd at debian.org> wrote:
>> On 7 January 2012 at 10:04, Douglas Bates wrote:
>> | 2012/1/7 Romain François<romain at r-enthusiasts.com>:
>> |> Le 06/01/12 20:46, Douglas Bates a écrit :
>> |>
>> |>> On Fri, Jan 6, 2012 at 1:12 PM, Dirk Eddelbuettel<edd at debian.org> wrote:
>> |>>>
>> |>>> On 6 January 2012 at 12:59, Douglas Bates wrote:
>> |>>> | On Fri, Jan 6, 2012 at 12:39 PM, John Chambers<jmc at 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.
--
Romain Francois
Professional R Enthusiast
http://romainfrancois.blog.free.fr
More information about the Rcpp-devel
mailing list