Questions on the R C API

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Questions on the R C API

MorganMorgan
Hi All,

I have some questions regarding the R C API.

Let's assume I have a function which is defined as follows:

R file:

myfunc <- function(a, b, ...) .External(Cfun, a, b, ...)

C file:

SEXP Cfun(SEXP args) {
  args = CDR(args);
  SEXP a = CAR(args); args = CDR(args);
  SEXP b = CAR(args); args = CDR(args);
  /* continue to do something with remaining arguments in "..." using the
same logic as above*/

  return R_NilValue;
}

1/ Let's suppose that in my c function I change the value of a inside the
function but I want to reset it to what it was when I did SEXP a =
CAR(args); . How can I do that?

2/Is there a method to set "args" at a specific position so I can access a
specific value of my choice? If yes, do you have an simple example?

3/ Let's suppose now, I call the function in R. Is there a way to avoid the
function to evaluate its arguments before going to the C call? Do I have to
do it at the R level or can it be done at the C level?

Thank you very much in advance.
Best regards
Morgan

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Questions on the R C API

Wang Jiefei
Hi Morgan,

My solutions might not be the best one(I believe it's not), but it should
work for your question.

1. Have you considered Rf_duplicate function? If you want to change the
value of `a` and reset it later, you have to have a duplication somewhere
for resetting it. Instead of changing the value of `a` directly, why not
changing the value of a duplicated `a`? So you do not have to reset it.

2. I think a pairlist behaves like a linked list(I might be wrong here and
please correct me if so). Therefore, there is no simple way to locate an
element in a pairlist. As for as I know, R defines a set of
convenient functions for you to access a limited number of elements. See
below

```
#define CAR(e) ((e)->u.listsxp.carval)
#define CDR(e) ((e)->u.listsxp.cdrval)
#define CAAR(e) CAR(CAR(e))
#define CDAR(e) CDR(CAR(e))
#define CADR(e) CAR(CDR(e))
#define CDDR(e) CDR(CDR(e))
#define CDDDR(e) CDR(CDR(CDR(e)))
#define CADDR(e) CAR(CDR(CDR(e)))
#define CADDDR(e) CAR(CDR(CDR(CDR(e))))
#define CAD4R(e) CAR(CDR(CDR(CDR(CDR(e)))))
```

You can use them to get first a few arguments from a pairlist. Another
solution would be converting the pairlist into a list so that you can use
the methods defined for a list to access any element. I do not know which C
function can achieve that but `as.list` at R level should be able to do
this job, you can evaluate an R function at C level and get the list
result( By calling `Rf_eval`). I think this operation is relatively low
cost because the list should only contain a set of pointers pointing to
each element. There is no object duplication(Again I might be wrong here).

3. You can get unevaluated expression at the R level before you call the C
function and pass it to your C function( by calling `substitute` function).
However, from my vague memory, the expression would be eventually evaluated
at the C level even you pass the expression to it. Therefore, I think you
can create a list of unevaluated arguments before you enter the C function,
so your C function can expect a list rather than a pairlist as its
argument. This can solve both your second and third questions.

Best,
Jiefei



On Mon, Nov 4, 2019 at 2:41 PM Morgan Morgan <[hidden email]>
wrote:

> Hi All,
>
> I have some questions regarding the R C API.
>
> Let's assume I have a function which is defined as follows:
>
> R file:
>
> myfunc <- function(a, b, ...) .External(Cfun, a, b, ...)
>
> C file:
>
> SEXP Cfun(SEXP args) {
>   args = CDR(args);
>   SEXP a = CAR(args); args = CDR(args);
>   SEXP b = CAR(args); args = CDR(args);
>   /* continue to do something with remaining arguments in "..." using the
> same logic as above*/
>
>   return R_NilValue;
> }
>
> 1/ Let's suppose that in my c function I change the value of a inside the
> function but I want to reset it to what it was when I did SEXP a =
> CAR(args); . How can I do that?
>
> 2/Is there a method to set "args" at a specific position so I can access a
> specific value of my choice? If yes, do you have an simple example?
>
> 3/ Let's suppose now, I call the function in R. Is there a way to avoid the
> function to evaluate its arguments before going to the C call? Do I have to
> do it at the R level or can it be done at the C level?
>
> Thank you very much in advance.
> Best regards
> Morgan
>
>         [[alternative HTML version deleted]]
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Questions on the R C API

MorganMorgan
Thank you for your reply Jiefei.
I think in theory your solution should work. I'll have to give them a try.


On Mon, 4 Nov 2019 23:41 Wang Jiefei, <[hidden email]> wrote:

> Hi Morgan,
>
> My solutions might not be the best one(I believe it's not), but it should
> work for your question.
>
> 1. Have you considered Rf_duplicate function? If you want to change the
> value of `a` and reset it later, you have to have a duplication somewhere
> for resetting it. Instead of changing the value of `a` directly, why not
> changing the value of a duplicated `a`? So you do not have to reset it.
>
> 2. I think a pairlist behaves like a linked list(I might be wrong here and
> please correct me if so). Therefore, there is no simple way to locate an
> element in a pairlist. As for as I know, R defines a set of
> convenient functions for you to access a limited number of elements. See
> below
>
> ```
> #define CAR(e) ((e)->u.listsxp.carval)
> #define CDR(e) ((e)->u.listsxp.cdrval)
> #define CAAR(e) CAR(CAR(e))
> #define CDAR(e) CDR(CAR(e))
> #define CADR(e) CAR(CDR(e))
> #define CDDR(e) CDR(CDR(e))
> #define CDDDR(e) CDR(CDR(CDR(e)))
> #define CADDR(e) CAR(CDR(CDR(e)))
> #define CADDDR(e) CAR(CDR(CDR(CDR(e))))
> #define CAD4R(e) CAR(CDR(CDR(CDR(CDR(e)))))
> ```
>
> You can use them to get first a few arguments from a pairlist. Another
> solution would be converting the pairlist into a list so that you can use
> the methods defined for a list to access any element. I do not know which C
> function can achieve that but `as.list` at R level should be able to do
> this job, you can evaluate an R function at C level and get the list
> result( By calling `Rf_eval`). I think this operation is relatively low
> cost because the list should only contain a set of pointers pointing to
> each element. There is no object duplication(Again I might be wrong here).
>


So there is no way to reset a pairlist to its first element?


> 3. You can get unevaluated expression at the R level before you call the C
> function and pass it to your C function( by calling `substitute` function).
> However, from my vague memory, the expression would be eventually evaluated
> at the C level even you pass the expression to it. Therefore, I think you
> can create a list of unevaluated arguments before you enter the C function,
> so your C function can expect a list rather than a pairlist as its
> argument. This can solve both your second and third questions.
>

Correct me if I am wrong but does it mean that I will have to change "..."
to "list(...)" and use .Call instead of .External?

Also does it mean that to avoid expression to be evaluated at the R level,
I have to use "list" or "substitute"? The function "switch" in R does not
use them but manage to achieve that.

switch(1, "a", stop("a"))
#[1] "a"

It is a primitive but I don't understand how it manage to do that.

Best,
Morgan



> Best,
> Jiefei
>
>
> On Mon, Nov 4, 2019 at 2:41 PM Morgan Morgan <[hidden email]>
> wrote:
>
>> Hi All,
>>
>> I have some questions regarding the R C API.
>>
>> Let's assume I have a function which is defined as follows:
>>
>> R file:
>>
>> myfunc <- function(a, b, ...) .External(Cfun, a, b, ...)
>>
>> C file:
>>
>> SEXP Cfun(SEXP args) {
>>   args = CDR(args);
>>   SEXP a = CAR(args); args = CDR(args);
>>   SEXP b = CAR(args); args = CDR(args);
>>   /* continue to do something with remaining arguments in "..." using the
>> same logic as above*/
>>
>>   return R_NilValue;
>> }
>>
>> 1/ Let's suppose that in my c function I change the value of a inside the
>> function but I want to reset it to what it was when I did SEXP a =
>> CAR(args); . How can I do that?
>>
>> 2/Is there a method to set "args" at a specific position so I can access a
>> specific value of my choice? If yes, do you have an simple example?
>>
>> 3/ Let's suppose now, I call the function in R. Is there a way to avoid
>> the
>> function to evaluate its arguments before going to the C call? Do I have
>> to
>> do it at the R level or can it be done at the C level?
>>
>> Thank you very much in advance.
>> Best regards
>> Morgan
>>
>>         [[alternative HTML version deleted]]
>>
>> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Questions on the R C API

Gabriel Becker-2
Hi Martin and Jiefei,

A quick note, I'll try to respond more completely later.


> It is a primitive but I don't understand how it manage to do that.
>

Primitives and Internals are allowed to be, but usually aren't, SPECIALSXPs
rather than BUILTINSXPs. SPECIALSXPs receive their arguments unevaluated
when called from R. See
https://cran.r-project.org/doc/manuals/r-release/R-ints.html#g_t_002eInternal-vs-_002ePrimitive.
This is not possible for functions that are not part of the R sources as
far as I know.

Also the difference between Primitives and internals isn't evaluation of
arguments (thats special vs builtin) but rather, whether they behave like a
closure (internal) or not (primitive).

Evaluation behavior for internal and primitive functions is defined within
the function table in names.c, the comment there explains the format.

Best,
~G

>
> Best,
> Morgan
>
>
>
> > Best,
> > Jiefei
> >
> >
> > On Mon, Nov 4, 2019 at 2:41 PM Morgan Morgan <[hidden email]>
> > wrote:
> >
> >> Hi All,
> >>
> >> I have some questions regarding the R C API.
> >>
> >> Let's assume I have a function which is defined as follows:
> >>
> >> R file:
> >>
> >> myfunc <- function(a, b, ...) .External(Cfun, a, b, ...)
> >>
> >> C file:
> >>
> >> SEXP Cfun(SEXP args) {
> >>   args = CDR(args);
> >>   SEXP a = CAR(args); args = CDR(args);
> >>   SEXP b = CAR(args); args = CDR(args);
> >>   /* continue to do something with remaining arguments in "..." using
> the
> >> same logic as above*/
> >>
> >>   return R_NilValue;
> >> }
> >>
> >> 1/ Let's suppose that in my c function I change the value of a inside
> the
> >> function but I want to reset it to what it was when I did SEXP a =
> >> CAR(args); . How can I do that?
> >>
> >> 2/Is there a method to set "args" at a specific position so I can
> access a
> >> specific value of my choice? If yes, do you have an simple example?
> >>
> >> 3/ Let's suppose now, I call the function in R. Is there a way to avoid
> >> the
> >> function to evaluate its arguments before going to the C call? Do I have
> >> to
> >> do it at the R level or can it be done at the C level?
> >>
> >> Thank you very much in advance.
> >> Best regards
> >> Morgan
> >>
> >>         [[alternative HTML version deleted]]
> >>
> >> ______________________________________________
> >> [hidden email] mailing list
> >> https://stat.ethz.ch/mailman/listinfo/r-devel
> >>
> >
>
>         [[alternative HTML version deleted]]
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel