--- Joel VanderWerf <vjoel / path.berkeley.edu> wrote:

> Eric Mahurin wrote:
> > --- "Berger, Daniel" <Daniel.Berger / qwest.com> 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]


The exception issue bothers me too with this ensure trick. 
But, this else doesn't really help.  I was wanting something
that appplied some post operations after you determine the
return value.  For example, the equivalent to the C expression
a[i++] is the following using the ensure "operator":

a[begin i ensure i+=1 end]

I've benchmarked various ways of doing this and this method is
the clear winner.

Functionally, I guess something like this would be most
flexible (no performance advantage like "ensure"):

class Object
  def post
    yield(self)
    self
  end
end

Then you could do these types of things:

a[i.post{i+=1}]

foo = Foo.new.post do |f|
   f.bar = "hello"
   f.baz = 5
   f.zap = "world"
end

With this, no need for the "yield(self) if block_given?" in
initialize.

This very useful little method is a nice thing to have in your
bag-o-tricks.



		
____________________________________________________
Start your day with Yahoo! - make it your home page 
http://www.yahoo.com/r/hs