The problem of "print line if line = DATA.gets"
Right now, I find the following code will raise an exception:
print line if line = DATA.gets
undefined local variable or method `line' for main:Object (NameError)¶
"print line while line = DATA.gets" also doesn't work, maybe "unless" "until" modifiers either.
It seems that the Ruby interpreter is too impatient, once seeing unassigned variable "line", it croaks.
However, the expression after "if" or "while" modifier should be evaluated first. Logically, I think the code above should work properly, there's no need to write "line = nil" before it.
#1 Updated by Michael Edgar about 5 years ago
Some technical background: the current issue stems from how the parser must differentiate between local variables and method calls. Presently, local variables are created by the parser upon their introduction (assignment, rescue handlers, etc.), and they are available lexically after that in the given scope. This approach allows the parser to create the AST as each grammar rule is parsed. However, as you note, the if-guard and until-guard constructs, which are parsed after the guarded body, are executed before the guarded body. When not using begin...end with while-mod and until-mod, the condition is executed first as well.
Fixing this would involve post-processing in the parser, because the parser will discover the assignment after it has parsed reference and created the relevant AST node(s). One strategy is, when a guarded expression is parsed, to go back and examine the guarded body for local variable references that were instead considered method calls, replacing them with lvar references. It'd be a bit messy, but should work. It would break backwards compatibility, but not really in a meaningful way; it'd probably end up targeted for 2.0 though, regardless.
I'll whip up a patch implementing this today.
#3 [ruby-core:43648] Updated by Martin Dürst over 4 years ago
Just for completeness, at today's developers' meeting in Akihabara, there were several people who were supportive of this proposal. Arguments given were that humans read code top-down, but not necessarily left-to-right character-by-character, and that if we would want to claim that Ruby works strictly top-down and per-line-left-to-right, then postfix if (and friends) would be impossible in the first place.