if/else constructs inside and outside functions

Solution 1:

Executive Summary:

There are only two ways for R to know that an else clause belongs to the if clause above it:

  1. The entire if...else statement (and perhaps other statements as well) is enclosed in braces;
  2. The word else appears on the same line as the end of the if clause.

Evidence:

The above discussion helped me, but I hope I can offer a useful quibble. Yes, it is correct that

f <- function (exp)
    if (exp)
        1  
    else
        2

fails with the classic Error: unexpected 'else' in "else" message due to R's failure to keep reading past the 1. Two ways have been correctly offered to make R keep reading past the 1:

f <- function (exp) {
    if (exp)
        1  
    else
        2
}

and

f <- function (exp) if (exp) 1 else 2

But there is a third way not yet mentioned---just move else up a line. Thus, the following also works because R knows to keep reading past the 1:

f <- function (exp)
    if (exp)
        1  else
        2

I think the key point is to either brace the entire body of the function, or make sure the else occurs on the same line as the end of the if clause so that R knows to keep reading. That's why the one-line solution works. It is also why this works:

f <- function (exp)
    if (exp) {
        1
    } else
        2

But this fails:

f <- function (exp)
    if (exp) {
        1
    }  
    else
        2

And using the more standard bracing of the function body, this works too:

f <- function (exp) {
    if (exp) {
        1
    }  
    else
        2
}

But whether or not we are building a function is a red herring. What matters is only braces and location of else. Thus, these work:

{
    if (exp) {
        1
    }  
    else
        2
}


if (exp) {
    1
} else
    2

but this fails:

if (exp) {
    1
} 
else
    2

and to demonstrate my assertion 1 at the top, this works:

{
x <- 4
if (exp) 
    1
else
    2
}

Solution 2:

It’s a consequence of using an interactive shell (REPL) to run scripts:

After the first branch the shell has seen a complete statement so it assumes that you’re done typing. Unfortunately, R uses the same shell for interpreting scripts even if they are not typed in interactively – so even when you save the if statement to a file and source it (or pipe it into R) you will get the error on the else branch.

But the following will work just fine:

if (exp) a <- 1 else a <- 2

Here, the interpreter swallows the line and executes it.

In your function one would assume that the same applies – and it does! However, the function itself starts with an open brace in your case, so R has to read until it finds the matching closing brace. By contrast, take this function declaration:

f <- function (exp)
    if (exp)
        a <- 1
    else
        a <- 2

In R you can define functions without braces around the body. But the above code will fail for the same reason that the standalone if without braces fails. By contrast, if I had written the if on a single line this code would once again work.

Incidentally, your function uses an assignment to a variable that isn’t used. You can (should) do the following instead:

f <- function (exp) {
    if (exp)
        1
    else
        2
}

… and the same when using if inside the shell:

a <- if (exp) 1 else 2

because in R, if is an expression which returns a value.