[Rd] Can a function know what other function called it?

Duncan Murdoch murdoch at stats.uwo.ca
Sun May 24 13:58:39 CEST 2009


On 23/05/2009 4:55 PM, Robert Gentleman wrote:
> Hi Kynn,
> 
> 
> Kynn Jones wrote:
>> Suppose function foo calls function bar.  Is there any way in which
>> bar can find out the name of the function that called it, "foo"?
> 
>  essentially yes. You can find out about the call stack by using sys.calls and
> sys.parents etc. The man page plus additional manuals should be sufficient, but
> let us know if there are things that are not clear.
> 
>> There are two generalization to this question that interest me.
>> First, can this query go farther up the call stack?  I.e. if bar now
>> calls baz, can baz find out the name of the function that called the
>> function that called it, i.e. "foo"?  Second, what other information,
> 
>  yes - you can (at least currently) get access to the entire calling stack and
> some manipulations can be performed.
> 
> 
>> beside its name, can bar find about the environment where it was
>> called?  E.g. can it find out the file name and line number of the
> 
>  there is no real concept of file and line number associated with a function
> definition (nor need their even be a name - functions can be anonymous).
> 
>  If you want to map back to source files then I think that currently we do not
> keep quite enough information when a function is sourced. Others may be able to
> elaborate more (or correct my mistakes).  I think we currently store the actual
> text for the body of the function so that it can be used for printing, but we
> don't store a file name/location/line number or anything of that sort. It could
> probably be added, but would be a lot of work, so it would need someone who
> really wanted it to do that.

By default we don't store either a copy of the source or the references 
to the source file for functions in a package, but those options can be 
enabled, and are enabled by default for users working at the console. 
For example, with this source in c:/temp/test.R:

g <- function(x) {
   x <- 1
   y <- 4
}

You can do the following:

 > getOption("keep.source")
[1] TRUE
 > source("c:/temp/test.R")
 > as.list(g)[[2]]
{
     x <- 1
     y <- 4
}
attr(,"srcfile")
c:/temp/test.R

You can also find out which part of the file corresponds to each 
statement of the function definition.  For example,

 > attributes(as.list(g)[[2]])
$srcref
$srcref[[1]]
{

$srcref[[2]]
x <- 1

$srcref[[3]]
y <- 4


$srcfile
c:/temp/test.R

 > print(attr(as.list(g)[[2]], "srcref")[[2]])
x <- 1
 > print(attr(as.list(g)[[2]], "srcref")[[2]], useSource=FALSE)
<srcref: file "c:/temp/test.R" chars 2:3 to 2:8>


> 
>  However, you can find out lots of other things if you want.  Do note that while
>  it is possible to determine which function initiated the call, it is not
> necessarily possible to figure out which of the calls (if there is more than one
> in the body of the function) is active.  R does not keep track of things in that
> way. To be clear if foo looks like:
> 
>   foo <- function(x) {
>     bar(x)
>     x = sqrt(x)
>     bar(x)
>   }
>   and you have a breakpoint in bar, you could not (easily) distinguish which of
> the two calls to bar was active. There is no line counter or anything of that
> sort available.

The evaluator doesn't pay any attention to srcref records, so this is 
still true, but it would be possible to keep the srcref on the stack as 
well as all the other info there.

I've written code (and I think I sent it to you last year) that can do 
things like replacing the statement coming from a particular line of a 
file with whatever code you like; this could be used in writing a nice 
source-level debugger.

Duncan Murdoch

> 
>  best wishes
>    Robert
> 
>> function call?
>>
>> Thanks!
>>
>> ______________________________________________
>> R-devel at r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>



More information about the R-devel mailing list