Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this work? Creating a logical with same name as base function still allows the function to be used

Tags:

r

I ran across an oddity here:

https://stackoverflow.com/a/11084038/636656

It appears that assigning to a name that is the same as a base function still allows you to use the base function:

> print <- FALSE
> print
[1] FALSE
> print("hi")
[1] "hi"
> 
> sum <- FALSE
> sum(1:10)
[1] 55
> sum
[1] FALSE

By contrast, assigning a function to the same name as a base function does not produce the same behavior:

> sum <- function(x) x^2
> sum(1:10)
 [1]   1   4   9  16  25  36  49  64  81 100
> sum
function(x) x^2

I'm aware that these sit in different namespaces, but I'm curious about two things:

  1. Why: Is this a failsafe to avoid difficult-to-recover-from behavior (e.g. if you overwrite rm)? What is the principle that predicts this behavior?

  2. How: Are there different lookup routines for functions and logicals by namespace?

like image 512
Ari B. Friedman Avatar asked Feb 24 '26 18:02

Ari B. Friedman


1 Answers

When evaluating a call to print(), R searches (along its ordinary search path) for a function with the name print. Your object print <- TRUE has the right name, but isn't a function, so the search shoots right past to the the first function having the right name.

Here's John Chambers' explanation, from "Chapter 13: How R works" in Software for Data Analysis: Programming with R.

The evaluation of the function call begins by looking for a function corresponding to the name. The rules for "looking for" are the same as the general rules for evaluating names mentioned above, except that the evaluator silently ignores any object found that is not a function, allowing local non-function objects with the same name as non-local functions, a concession motivated by people's tendency to assign objects names such as "c".

(I especially like that last bit about this being "a concession motivated by people's tendency to ..." ;)


Since you're interested in this, it's also worth having a look at match.fun(), which is designed to "extract the desired function object while avoiding undesired matching to objects of other types". It includes the following line, which nicely illustrates the strategy used by both and the evaluator:

FUN <- get(as.character(FUN), mode = "function", envir = envir)
like image 58
Josh O'Brien Avatar answered Feb 27 '26 07:02

Josh O'Brien



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!