[Rcpp-devel] Idiom for accessing scalars

Douglas Bates bates at stat.wisc.edu
Sat Jan 7 18:36:24 CET 2012


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;
}


More information about the Rcpp-devel mailing list