From: Avi Bryant Date: 2001-10-30T11:37:08+09:00 Subject: [ruby-talk:23795] Re: RCR: Fun with attribute shortcuts solves RCR #3 and more On Tue, 30 Oct 2001, Albert Wagner wrote: > Wow, keep this up and you can boil a whole application down into a single > obtuse statement :-) Actually, I find such methods much less obtuse than the code they replace. Although it's very easy to recognize an accessor method when you see one, using attr_accessor makes the concept more explicit and more readable, not less. Similarly, == methods impose a certain cognitive load when reading them; I have to read the entire method to make sure it doesn't do anything unusual. With attr_equality, I know that the implementation of the method is the usual one. Macros and metaprogamming are not about obfuscation - quite the opposite, in fact. The more you can bring explicit design concepts and vocabulary into your code, the better. > On Monday 29 October 2001 04:45 pm, you wrote: > > Hi everyone, remember this? > > > > >I'm constantly creating small classes, and many of them start something > > >like: > > > class Msg > > > def initialize(name, type, txt) > > > @name, @type, @txt = name, type, txt > > > end > > > # ... > > > end > > > > Yeah, it's a classic, RCR #3. We all hate repetition and typing > > stuff that is obvious, right? > > > > Last time it was Joe McDonald who said: > > > and if you have a sec, vote on RCR #3. It's a pet peeve of mine. > > > > I think it's a pet peeve for a lot of us but I can see why > > RCR #3 was rejected as it stands now. > > What would it mean for example, if you created another > > function in the same way, like def func(@instance_var) - > > is @instance_var assigned also in that case? > > If not, why should there be a special case for initialize? > > > > So instead I propose to extend on the much loved shortcut > > methods that exist for accessors. > > > > I.e. attr_accessor :a, :b, :c creates getters and setters for > > @a, @b and @c so why not: > > > > class Mine > > attr_initializer :a, :b, :c > > ... > > end > > > > attr_initializer creates an initializer > > for them: > > > > def initialize(a, b, c) > > @a, @b, @c = a, b, c > > end > > > > So there's the idea - I thought it was quite nice but > > now comes the fun part. I love this - when you get a good idea, > > often it's easy to implement in Ruby without touching any > > interpreter or such! For example, if you didn't get this yet, > > notice that "attr_accessor" and the like are described in docs as > > being just plain methods, in the class Module! > > > > So in some spare time at RubyConf and OOPSLA I fooled around with this > > and got really positive responses, for example at the BOF session > > at OOPSLA. > > Trying it out for real makes a much better impact. > > Using the eval-family of functions and the open classes, for > > example "Class" and "Module", you can do a lot of cool stuff > > that looks a lot like extentions of the language syntax, so here > > is my implementation of attr_initializer: > > > > # file: AttrInitializer > > class Module > > def attr_initializer(*attrs) > > alist = plist = "" > > attrs.each do |v| > > alist += "@#{v}," # >> @var1,@var2,@var3, ... > > plist += "#{v}," # >> var1,var2,var3, ... > > end > > alist.chop!; plist.chop! # Remove last comma > > class_eval "def initialize(#{plist}); #{alist} = #{plist}; end" > > end > > end > > > > Since the Class class inherits from Module, now you can just > > require this file and you are able to use the attr_initializer > > shortcut in all classes. > > > > > > OK, now let's keep it going. What else is common to define in many > > classes? Well, the default definition of equality is that the > > compared references must be refs to the same object. However, it is > > more common to want to compare (part of) the inner state of objects > > and if they are equal, then the two different objects should be > > considered equal. > > > > So you end up often defining == in your classes, like this, right? > > > > class Mine > > attr_accessor :foo, :bar, :moo > > # @foo, @bar, and @moo are my > > # important inner state > > > > def ==(obj) > > @foo = obj.foo && > > @bar = obj.bar && > > @moo = obj.moo > > end > > end > > > > Nowadays I just do this: > > > > class Mine > > attr_equality :foo, :moo, :bar > > ... > > end > > > > Another option is to leave out the names of objects to make > > it even simpler. This requires the equality function to introspect > > self and the compared object to find all their instance vars. > > > > class Mine > > attr_equality > > ... > > end > > > > I won't post the implementation of attr_equality because it's > > longish, to support also the second option but you get the > > idea from the attr_initializer example. > > > > I'll make an RCR for this and we'll see if people like it. > > If you want a full implementation of both shortcuts > > with some tests to go with them Drop me an email directly. > > Don't reply to the list by mistake... > > (Yes, XP-enthusiasts, I wrote the tests first! Great isn't it? > > Although I updated them to run with Lapidary later) > > > > Have fun > > > > /Gunnar > > > > --- > > Gunnar Andersson > > gand -at- acm.org > > > > > > __________________________________________________ > > Do You Yahoo!? > > Make a great connection at Yahoo! Personals. > > http://personals.yahoo.com >