4

Background

Function is passed as an argument to a function. The problem pertains to:

  • getting the name of that function as a string for convenient subsequent manipulation
  • locating that function within the package from which is called
  • understanding :: and ::: calls

Example

Function fun_tst executes function FUN on x:

fun_tst <- function(x = 1:100, FUN = mean) {
    return(FUN(x))
}

mean

fun_tst()
# [1] 50.5

sum

fun_tst(x = 1:1e3, FUN = sum)
# [1] 500500

Problem

fun_tst <- function(x = 1:100, FUN = mean) {
    msg <- paste("Executing function", FUN)
    print(msg)
    return(FUN(x))
} 


fun_tst(x = 1:1e3, FUN = sum)

Error in paste("Executing function", FUN) : cannot coerce type 'builtin' to vector of type 'character'


Attempts

1)

Interestingly, print can handle FUN object but results return function body.

fun_tst <- function(x = 1:100, FUN = mean) {
    print(FUN)
    return(FUN(x))
} 


fun_tst(x = 1:1e3, FUN = sum)

function (..., na.rm = FALSE) .Primitive("sum") [1] 500500

2) subsitute

fun_tst <- function(x = 1:100, FUN = mean) {
    fun_name <- substitute(FUN)
    msg <- paste("Executing function", fun_name, collapse = " ")
    print(msg)
    return(FUN(x))
} 


fun_tst(x = 1:1e3, FUN = sum)

>> fun_tst(x = 1:1e3, FUN = sum)
[1] "Executing function sum"
[1] 500500

Almost there but it looks like a total mess when used with :: as in:

>> fun_tst(x = 1:1e3, FUN = dplyr::glimpse)
[1] "Executing function :: Executing function dplyr Executing function glimpse"
 int [1:1000] 1 2 3 4 5 6 7 8 9 10 ..

Desired results

fun_tst(x = 1:1e3, FUN = dplyr::glimpse)
# Executing function glimpse from package dplyr
int [1:1000] 1 2 3 4 5 6 7 8 9 10 ...

fun_tst(x = 1:1e3, FUN = sum)
# Executing function sum from package base
Konrad
  • 17,740
  • 16
  • 106
  • 167
  • possibly relevant: ["How to get name of current function?"](http://r.789695.n4.nabble.com/How-to-get-name-of-current-function-td879084.html) and https://stackoverflow.com/questions/7307987/logging-current-function-name – Frank Oct 29 '18 at 13:40
  • Another option is to pass in the function name as character, print the name, and then use `eval` and `parse` to call the function. – Frank Oct 29 '18 at 13:44
  • @Frank Thanks, sounds like a sensible suggestion. I would hope that maybe there is an easy way to "fish out" function namespace (package) and it's name without deparse and then parse again.... – Konrad Oct 29 '18 at 13:54
  • 1
    Dead link in first comment should be ["How to get name of current function?"](https://stat.ethz.ch/pipermail/r-help/2009-January/378453.html) – Frank Mar 25 '22 at 18:45

2 Answers2

5

You're almost there with your second try (using substitute). The problem comes from the way R converts language objects to character:

> as.character(substitute(dplyr::glimpse))
[1] "::"      "dplyr"   "glimpse" 

Given this, it's not surprising that paste mangles it that way. I would fix this just by handling the two cases separately:

fun_tst <- function(x = 1:100, FUN = mean) {
  fun_name <- substitute(FUN)
  if (length(fun_name) == 1) {
    msg <- paste("Executing function", fun_name, "from package base")
  } else {
    msg <- paste("Executing function", fun_name[3], "from package", fun_name[2])
  }
  print(msg)
  return(FUN(x))
} 

This works on both of your examples:

> fun_tst(x = 1:1e3, FUN = sum)
[1] "Executing function sum from package base"
[1] 500500
> fun_tst(x = 1:1e3, FUN = dplyr::glimpse)
[1] "Executing function glimpse from package dplyr"
 int [1:1000] 1 2 3 4 5 6 7 8 9 10 ...

However, as written, it will think all functions in the global environment are from base, even if they're user-defined or introduced with a library call. If this is your use case, don't explicitly say "from package base".

Frank
  • 2,386
  • 17
  • 26
4

If you use deparse() and substitute you'll get the desired output, see a similar post on passing variable names to plot(), https://stackoverflow.com/a/9666650/1993932.

fun_tst <- function(x = 1:100, FUN = mean) {
  message(paste("Executing function",deparse(substitute(FUN))))
  return((FUN(x)))
}
> fun_tst(x = 1:1e3, FUN = sum)
Executing function sum
[1] 500500

> fun_tst(x = 1:1e3, FUN = dplyr::glimpse)
Executing function dplyr::glimpse
 int [1:1000] 1 2 3 4 5 6 7 8 9 10 ...

If you rather want the message as a character vector, replace message with print.

nadizan
  • 1,323
  • 10
  • 23