Different behavior of -> (right-arrow) and <- (left arrow) on a for loop
Asked Answered
L

1

4

Since R3.0, a for loop returns NULL (as documented):

x <- for(i in 1:3) {i+1}
x
# NULL

However, using the right-arrow assignment, it seems to returns the last value:

for(i in 1:3) {i+1} -> x
x
# [1] 4

The documentation doesn't comment on ->, and as pointed by Ben Bolker, the -> seems to be converted to <- anyway:

expression(1 -> x)
# expression(x <- 1)

So my questions are:

  1. Is this a bug or a misunderstanding?
  2. Why would -> behave differently from <- in that case, if they're supposed to be identical?
Lookeron answered 16/8, 2020 at 3:46 Comment(0)
S
8

Really this is more of an issue of parsing I think. The command

for(i in 1:3) {i+1} -> x

actually is parsed to something like

for(i in 1:3) {
   x <- {i+1}
}

You can kind of see that in the AST with the help of the lobstr package

lobstr::ast(for(i in 1:3) {i+1} -> x)
o-`for` 
+-i 
+-o-`:` 
| +-1 
| \-3 
\-o-`<-` 
  +-x 
  \-o-`{` 
    \-o-`+` 
      +-i 
      \-1 

So the assignment is part of the loop body. For example you can also run this without error

for(i in 1:3) {i+1} ^2

or see what you get from this expression

for(i in 1:3) {i+1} + {print(i)}
# [1] 1
# [1] 2
# [1] 3

The loop body expression doesn't terminate at the end of the first brace. It ends at the end of the line (or you could make it end with a ; or by nesting it in a code block). This isn't unique to the assignment operators in any way.

So this isn't a bug, it's just a bit of confusing syntax. What you were expecting would look more like

{for(i in 1:3) {i+1}} -> x

which still returns NULL.

Schroth answered 16/8, 2020 at 3:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.