DAY 5: Functions, their arguments and their scoping

SaiGayatri Vadali
5 min readDec 23, 2017

--

We are on the fifth day of our mission to learn R in 30 days. The other articles are available here. If you want to know more about this series, you can read here.

Functions:

Functions play a very important role in any programming language. R is no exception. It has many pre-built functions too. Let’s first see how a function is defined in R by a user.

> my_function <- function(<arguments>){    
#do something
}

So, a function is declared with function() directive. Functions in R have some interesting properties

  1. Functions are first class objects in R which means they are nothing but other objects like data frames, matrices and vectors.
  2. Functions can be passed as arguments to other functions.
  3. Functions can be nested — that is a function can be defined in other.
  4. Return value of the function is the last expression to be evaluated in the function body. You don’t need to specifically write a return statement.

let’s have a glance at an example in order better understand above statements

my_function1 <- function(num){  #num is the argument
num=num*3
res=num+4 # This statement acts the return statement
}
print(my_function1(9))
[1] 31

Arguments in function:

Functions in R have named arguments. That is arguments might be defined and named before itself and you can set their values. It is not needed that we set values for all the arguments of a function. Often we send only those parameters which are needed for our computations. Go through this example, in order to get better understanding

> my_data <- rnorm(100)
> mean(my_data)
[1] -0.1005646
> mean(x=my_data)
[1] -0.1005646
> mean(x=my_data,rnorm=FALSE)
[1] -0.1005646

Don’t worry about rnorm(100) , we will know more about it. We are just getting random normalised data with 100 values. Then we are using an inbuilt function mean() to get it’s mean value. Here, let’s see the three notations clearly.

  1. We have written only attribute value in the first example.
  2. In the second one, as you can see, we have given ‘x=my_data’ — This shows how named arguments work. Here ‘x’ specifies data.
  3. In the third one, we have ‘rnorm’ attribute set to FALSE.

All have given same result. This means, mean() method can be written in any of the above ways. We use it’s arguments depending upon on our necessity. In order to know, if mean() has some more attributes, type ‘?mean’ in your console. This gives necessary documentation from R. You can use ‘?***’ whenever you want to get some help about anything in R.

Default values of arguments :

We can set default values to arguments also just as mentioned below. They come handy when we call function () without passing any parameter values.

>my_function1 <- function(num=1){  
res=0 #num is the argument with default value set against it.
num=num*3
res=num+4 # This statement acts the return statement
}
>print(my_function1()) # No argument sent
[1] 7

Matching argument values:

R arguments can be matched positionally or by their names. That is if you don’t specify their names, you need to place arguments in the order mentioned during function definition. Otherwise, you can use the argument names and can place them in any order. This example makes this explanation clear.

my_function1 <- function(num, add, sub){  
res=0 #num is the argument
num=num*3
num=num+add
num=num-sub
res=num+4 # This statement acts the return statement
}
print(my_function1(add=3,1,4))
[1] 6
print(my_function1(3,1,4))
[1] 10

In the first case, I gave value of ‘add’ argument as ‘3’, hence match by name occurred. The others are chosen in the order of arguments. Hence, num=1, sub=4

But in the second case, positional match occurred and hence the result.

Lazy evaluation of arguments:

R arguments are evaluated lazily. That is the arguments are evaluated only when needed.

my_function1 <- function(num, add, sub){  
res=0 #num is the argument
num=num*3
res=num+4 # This statement acts the return statement
}
print(my_function1(3))
[1] 13

Here I didn’t pass ‘add’ and ‘sub’ values, yet the function didn’t produce error because, in R, only those arguments that are needed for computation are evaluated.

The “…” argument :

‘…’ indicates variable number of arguments. It is used when you don’t want to use all the default arguments specified in a pre-built function. It is also used when we don’t know number of arguments well in advance.

One thing that is to be remembered with “…” argument is that, the arguments used after “…” must be mentioned with their names.

mean(x, trim=0, na.rm=FALSE, ...)

How to know about arguments of a function?

There is a function called args() which does this work for us. Just send the function name as argument to args() function.

> args(my_function1)
function (num, add, sub)
NULL

Scope and Binding rules :

Scoping rules determine how a value is associated with a free variable in a function.

R uses Lexical scoping or static scoping. Consider the following function

my_function1 <- function(x, y){  
x^2+y/z
# This statement acts the return statement
}

Here x and y are the formal arguments( arguments in function definition are called formal arguments )but function has another variable ‘z’ which is not defined or assigned with some value prior to it’ use. These variables are called free variables. Scoping rules of a language determine how values of these variable are assigned.

Lexical scoping:

Lexical scoping means that R searches for the value of ‘z’ in the environment in which function is defined.

What is an enviroment ?

An environment is a collection of ( symbol, value) pairs. x is symbol , 1 is it’s value. Every environment has it’s parent environment. The only environment without parent environment is Global environment which is nothing but our workspace.

Search for the free variables in a function begins with in it’s scope and starts extending into it’s parent, then parent of it’s parent till global environment.

That means in R value of free variable is first searched in the environment in which the function is defined and it goes further till global environment. But this not always the case in other languages too. There is another scoping called Dynamic scoping.

Dynamic scoping:

In dynamic scoping, the value of free variable is first looked in the environment in which the function is called.

Let’s understand all this with these simple examples.

Lexical scoping occurs in R!!!
y<- 10 # function definition environment #1
my_function1 <- function(x){ #2
y <- 2 # function calling environment #3
y^2 +g(x)

}
g <- function(x){
x*y
}
print(my_function1(3))
[1] 31

In R, as lexical scoping occurs, the value of y in g(x) is chosen as 10.

Let’s see what happens with dynamic scoping. Note that the value of ‘y’ in ‘y²+g(x)’ expression is 2. There is no doubt in it. But in g(x), when ‘x*y’ computation occurs, it can chose ‘y’ value from two different scopes ( from line 1 or from line 3)

The value of ‘y’ becomes 2 in dynamic scoping and hence the total result would be ‘10’.

With that we are done with functions. Many have told me lexical and dynamic scoping are often confusing!! I hope, I made it clear to you. How did you feel about this article? I felt very much satisfied writing this article. I started experiencing the real amazing nature of R. Did you also start feeling ? Keep reading!! Keep sharing!! and fly with colours !!

--

--

SaiGayatri Vadali

An inquisitive Machine Learning Engineer, yoga trainer, fitness freak and a passionate writer!