From: Joel VanderWerf Date: 2005-08-09T03:48:14+09:00 Subject: Re: polymorphism and/or named parameters: the ruby way? Eric Mahurin wrote: > --- "Berger, Daniel" wrote: ... >>class Foo >> attr_accessor :bar, :baz, :zap >> def initialize >> yield self if block_given? >> end >>end >> >>foo = Foo.new do |f| >> f.bar = "hello" >> f.baz = 5 >> f.zap = "world" >>end > > > What's the advantage of this over: > > foo = Foo.new > foo.bar = "hello" > foo.baz = 5 > foo.zap = "world" One advantage is you can construct and configure an object without assigning to a local variable. This can be useful if you are constructing a bunch of objects in #map or in literal hashes or arrays or (this is a bit far-fetched, but why not) parameter lists. And it is nice not to add a symbol to the namespace. I particularly like the fact that if you are doing several of these, possibly even in different methods, you can use the same |f| parameter and cut and paste between the assignments: def make_foos foo1 = Foo.new do |f| f.bar = "BAR" end foo2 = Foo.new do |f| f.bar = "ZAP" end end That has a nice standardized look to me, especially when you are populating many fields in several different methods. > Is it method chaining? You want this thing to return foo? You > could just end this statement list with "foo", or you could use > "ensure": > > begin > foo = Foo.new > ensure > foo.bar = "hello" > foo.baz = 5 > foo.zap = "world" > end Danger Will Robinson. An exception may happen in Foo.new.... > This begin..ensure..end expression returns foo (the result > before ensure) not "world" as you might expect. Great for > doing post operations after you calculate a return value > (equivalent of C's i++ is another example). You can use an else clause to return a value from a begin..end block, but only if there is at least one rescue clause (or else you get a warning). p( begin a = [] a << 1 a << 2 rescue else a end ) # ==> [1, 2] -- vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407