Return syntax quirk in R - r

You can make a function with the following code in R, omitting the brackets after the return command, but the return statement does not behave as expected and seems to do nothing:
> func <- function(x) { return; print(x) }
> func(1)
[1] 1
Including the brackets behaves as expected:
> func <- function(x) { return(); print(x)}
> func(1)
NULL
Why? Does a return statement without an argument serve a purpose, and, if not, why doesn't it cause an exception?

I can perhaps offer some insight. In addition to it being legal in R to have a function by itself with no parameters, it is also legal to have a variable on a line with no assignments, function calls, etc. Consider the following code snippet:
x <- c(1,2,3)
x
print(x)
print
Here is the output from that:
[1] 1 2 3
[1] 1 2 3
function (x, ...)
UseMethod("print")
<bytecode: 0xbb87b8>
<environment: namespace:base>
In other words, from the console the default behavior for a variable or function by itself is to print information about that variable or function. So there clearly is defined behavior in this case, and it seems to be that the function does not get called. This makes less sense perhaps when this is happening inside another function, though it definitely seems that R has behavior defined for this.

function(x) { return(); print(x) } calls return() as a function. function(x) { return; print(x) } references return as an ordinary object. Here is the difference.
return # Just show the function body.
## .Primitive("return")
return() # Actually call the function.
## Error: no function to return from, jumping to top level

Related

return function inside with() block

How does return() in a with() block work?
Here is a test function
test_func <- function(df, y) {
with(df,
if(x > 10){
message('Inside step 1')
return(1)
}
)
message("After step 1")
if(y > 10){
message('In side step 2')
return(2)
}
message("After step 2")
}
The function keeps going after return(1).
df <- data.frame(x = 11)
y <- 11
test_func(df, y) ## result is 2
Output
Inside step 1
After step 1
In side step 2
[1] 2
return(1) doesn't return to the test_func() rather than get out the with() block
df <- data.frame(x = 11)
y <- 5
test_func(df, y) ## no result
Output
Inside step 1
After step 1
After step 2
I think the main point here is that return() is designed to exit the current scope to the parent scope with a particular value. In the case of running
return("hello")
# Error: no function to return from, jumping to top level
You get an error because we are calling this from the global environment and there is no parent scope you are jumping back to. Note that thanks to R's lazy evaluation, parameters passed to a function are usually evaluated in the environment where they were passed from. So in this example
f <- function(x) x
f(return("hello"))
# Error in f(return("hello")) :
# no function to return from, jumping to top level
So because we are actually passing in the return() call to the function from the global environment, that's where the return will be evaluated and will return the same error. But note that this is not what with does, instead it captures the commands you pass and re-runs them in a new environment. It's closer to something like this
f <- function(x) eval(substitute(x))
f(return("hello"))
# [1] "hello"
This eval() creates a new level of scope we can escape from, and because we aren't evaluating the parameter passed to the function directly, we are just running those commands in a different environment, the return is no longer evaluated in the global environment so there's no error. So the function we created is basically the same as calling
with(NULL, return("hello"))
# [1] "hello"
which is different from something like
print(return("hello"))
# no function to return from, jumping to top level
where the parameter is directly evaluated. So the different meanings of return() really are side effects of non-standard evaluation in this case.
When return() is used inside a with(), you are not returning from the function that you called with() from, but you are returning from the scope that with() created for you to run your command.
How to fix this particular problem is already addressed by the comments left by #IceCreamToucan. You just need to move the return outside of the with().

How do I use the variables from rlang::UQS in a custom function?

