[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