Feature #4965
closedThe problem of "print line if line = DATA.gets"
Description
Right now, I find the following code will raise an exception:
print line if line = DATA.gets
END
abcdef
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.
Updated by adgar (Michael Edgar) over 13 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.
Updated by mame (Yusuke Endoh) over 12 years ago
- Status changed from Open to Assigned
- Assignee set to matz (Yukihiro Matsumoto)
Updated by duerst (Martin Dürst) over 12 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.
Updated by matz (Yukihiro Matsumoto) over 12 years ago
- Status changed from Assigned to Rejected
The reason behind has been explained in #1141. If someone want to change the rule, he need to understand the rational first, then should try persuade me.
Matz.
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 12 years ago
Hi Matz, some people tried to with the argument that if you're reading a post-if/unless and they seem natural, using a variable assignment alongside with the post-if/unless would be just as natural.