I am still trying to understand quosures in R, but I do not understand why the substitution in the function below fails.
my.toggle <- function(toggle) {
if (toggle) {
print("yes")
} else {
print("no")
}
}
fn.args <- list(toggle = T)
my.toggle(rlang::UQS(fn.args)) # fails
# Error in if (toggle) { : argument is not interpretable as logical
rlang::quo(my.toggle(rlang::UQS(fn.args))) # but this is the right function call
# <quosure: global>
# ~my.toggle(toggle = TRUE)
It seems like calling my.toggle(rlang::UQS(fn.args)) should be equivalent to my.toggle(toggle = T) (and, indeed, that's what you get when you wrap the function call in quo), but the function does not execute correctly. What am I doing wrong?
You'd have to evaluate your quosure, like so:
library(rlang)
eval_tidy(quo(my.toggle(UQS(fn.args))))
[1] "yes"
[1] "yes"
(Why does it print twice? This is an artefact of print(): print normally returns its argument, invisibly. It seems evaluating implicitly toggles visibility, so the return value prints again. If you just replace print("yes") with (print("yes")) (toggling visibility manually with parens), the behavior is consistent again with my.toggle(toggle = TRUE)). I wouldn't worry about it too much).
As to why you get the error: UQS() returns a list, specifically: a Dotted pair list of 1: $ toggle: logi TRUE. You could hack around with my.toggle(UQS(fn.args)[["toggle"]]).

Using the '->' operator in R to define a function requires parentheses to work

I was playing with R and its assignment operators a little and I found out that if I want to use the -> operator to write a function into a variable, I need to enclose the definition inside parentheses like so:
(function(x) {
return(x)
}) -> my_func
my_func("hi")
The following doesn't work as expected:
function(x) {
return(x)
} -> my_func
my_func("hi")
The output seems also rather strange to me:
function (x) my_func <- {
return(x) }
Error in eval(expr, envir, enclos): could not find function "my_func" Traceback:
Does anyone know why that is? My guess is that it will have something to do with the precedence and associativity of operators, but I can't put my finger on it...
The documentation for "function" in R show the following usage
function( arglist ) expr
So basically everything after function() will be interpreted as an expression and used as the function body. It just so happens that the assignment operator can be interpreted as part of that expression. Note that this is a valid expression in R
{1 - 2} -> x
So you are basically defining a function that does the assignment. You are not creating by evaluating that statement -- only defining an unnamed function. So for your example
function(x) {
x
} -> my_func
This line nerver creates a variable named my_func. It creates a function that will assign to a variable named my_func but that variable will only exist in the function scope and will not be available after the function finished running.
In your actual example, you used return so that local variable will never actually be created because the return() happens in the code block before the assignment completes. But if you did a global assignment, that would be more clear
if (exists("my_func")) rm(my_func)
exists("my_func")
# [1] FALSE
f <- function(x) {
x
} ->> my_func
f(5)
exists("my_func")
# [1] TRUE
But you can see that if you run, that variable is never created
if (exists("my_func")) rm(my_func)
function(x) {
x
} -> my_func
exists("my_func")
# [1] FALSE
When you use x <- function() {} with a new line after, these is a clear break so the parser knows where the expression ends. Adding in the () also makes is clear to the parse where the function expression ends so R doesn't gobble the assignment into the expression (function body) as well. Functions in R don't require curly braces or explicit return() calls: function(x) x is a valid function definition.
Without parenthesis the assignment -> is in the body of the function. So when you do
function(x) {
return(x)
} -> my_func
it is like
function(x) {
my_func <- {return(x)}
}
You can see that for instance by creating a variable:
a <- function(x) {
return(x)
} -> my_func
debug(a)
a(1)
Then it prompts the function as understood by R:
> a(1)
debugging in: a(1)
debug: my_fun <- {
return(x)
}

getting the arguments of a parent function in R, with names

I'm trying to write a function that captures the arguments of the function it is called from. For example,
get_args <- function () as.list( sys.call(sys.parent()) )[-1]
caller <- function (x, y, z) {
get_args()
}
caller(1,2,3)
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
sys.call() unfortunately does not add match parameter names with argument values, and I'd like to write a similar version of get_args that returns output similar to
caller2 <- function (x, y, z) {
as.list( match.call() )[-1]
}
caller2(1,2,3)
$x
[1] 1
$y
[1] 2
$z
[1] 3
replacing "get_args()" with "match.call()" directly is not the solution I'm looking for, since in reality get_args will do some other things before returning its parent functions arguments.
I've tried to use match.call() with sys.parent() in several ways, but I can't get the function to return the arguments of caller; it just returns the arguments of get_args().
Is there any way to make get_args() return output identical to that of caller2 for the above test case? I know that naming the arguments manually is possible using formals(), but is this guaranteed to be equivelant?
If any clarification is needed, leave a comment below. Thanks.
EDIT 1:
the aim of get_args() is to act as a user-friendly way of getting the arguments with which a function was called. Typing as.list( match.call() )[-1] gets old, but because match.call grabs the nearest function call it just gets the arguments of get_args() at the moment.
get_args() will also get default arguments from the parent function, but this easy to implement.
SOLUTION:
thanks Hong Ooi, the key to using match.call seems to be providing both the call and the definition of the function you want to find out about. A slightly modified, anonymous-friendly version of get_args is below for posterity
get_args <- function () {
as.list( match.call(
def = sys.function( -1 ),
call = sys.call(-1)) )[-1]
}
This version finds the function further up the call stack, grabs its definition and call, and matches parameters to its arguments.
get_args <- function()
{
cl <- sys.call(-1)
f <- get(as.character(cl[[1]]), mode="function", sys.frame(-2))
cl <- match.call(definition=f, call=cl)
as.list(cl)[-1]
}
The key here is to set the definition argument to match.call to be get_arg's calling function. This should (hopefully!) work for the general case where get_args can be called from anywhere.

force-evaluate an object being passed as an argument to a function

I would like to pass the value of an object as an argument to a function.
# This is my object
anObject <- "an_unkown_string"
# I would like to do the equivalent of:
someFunc("an_unkown_string")
# .. by somehow calling on the object containing the string
someFunc( ??? (anObject) )
For example, with the sample function below (based on save()):
someFunc <- function(...) {
names <- as.character(substitute(list(...)))[-1L]
return(names)
}
# Ideally, the output would be:
someFunc( ??? (anObject) )
[1] "an_unkown_string"
I do not have access to modify someFunc
I have tried the following, but with no success.
someFunc(Name_of_Object)
someFunc(eval(Name_of_Object))
someFunc(evalq(Name_of_Object))
someFunc(force(Name_of_Object))
someFunc(eval(parse(text=Name_of_Object)))
Any help is appreciated.
How about
> do.call(someFunc, list(anObject))
[1] "an_unkown_string"
Or you could make a wrapper
myWrap <- function(...) {
do.call(someFunc, as.list(...))
}
> myWrap(anObject)
[1] "an_unkown_string"
Another way to construct a call and evaluate it:
> call("someFunc", anObject)
someFunc("an_unkown_string")
> eval(call("someFunc", anObject))
[1] "an_unkown_string"
I suppose I should mention that ?do.call says
The behavior of some functions, such as substitute, will not be the same for functions evaluated using do.call as if they were evaluated from the interpreter. The precise semantics are currently undefined and subject to change.
Nevertheless, for now at least, anObject is evaluated when the call is constructed (in the call to call or do.call), so substitute finds "an_unknown_string" instead of "anObject".
I'm puzzled. Why are you trying to make this more complex than it realy is?
someFunc <- function(obj) {
return(obj)
}
> someFunc(anObject)
[1] "an_unkown_string"

Resources