From simon.urbanek at r-project.org  Thu Oct 28 06:15:56 2010
From: simon.urbanek at r-project.org (Simon Urbanek)
Date: Thu, 28 Oct 2010 00:15:56 -0400
Subject: [Rd] must .Call C functions return SEXP?
In-Reply-To: <20101027234347.GA69179@piskorski.com>
References: <20101027234347.GA69179@piskorski.com>
Message-ID: <1E6722DD-D3E2-4BDD-A9BE-C07271B3D1FC@r-project.org>


On Oct 27, 2010, at 7:43 PM, Andrew Piskorski wrote:

> For using R's .Call interface to C functions, all the examples I've
> seen have the C function return type SEXP.  Why?  What does R actually
> do with this return type?  What happens if I *don't* return a SEXP?
> 

You are breaking the API = bad things happen.

.Call behaves like any function in R which means it takes arguments are returns a value. The result of .Call will be exactly the SEXP that you return from your C code hence you have to return something. It's quite common to R_NilValue which is NULL in R if you have nothing to do.


> Reason I ask, is I've written some R code which allocates two long
> lists, and then calls a C function with .Call.  My C code writes to
> those two pre-allocated lists,

That's bad! All arguments are essentially read-only so you should never write into them! R has pass-by-value(!) semantics, so semantically you code has nothing to do with the result.1 and result.2 variables since only their *values* are guaranteed to be passed (possibly a copy). The fact that internally R attempts to avoid copying for performance reasons is the only reason why your code may have appeared to work, but it's invalid!

So what you really want to do is to have just

.Call("my_C_function", other.input)

and in your C code you have

SEXP result_1 = PROTECT(allocVector(VECSXP, 1e6));
SEXP result_2 = PROTECT(allocVector(VECSXP, 1e6));

/* do something ... */

and in order to pass it out you just create a list and return it:

SEXP result = PROTECT(allocVector(VECSXP, 2));
SET_VECTOR_ELT(result, 0, result_1);
SET_VECTOR_ELT(result, 1, result_2);
UNPROTECT(3);
return result;


Accordingly you get:
l = .Call("my_C_function", other.input)
result_1 = l[[1]]
result_2 = l[[2]]


Cheers,
Simon



> thus, I thought I should NOT need to
> return any SEXP from my C function.  However, if I do that, it
> segfaults somewhere in "src/main/memory.c".
> 
> If I instead return the SEXP for one of my two result lists it appears
> to work fine...  But of course I don't understand what's going on here
> and so don't trust it.  The list SEXP I am returning was allocated by
> R, not by my C code, so why does it make any difference whether my C
> function returns it or not?
> 
>> From "src/main/names.c" I see that .Call is implemented by do_dotcall
> in "src/main/dotcode.c".  I don't necessarily understand what that
> really does, but AFAICT if my C function returns nothing, the
> do_dotcall's retval should simply remain set to R_NilValue, which
> should be fine.
> 
> I must be misunderstanding something here, but I don't know what, and
> would definitely appreciate any help.  Thanks!
> 
> 
> My R code looks like this:
> 
>  result.1 <- vector("list" ,1e6)
>  result.2 <- vector("list" ,1e6)
>  .Call("my_C_function", result.1, result.2, other.input)
> 
> My C code looks like this:
> 
>  SEXP result_v; 
>  result_v = Rf_allocVector(REALSXP, 5); 
>  SET_VECTOR_ELT(result_list_1, k1, result_v); 
>  REAL(result_v)[0] = some_number; 
>  REAL(result_v)[1] = another_number; 
>  /* Also do the same sort of thing for result_list_2. */
>  return(result_list_1);  /* Appears to work ok. */
>  /* return; */  /* Segfaults. */
> 
> -- 
> Andrew Piskorski <atp at piskorski.com>
> http://www.piskorski.com/
> 
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
> 
> 



[Rd] must .Call C functions return SEXP?
Simon Urbanek