4 ms·
That makes sense, but I've never seen statement modifiers defined that way. Every explanation I've ever seen, the pickaxe included, seems to outright state, or
by angilly 17y ago
That makes sense, but I've never seen statement modifiers defined that way. Every explanation I've ever seen, the pickaxe included, seems to outright state, or at least imply, the former.
- pvg 17y agoI think it's easy to get confused here because there's a natural tendency to read and interpret 'unless' as English and the fact that assignment in Ruby is also implicit declaration. Once this happens - a = a is defined. It doesn't matter at all what comes after (as long as it keeps the expression syntactically valid) - a is defined. The only question remains is what will end up getting assigned to it. Try a = asdfgasdfweradsf it will complain there is no asdf... but a is defined.
- deleted 17y ago[deleted]
- gaius 17y agoThat definitely sounds like a bug to me. Either a statement is fully valid and is executed, or it isn't and it isn't. In Python: >>> a=b Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'b' is not defined >>> a Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'a' is not defined >>> I think that follows the POLA...
- angilly 17y agointeresting. in ruby: ra:~$ irb irb(main):001:0> defined? a => nil irb(main):002:0> defined? b => nil irb(main):003:0> a = b NameError: undefined local variable or method `b' for main:Object from (irb):3 irb(main):004:0> a => nil irb(main):005:0> b NameError: undefined local variable or method `b' for main:Object from (irb):5 irb(main):006:0> defined? a => "local-variable" irb(main):007:0> 'a' gets defined.
- pvg 17y agoDepends what you are astonished by, I suppose. As far as I can tell the Ruby behaviour has to do with the fact that Ruby variable definition appears to take place sometime before evaluation, maybe during parsing. So as long as the statement parses and looks like a variable definition/assignment, you get your variable. On evaluation, undefined variables cause barfage but in the case above, the a got defined before the statement was actually executed.
- gaius 17y agoWell, I am astonished that entering invalid code can cause a persistent state change within my interpreter. I can't think of any other REPL language in which that happens. OCaml: # let a=b;; Error: Unbound value b # a;; Error: Unbound value a # Haskell: Prelude> let a=b <interactive>:1:6: Not in scope: `b' Prelude> a <interactive>:1:0: Not in scope: `a' Prelude> Scheme: guile> (define a b) Backtrace: In standard input: 1: 0* (define a b) standard input:1:1: In expression (define a b): standard input:1:1: Unbound variable: b ABORT: (unbound-variable) guile> a ERROR: Unbound variable: a ABORT: (unbound-variable) You can see where my astonishment comes from...
- pvg 17y agoYeah I was a little surprised too. It looks like the parser just defines foo for any parsable foo = .... before anything actually runs. Kind of a funky design choice, especially for such a dynamic language.
- deleted 17y ago[deleted]
- telemachos 17y agoIf it's a bug, it's by design. Note that this only happens with local variables (rather than instance, class or global variables) according to David Black's The Well-Grounded Rubyist, page 153 ("Assignment syntax in condition bodies and tests" - everything that follows, including emphasis is from the book): Ruby doesn't draw as clear a line as compiled languages do between "compile time" and "run time," but the interpreter does parse your code before running it, and certain decisions are made during that process. An important one is the recognition and allocation of local variables. When the Ruby parser sees the sequence identifier, equal-sign, value, as in this expression x = 1 it allocates space for a local variable called x. The creation of the variable - not the assignment to it, but the internal creation of a variable - always takes place as a result of this kind of expression, even if the code isn't executed! Consider this example: if false x = 1 end p x # Output: nil p y # Fatal error: y is unknown The assignment to x isn't executed, because it's wrapped in a failing conditional test. But the Ruby parser sees the sequence x = 1, from which it deduces that the program involves a local variable x. The parser doesn't care whether x is ever assigned a value. It's job is just to scour the code for local variables for which space needs to be allocated. The result is that x inhabits a strange kind of variable limbo. It has been brought into being and initialized to nil.
- angilly 17y agoCan a bug be by design? :)
- telemachos 17y agoIt's a fairly common phrase (I thought - maybe not) simply meaning: you or I or everyone may not like it, but the developers did it that way on purpose. In many cases, a bug by design is a question of trade-offs. In this case, stricter rules for the parser might mean more syntax for the programmer.
- gaius 17y agoFor this to count as a feature and not, umm, a dodgy implementation of a parser, it would have to convey some advantage... But what?