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]]
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 <morgan.emailbox at gmail.com> 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]] > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel >[[alternative HTML version deleted]]
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, <szwjf08 at gmail.com> 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 <morgan.emailbox at gmail.com> > 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]] >> >> ______________________________________________ >> R-devel at r-project.org mailing list >> https://stat.ethz.ch/mailman/listinfo/r-devel >> >[[alternative HTML version deleted]]