5

I want to trace a function so that it prints all of its arguments at the call and it prints the return value together with the arguments when it returns the result. The function trace allows to define action to be performed on entering and on exiting a function call. Is there a function returning the list of arguments within the function, and is there a way of getting the result value without doing each one of multiple branches where each branch exits the function?

in the following example, tracing should print a list of both input parameters (or the function call as text itself) at the call and the return value when the function exits in any one of the branches.

myfun <- function(a,b){
  if (a==1) return(b+1)
  if (a==2) return(b*10)
  return(b)
}
Erich Neuwirth
  • 943
  • 7
  • 13

2 Answers2

4

You're looking for the functions match.call() and returnValue():

myfun <- function(a,b){
    if (a==1) return(b+1)
    if (a==2) return(b*10)
    return(b)
}

trace("myfun", tracer = substitute(print(as.list(match.call()))),
      exit = substitute(print(returnValue())))
#> [1] "myfun"

myfun(1, 2)
#> Tracing myfun(1, 2) on entry 
#> [[1]]
#> myfun
#> 
#> $a
#> [1] 1
#> 
#> $b
#> [1] 2
#> 
#> Tracing myfun(1, 2) on exit 
#> [1] 3
#> [1] 3
myfun(2, 2)
#> Tracing myfun(2, 2) on entry 
#> [[1]]
#> myfun
#> 
#> $a
#> [1] 2
#> 
#> $b
#> [1] 2
#> 
#> Tracing myfun(2, 2) on exit 
#> [1] 20
#> [1] 20
myfun(3, 2)
#> Tracing myfun(3, 2) on entry 
#> [[1]]
#> myfun
#> 
#> $a
#> [1] 3
#> 
#> $b
#> [1] 2
#> 
#> Tracing myfun(3, 2) on exit 
#> [1] 2
#> [1] 2

Created on 2018-10-07 by the reprex package (v0.2.1)

As Moody_Mudskipper mentions, in the comments, you can also use quote() rather than substitute():

myfun <- function(a,b){
    if (a==1) return(b+1)
    if (a==2) return(b*10)
    return(b)
}

trace("myfun", tracer = quote(print(as.list(match.call()))),
      exit = quote(print(returnValue())))
#> [1] "myfun"

myfun(1, 2)
#> Tracing myfun(1, 2) on entry 
#> [[1]]
#> myfun
#> 
#> $a
#> [1] 1
#> 
#> $b
#> [1] 2
#> 
#> Tracing myfun(1, 2) on exit 
#> [1] 3
#> [1] 3
myfun(2, 2)
#> Tracing myfun(2, 2) on entry 
#> [[1]]
#> myfun
#> 
#> $a
#> [1] 2
#> 
#> $b
#> [1] 2
#> 
#> Tracing myfun(2, 2) on exit 
#> [1] 20
#> [1] 20
myfun(3, 2)
#> Tracing myfun(3, 2) on entry 
#> [[1]]
#> myfun
#> 
#> $a
#> [1] 3
#> 
#> $b
#> [1] 2
#> 
#> Tracing myfun(3, 2) on exit 
#> [1] 2
#> [1] 2

Created on 2018-10-07 by the reprex package (v0.2.1)

For an illustration of the difference between the two, see this Stack Overflow question.

duckmayr
  • 16,303
  • 3
  • 35
  • 53
  • upvoted, but maybe `quote` makes more sense than `substitute` ? (same output) – moodymudskipper Oct 07 '18 at 16:45
  • 1
    @Moody_Mudskipper Added a note that both give the same output here, as well as a link to an illustration of the difference between the two. – duckmayr Oct 07 '18 at 16:54
  • Why do I get the error `Caused by error in `match.call()`: ! ... used in a situation where it does not exist`. In which sutation will it not exist. What does not exist, is not clear to me. – Lazarus Thurston Sep 10 '22 at 19:45
0

Just overlap it with .trace in name?

myfun.trace <- function(a,b){
  if (a==1) return({{"a","b"},{a,b}},{b+1})
  if (a==2) return({{"a","b"},{a,b}},{b*10})
return({{"a","b"},{a,b}},{b})    }
Eugen
  • 258
  • 1
  • 10