T
Trans
I have been working on a project where a particularly important
parameter can either be a hash (or hash-like object) or a proc. With
the later it is very nice to be able to use a block. But having to
accept both types of object makes it akward b/c of the distinction Ruby
makes between these kinds of parameters, i.e. arg vs. &arg. While this
has occured to me before with regards to default values (becuase blocks
parameters can not have default values) this issue makes the situation
particularly stark. Ruby is working against itself here. While Ruby
promotes duck-typing, in this particular case Ruby prevents it. The
prevention arises, it seems, from the a certain concept of yeild and
block_given? --that which makes a block an option on any method
wahtesoever without regard to the methods definition. While seemingly
convenient, this actually creates constraints that prove to be less
than convenient. After much consideration,I think Ruby is probably
being a little too magical for it's own good here.
Just to be very clear, here is a simple example to demonstrate what I
mean about the lack of duck-typing with the block parameter. One can
exrapolate other exmaples including the converse situation of accepting
the data but not the block.
def foo( &b )
b.call
end
a = "Quack"
def a.call ; self ; end
foo { "Quack" } #=> "Quack"
foo "Hello" #=> error
So given this, I wonder if it might not be better to get rid of these
special block parameters? Why not have a normal parameter, the last one
in the list, pick up the block? In other words what if
foo { "Quack" }
were ssentially the same as doing:
foo( lambda { "Quack" } )
The difference being just one of convenience. Then simply using
def foo( b )
b.call
end
would work fine. No only does it provide for the polymorphism. But it
aslo allows control over when a block parameter is required or can be
omitted by providing a default (eg. 'foo(b=nil)' or 'foo(b=proc{...})'
). Moreover, it simplifies the syntax a touch too --that's always nice.
Of course we must also ask what happens to #yield and #block_given?. At
first I thought they'd have to be deprecated. But I later realized not.
They could still work just as before. The only new requirement is that
a parameter must always be provided to capture the block. This
requirement on the method interface is more self documenting anyway and
in my experience using a parameter proves to be more useful and
actually faster besides.
Clearly this change is a Ruby 2.0 level change but I think it is worthy
of consideration. What do you think?
T.
parameter can either be a hash (or hash-like object) or a proc. With
the later it is very nice to be able to use a block. But having to
accept both types of object makes it akward b/c of the distinction Ruby
makes between these kinds of parameters, i.e. arg vs. &arg. While this
has occured to me before with regards to default values (becuase blocks
parameters can not have default values) this issue makes the situation
particularly stark. Ruby is working against itself here. While Ruby
promotes duck-typing, in this particular case Ruby prevents it. The
prevention arises, it seems, from the a certain concept of yeild and
block_given? --that which makes a block an option on any method
wahtesoever without regard to the methods definition. While seemingly
convenient, this actually creates constraints that prove to be less
than convenient. After much consideration,I think Ruby is probably
being a little too magical for it's own good here.
Just to be very clear, here is a simple example to demonstrate what I
mean about the lack of duck-typing with the block parameter. One can
exrapolate other exmaples including the converse situation of accepting
the data but not the block.
def foo( &b )
b.call
end
a = "Quack"
def a.call ; self ; end
foo { "Quack" } #=> "Quack"
foo "Hello" #=> error
So given this, I wonder if it might not be better to get rid of these
special block parameters? Why not have a normal parameter, the last one
in the list, pick up the block? In other words what if
foo { "Quack" }
were ssentially the same as doing:
foo( lambda { "Quack" } )
The difference being just one of convenience. Then simply using
def foo( b )
b.call
end
would work fine. No only does it provide for the polymorphism. But it
aslo allows control over when a block parameter is required or can be
omitted by providing a default (eg. 'foo(b=nil)' or 'foo(b=proc{...})'
). Moreover, it simplifies the syntax a touch too --that's always nice.
Of course we must also ask what happens to #yield and #block_given?. At
first I thought they'd have to be deprecated. But I later realized not.
They could still work just as before. The only new requirement is that
a parameter must always be provided to capture the block. This
requirement on the method interface is more self documenting anyway and
in my experience using a parameter proves to be more useful and
actually faster besides.
Clearly this change is a Ruby 2.0 level change but I think it is worthy
of consideration. What do you think?
T.