7 ms·
It is supposed to work this way for some good reasons. But! Enough people have had the same problem as you that new versions of Ruby behave the way you expect.
by ambition 19y ago
It is supposed to work this way for some good reasons. But! Enough people have had the same problem as you that new versions of Ruby behave the way you expect.
- raganwald 19y agoHelp me understand: what are the good reasons for the parameters of a block overwriting variables in an enclosing scope? That is, we are talking about: i = 100 x = 0 [1,2,3].each { |i| x += i } I understand why it is incredibly helpful for x to refer to a variable in the enclosing scope (even if we could accomplish this same effect with a fold). What are the use cases for the parameter i referring to a variable in the enclosing scope?
- ambition 19y agoOh, you're right, I had missed that. Yeah, that's dumb. I can't think of any iterators that would leave useful information in the parameters, either.
- brlewis 19y agoAs someone who's used to Scheme (lexical scoping), I have to say that's pretty bizarre. That's my second disappointment with Ruby blocks. The first was learning you could only have one block argument. Do they resemble first-class objects at all? Can you assign a variable to a block? If you were to assign { |i| x += i } to a variable outside that enclosing scope, and then used that variable in that scope, would i be overwritten in that call to the block?
- raganwald 19y ago"you could only have one block argument" Do you mean one method can only have one block?
- brlewis 19y agoHaving only read about Ruby and not coded in it, I'm not sure what the correct terminology is. I'm talking about doing something like this: someObject.someMethod({block1},{block2})
- tptacek 19y agoYou can't pass more than one block literal to a method. But you can certainly pass multiple blocks; they're objects, just like anything else. Just add the token "lambda" to your expression: def foo(x, y); x.call(y.call); end foo(lambda {|x| 2+x}, lambda {1}) # => 3 It seems to me that in this case, the language degrades to approximately the same level as Common Lisp.
- brlewis 19y agoIt's good to see that an upgrade to approximately the power of CL is possible in this case. Still, I feel a little let down. When I first saw Ruby block literals, I said to myself, "Hey, that's a great, concise syntax for lambda. Languages really are getting more lisp-like all the time." But now I know that Ruby block literals aren't really lambda. It does look like Ruby lambdas really are lambdas, though.
- mdemare 19y agoBlocks are lambda's, they're just not objects (but they can be converted to objects.)
- brlewis 19y agoIf you can't pass more than one block literal to a method, then a block literal is not a real lambda, from the Lisp point of view.
- tptacek 19y agoThis is confusing, because Lisp doesn't have the literal notation you're talking about. Since Ruby supports arbitrary lambdas using "lambda" notation (something Python does not support), it seems like Ruby's syntax can only be be better than Lisp's in this regard.
- brlewis 19y agoCould you give a more complete example? I'm getting sane behavior in Ruby 1.8.6: irb(main):010:0> f = lambda { i = 100; x = 0; [1,2,3].each { |i| x += i }; x} => #<Proc:0x05011b34@(irb):10> irb(main):011:0> f.call() => 6
- raganwald 19y agoyou missed the fun: macbook-pro-2:trunk raganwald$ ruby -v => ruby 1.8.6 (2007-03-13 patchlevel 0) [i686-darwin8.10.1] macbook-pro-2:trunk raganwald$ irb irb(main):001:0> lambda { i = 100; x = 0; [1,2,3].each { |i| x += i }; i }.call => 3