7

I recently encountered this example in my R tutorial:

sapply(list(runif (10), runif (10)), 
   function(x) c(min = min(x), mean = mean(x), max = max(x))

I was under the impression that in the function()-function you first had to list your arguments within parenthesis and then the actions performed by the function inside curly brackets.

In this example there are "no" curly brackets and the code seems to function anyway, how can this be?

moodymudskipper
  • 46,417
  • 11
  • 121
  • 167
Magnus
  • 728
  • 4
  • 17
  • You don't need that unless you have a separate statement .e. `function(x) {x1 <- x[x > 0]; c(min = min(x1), mean = mean(x1))})` – akrun May 31 '19 at 20:02

2 Answers2

4

It is a single statement and for that there is no need for any brackets

sapply(0:5, function(x) x  + 5)

But, if the function demands multiple statements, each statement can be separated within the curly brackets

sapply(0:5, function(x) {
             x <- sequence(x)
             x1 <- x[x > 2]
             c(mean = mean(x1), min = min(x1))
             })

As @qdread mentioned in the comments, a good practice would be to include the curlies though there might be a slight efficiency dip

library(microbenchmark)
microbenchmark(nocurly = sapply(0:1e6, function(x) x + 5),
      curly = sapply(0:1e6, function(x) {x + 5}))
#Unit: milliseconds
#    expr      min       lq     mean   median       uq      max neval
# nocurly 666.2539 922.0929 928.6206 942.9065 966.8318 1113.828   100
#   curly 710.8450 925.7917 947.7641 955.2041 973.8009 1081.597   100
akrun
  • 874,273
  • 37
  • 540
  • 662
  • 2
    I would add that it's generally seen as good coding practice to include the brackets even if there is only one statement. If you need to add other statements later, the brackets are already there. Not to mention it's more consistent, and often more readable, to include them. – qdread May 31 '19 at 20:11
  • 1
    @qdread there would be slight hit on performance by including the brackets – akrun May 31 '19 at 20:11
2

function is a primitive function :

`function`
.Primitive("function")

Its second argument is the body, it's a quoting function, meaning this second argument is not evaluated. These are equivalent :

fun1 <- function(x) x + 5
fun2 <- `function`(NULL, x + 5)
formals(fun2) <- alist(x=)
fun3 <- do.call( 'function', list(as.pairlist(alist(x=)), quote(x+5)))
identical(fun1,fun2)
[1] TRUE
identical(fun1,fun3)
[1] TRUE

See this question adressing why we can't use the function function as we can with other : How do I call the `function` function?

The syntax used for fun1 is function(...) body, where ... will be mapped to a pairlist.

{ is itself a function. Unlike (, { is never treated specially by the parser.

So when you have a single call in your expression, the { is not needed, not because function's syntax is designed to be flexible, but because it's not part of the function syntax.

I tend to agree that it's good practice to use curly braces for consistency, when you want to use trace for example inconsistencies are annoying. It's generally of little consequences though, and it's not enforced by base R :

mean
# function (x, ...) 
# UseMethod("mean")
# <bytecode: 0x000000000e146288>
# <environment: namespace:base>

body(mean)
# UseMethod("mean")

As a side note rlang has a nice function to be able to get a consistent body output:

rlang::fn_body(mean)
# {
#   UseMethod("mean")
# }
moodymudskipper
  • 46,417
  • 11
  • 121
  • 167