This question prompted the following question: Is there a way to view the special primitive functions that are in the call stack?
For example, create a function that returns the call stack on exit:
myFun <- function(obj){
on.exit(print(sys.calls()))
return(obj)
}
Calling this function and assigning its result to an object using assign
avoids using special primitive functions:
> assign("myObj",myFun(4))
[[1]]
assign("myObj", myFun(4))
[[2]]
myFun(4)
But using the assignment operator, this gets left out of the stack
> `<-`(myObj, myFun(6))
[[1]]
myFun(6)
Granted, it might not be all that common to want to see the assignment operator in the call stack, but other functions such as rep
and log
also get hidden
I don't think there's any way to access calls to primitive functions via the call stack. Here is why.
When a "typical" R function is evaluated:
The chain of enclosing environments that is built up when function calls are nested within one another is the "call stack" or "frame stack" to which sys.calls()
, sys.frames()
and the like provide some access.
My strong suspicion is that calls to primitive functions don't appear on the call stack because no R-side environment is created during their evaluation. No environment is created, so no environment appears on the call stack.
For some more insight, here's how John Chambers describes the evaluation of primitive functions on page 464 of Software for Data Analysis:
Evaluation of a call to one of these functions starts off in the usual way, but when the evaluator discovers that the function object is a primitive rather than a function defined in R, it branches to an entirely different computation. The object only appears to be a function object with formal arguments and a call to the function .Primitive() with a string argument. In reality, it essentially contains only an index into a table that is part of the C code implementing the core of R. The entry of the table identifies a C routine in the core that is responsible for evaluating calls to this specific primitive. The evaluator will transfer control to that routine, and expects the routine to return a C-language pointer to the R object representing the value of the call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With