From: "David A. Black" Date: 2008-11-02T13:53:02+09:00 Subject: Re: How to access to local variables in enclosing scopes? Hi -- On Sun, 2 Nov 2008, Yuh-Ruey Chen wrote: > On Nov 1, 7:26 am, "David A. Black" wrote: >>> I guess my big beef with Ruby is that it is too complex and bloated >>> with features that often are inconsistent or lack symmetry with each >>> other. It's too "magical", making it hard to learn exactly how the >>> language works. From a language design perspective, Ruby really seems >>> like a mess to me, although with moments of brilliance. Most of the >>> time, when I'm metaprogramming, I'm guessing and looking at the >>> output, hoping I got so-and-so quirk correct. >> >> I'd be interested in seeing some of these examples. In my experience, >> a great deal of what people find confusing or opaque in Ruby turns out >> to be confusing because it is so simple, and because there are so few >> exceptions to the rules. I've always been impressed with the >> strictness with which Ruby applies a small number of underlying >> principles. It's possible that a bit of analysis of some examples >> could help you nail some of those. > > Okay, there are several little quirks of Ruby that annoy me, but I'll > just a list a couple: > > 1) When I saw the method! notation for mutation methods, I thought > that was particularly brilliant. But then I noticed that methods are > only postfixed with ! if there was already another method that did the > same thing except on a new copy. It would've been nice of all mutation > methods were postfixed with !. One use case for this would be trapping > all mutation methods of a class for some purpose (e.g. making a read- > only class, or a class that notifies an observer upon mutation). The ! methods are not specifically mutation methods. See: http://dablog.rubypal.com/2007/8/15/bang-methods-or-danger-will-rubyist for an explanation of what they signify (and why it's cool, and why putting ! on Array#pop and so forth would not be cool). > 2) Awkwardness of defining singleton methods. Contrast: > > class << obj > def singleton_method > 'foo' > end > end > > with: > > obj.singleton_method = function() { > return 'blah' > } > > Of course, YMMV with regards to "elegance". When writing instance methods, I like to be inside a code definition block, without regard to whether the class is a singleton class or not. If you don't, you can always do: def obj.some_method but that gets tiresome if you've got a lot of them. class << obj just puts you in the class block, and then you proceed as you always do with instance methods. There's really no need for a whole separate apparatus; the class/object model is already designed to give you the interface to singleton behavior that you need. > 3) There are public/protected/private modifiers for functions, but not > for modules. (Yes, I'm aware that Ruby isn't Java, and that "private" > means "instance-private" not "class-private".) > > 4) "Scoping" weirdness (or whatever it's called) with modules and > classes. > > class A > class << self > attr_accessor :x > > def foo > @x = 20 > end > end > end > > A.foo > p A.x > > B = Class.new > B.instance_eval do > attr_accessor :x > > def foo > @x = 40 > end > end > > B.foo > p B.x # error because self within B.instance_eval is still B, not the > singleton thingamajig. Yet by some magic, |def foo| makes a singleton > method. It's by decree. It's extremely rare to use def inside a code block, so the idea, as I understand it, is that this is a way to introduce the ability to do the almost only imagineable such scenario: namely, creating a singleton method. The other imagineable similar scenario is represented by class_eval (aka module_eval). It's also related to the fact that def is a keyword, not a method. In your example, attr_accessor is simply a method call without an explicit receiver, which is always sent to "self" (B, in this case). There's no complexity there. def, however, doesn't have a receiver; it's a different kind of construct. So decisions always have to be made about what its effect will be in a given context. Its treatment in instance_eval is definitely special-cased, but if it weren't (if def just created an outer-level method, as it would in a non-special-cased code block), it would never be used (just as def never is in normal code blocks). So it's just a bit of quasi-vacant semantic space with a possible use-scenario, and it got engineered accordingly. > So there's really another type of "scope" or whatever it's called > here: module vs. instance. And I have to remember not to trip up on > it. In general you have to remember not to trip up on all the idioms of any language :-) It sounds like you're disgruntled about Ruby specifically because you're finding things that you have to learn, and that you can't just slide into based on what you've done in other languages. That's correct: Ruby really is its own language, and you do have to learn its idioms and toolsets. I would second what Ara said, namely that it would be interesting to see some actual things you're trying to do, and points at which you feel that Ruby's scoping rules and so forth are stopping you. David -- Rails training from David A. Black and Ruby Power and Light: Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL Advancing with Rails January 19-22 Fort Lauderdale, FL * * Co-taught with Patrick Ewing! See http://www.rubypal.com for details and updates!