Consider the following R input:
if(TRUE){1}else{0} + if(TRUE){1}else{0}
The result is 1, but I was expecting 2. If I enclose each if-else statement in parentheses,
(if(TRUE){1}else{0}) + (if(TRUE){1}else{0})
then the result is 2.
Can someone explain this behaviour?
The else clause doesn't end till R can identify the end of the expression. In R the {} aren't part of the syntax for if/else statements. The {} can be used anywhere you want to possibly put multiple statements. You can also do
if(TRUE) 1 else 0 + if(TRUE) 1 else 0
The {} aren't really meaningful. And since
0 + if(TRUE) 1 else 0
is a valid expression, R just assumes you wanted all of that for your else clause. Normally R will end the else clause when it encounters a newline after a completed expression. This means that
if(TRUE){1}else{0} +
if(TRUE){1}else{0}
will also return the same value because the + at the end of the first line indicates that there's more to come because a valid expression can't end in +.
Note you can see how the expression is turned into the abstract syntax tree with the help of the lobstr package if you are really curious.
#lobstr::ast(if(TRUE){1}else{0} + if(TRUE){1}else{0})
o-`if`
+-TRUE
+-o-`{`
| \-1
\-o-`+`
+-o-`{`
| \-0
\-o-`if`
+-TRUE
+-o-`{`
| \-1
\-o-`{`
\-0
Here we see that everything is nested in the first if. The + is not the main operator.
As you've done, you can use () or {} to end the expression blocks explicitly
{if(TRUE){1}else{0}} + {if(TRUE){1}else{0}}
Consider also the case of
x <- 5
if(FALSE) x+1 else x+2
# [1] 7
if(FALSE) x+1 else {x}+{2}
# [1] 7
Note how the x+2 is taken all together for the else expression. It doesn't end at the first symbol x.
Is has something to to with operator affinity which determines the order of evaluation. Like math, parenthesis have a higher priority than multiplications with have a higher priority than plus and minus. The second part of the expression will never get evaluated and thus ignored resulting in 1 e.g. if(TRUE){1}else{0} + message("I'll never get printed"). Including the parenthesis will force to first evaluate both parts seperatley and then do the plus resulting in 2.
Related
I am new to R and I am trying to understand why when we use && or || between two logical vectors it returns just 1 element
a<-c(TRUE,FALSE,TRUE)
b<-c(FALSE,FALSE,FALSE)
a&&b
Why doesn’t this return a logical vector?
There are two kinds of logical operators in R, vectorized and not vectorized. The && and || are not vectorized. They are intended to be used with single TRUE or FALSE values on either side, and short-circuit evaluation is used: so if the result is known after evaluating the left-hand side, the right-hand side will not be evaluated. For example,
FALSE && fn()
is FALSE regardless of the value of fn(), so it won't be evaluated. This is useful in tests where the right-hand side might give an error, e.g.
if (is.numeric(x) && x + 1 > 0)
since x + 1 > 0 will give an error if x is not numeric.
The & and | operators are the vectorized versions. They take vectors of logicals on both sides, and return a vector of logical values. They will always evaluate both sides. They need to do this in examples like
FALSE & fn()
because even though the result is known to be false, the length may change depending on the result of calling fn().
In upcoming versions of R, it will be an error to use something like your example, because it doesn't make sense to use && with length 3 vectors.
Due to a typo I found out this code works [note the repeated - in the 2nd line]
foo <- function()
-------------------------
{
1
}
Calling foo() returns -1. The number of - determines if the returned value is positive or negative [odd number returns a negative number].
I didn't find anything regarding this R function definition so I am now asking why is this allowed and what is the purpose of this.
Even the official R documentation doesn't mention this at all. Any idea?
A note: invisible(1) doesn't work. The output is not suppressed when there is a sign character before the opening {.
You've tripped on the strange allowances of R's syntax rules for function bodies.
Since the syntax of functions in R allow for any expression after the argument list, usually R functions provide a list of expressions surrounded by {}. This is sometimes known in other languages as an expression "block." In R, the "evaluation value" of a block is the evaluation value of the last expression in the block.
If -1 is a valid expression, then -{1} is a valid expression as well.
- is also the unary negation operator, and it is repeatable in R. Therefore:
1 = 1
-1 != -1
--1 == 1
----1 == 1
-----1 == -1
So the evaluation goes:
foo <- function() ------------------------- {1}
foo <- function() ------------------------- 1
foo <- function() -1
And due to R's syntax rules, you could as easily go:
foo <- function() -1
Javascript's comma operator is useful for inserting commands within code without it breaking the workflow. The preceding expression is executed but otherwise ignored (e.g. if embedded in a function that is expecting a different object):
> x = 5, 4
< 4
> x
< 5
Is there any way to implement this in R? I've tried following
',' = function(x, y) { x; y }
but R seems to have locked comma down:
> 4, 5
Error: unexpected ',' in "4,"
Is there any workaround to this?
(Un)fortunately , is one of the very few things in R that cannot be overloaded/redefined. It’s not an operator in the language, unlike e.g. `{` and `(`.
In a similar vein, while you can overload `=` and `(`, you cannot change their meaning indiscriminately; in a function call with parameters (e.g. f(a = 1, b = 2)), neither ( nor = can be made to change their meaning because, once again, they’re not operators in this context).
As noted in the comments, for your purpose, ; seems to be a very close equivalent, though.
Python, Java and Scala have ternary operators. What is the equivalent in Julia?
You may be referring to this.
a = true
b = 1
c = 2
julia>a ? b : c
1
a = false
julia>a ? b : c
2
For inline use, a ? b : c exists, as mentioned by the previous answer. However it is worth noting that if-else-end in Julia works just like (if cond expr1 expr2) in most Lisp dialects which acts both as the if-clause and as the ternary operator. As such, if-then-else returns the return value of the expression that gets executed.
Meaning that you can write things like
function abs(x)
if x > 0
x
else
-x
end
end
and this will return what you want. You do not have to use a return statement to break the function block, you just return the value returned by the if-block.
Inline, you can write
if (x > 0) x else -x end
which will return the same thing as the ternary operator expression (x > 0) ? x : -x , but has the benefit of avoiding perl-ish ?: symbols and is generally more readable, but less chainable.
Most languages have a ternary operator separate from if-then-else because if clauses are statements, while in lisp-like languages they are expressions just like everything else and have a return value.
Yes! Julia has a ternary operator. Here is a quick example from the Julia documentation:
The so-called "ternary operator", ?:, is closely related to the if-elseif-else syntax, but it is used where a conditional choice between single expression values is required, as opposed to conditional execution of longer blocks of code. It gets its name from being the only operator in most languages taking three operands:
a ? b : c
The expression a, before the ?, is a condition expression, and the ternary operation evaluates the expression b, before the :, if the condition a is true or the expression c, after the :, if it is false. Note that the spaces around ? and : are mandatory: an expression like a?b:c is not a valid ternary expression (but a newline is acceptable after both the ? and the :).
The easiest way to understand this behavior is to see an example. In the previous example, the println call is shared by all three branches: the only real choice is which literal string to print. This could be written more concisely using the ternary operator. For the sake of clarity, let's try a two-way version first:
julia> x = 1; y = 2;
julia> println(x < y ? "less than" : "not less than")
less than
julia> x = 1; y = 0;
julia> println(x < y ? "less than" : "not less than")
not less than
In Julia, I might want to write a function that returns 0 if the input is less than 1, or returns 2 if the input is greater than or equal to 1. This is a pretty simple function, and the verbosity of a five-line if else construct is probably excessive. So I'm trying to turn it into a one-line function. The best I can come up with is as follows:
f(x::Number) = begin (x < 1) && return(0); return(2); end
or
f(x::Number) = begin x < 1 ? (y=0) : (y=2); return(y); end
Are there any simpler ways to define this function?
julia> f(x::Number) = x < 1 ? 0 : 2
f (generic function with 1 method)
julia> f(0)
0
julia> f(1)
2
julia> f(0.99)
0
Alternative solution:
f(x::Number) = if (x < 1) 0 else 2 end
The if-elseif-else syntax in Julia will return the value of the expression that gets executed, which imho makes the C-like ternary operator rather superfluous. As in, all of its functionality is encompassed by a more readable alternative.
Looking at your previous attempts, I think it is worth mentioning that unlike in say Python, you rarely need to explicitly use return(). Often you can just return whatever your if-elseif-else blocks return, much like you would in most lisp dialects. Explicit return is like goto or break, something that you use to break control flow in exceptional cases.