Skip to content

returning NULL from .Call call

2 messages · Oleg Sklyar, Brian Ripley

#
Dear R developers,

I've just encountered one "feature" of R-C extensions. If it is known, I 
would be thankful for any hints why it works this way (I found the way 
around, which is also mentioned here, but maybe it is not the best one). 
If it is however unknown, it might be considered for a "wish list".

Consider a simple "aka" C function (the original implementation loads 
complex data structures and there could be other causes of trouble apart 
from non-existing files):

SEXP loadData(SEXP fileName) {
    int* data = NULL;
    try {
       // try to open the file and read the data into 'data'
    } catch(...) {
       std::cout << "Load failed (ANY REASON) - returning NULL" << 
std::endl;
       return NULL;
    }
    // operation successful, but the size of data can be nil
    if(data == NULL)
       return NULL;
    SEXP result = allocVector(INTSXP, numOfDataPoints);
    PROTECT(result);
    // copy data from 'data' into 'result'
    delete[] data;
    UNPROTECT(1);
    return result;
}

This function will nicely return a data array if no load problems occur 
and data is more than nil. If it is not the case I would be happy to 
receive a NULL as indication that the function didn't succeed, which I 
can then check with is.nul(...). I would consider it logical for SEXP, 
which is a pointer (in this case to a non-existing structure). However, 
trying to return NULL causes 'Segmentation Fault' without any further 
message and R-session closes. The question is, what would be a working 
way to return anything like NULL, something to check with is.null(...)?

Now the way around (just in case it might be of interest), slightly 
modified function returning numeric(0) on fail:

SEXP loadData(SEXP fileName) {
    // prerecreate and protect a non-NULL return value: numeric(0)
    SEXP result = allocVector(INTSXP, 0);
    PROTECT(result);
    int* data = NULL;
    try {
       // try to open the file and read the data into 'data'
    } catch(...) {
       std::cout << "Load failed (ANY REASON) - returning NULL" << 
std::endl;
       // unprotect and return numeric(0)
       UNPROTECT(1);
       return result;
    }
    // operation successful, but the size of data can be nil
    // unprotect old value to enable garbage collector to kill it sooner 
or later
    UNPROTECT(1);
    if(data == NULL)
       return result;
    // recreate and protect the return value
    result = allocVector(INTSXP, numOfDataPoints);
    PROTECT(result);
    // copy data from 'data' into 'result'
    delete[] data;
    UNPROTECT(1);
    return result;
}

This function always has something to return and it works, but not 
really elegantly and returning wrong data when fails.

Thanks in advance for any comments.
Regards
Oleg
#
On Tue, 15 Mar 2005, Oleg Sklyar wrote:

            
What feature is that?  (It really is not clear from your description.)

NULL in R is expressed as R_NilValue in C.  What did you do when `trying 
to return NULL'?  NULL in C is not a valid value for a SEXP pointer, of 
course.

This is documented in `Writing R Extensions', and there are many examples 
of it around.