There was some discussion on using proc to do this, which seems nice and versitle.
obj2 = proc(:==){ |x| obj1.include?(x) }
It might even be extensed to handle mutiple methods.
proc(:==,:not_there?) { |op,x|
case op
when :==
obj1.include?(x)
when :not_there?
!obj1.include?(x)
end
}
T.
This RCR demonstrates a lack of understanding of what duck typing really is. David Black has nicely deconstructed most (if not all) of the flaws behind this, but the quick summary is that duck typing is not a typing system (which this seems to want to introduce) but is rather an approach to programming. Formalising it as something the compiler can deal with is, IMO, a mistake made by novices or theoretical purists who aren't happy with Ruby but can't find anything better. -Austin
Trans, the above implementation does the first example you are talking about very easily:
- map :== to self (a proc)
obj2 = lambda { |x| obj1.include?(x) }.duck(:==)
In your second example, I'd still propose just to use multiple Proc's:
Object.duck(
:== => lambda { |x| obj1.include?(x) },
:not_there => lambda { |x| !obj1.include?(x) }
)
Austin, you are going off on a tangent. You are talking about the method definition. I've never proposed formalizing anything in the code. I have talked about better describing the "duck-type" in the documentation in the method definition, but that is it. What am I formalizing? I'm only talking about adding another method (or two) to better take advantage of the duck-typing that already exists. I'll add a concrete usage example from the core library - Enumerable.grep. And you can describe how you would solve that example.
There is no duck-typing system that already exists. There exists a *typing* system, which you can deploy, if you choose, in a manner which Dave Thomas has described as "duck typing". It's also plausible to say, as Jim Weirich has, that Ruby is a "duck-typed language" -- that is, that Ruby's typing system always has something of the duck-typing ethos about it, whether one considers oneself to have elected to do duck-typing or not.
Having a method called "duck" adds a fixity and rigidity to all of this which does not play well with either the existing typing system or the concept of duck typing. Asking an object to "duck" also does not make sense semantically, in my view.
Furthermore, as I understand it, there is a lot of freedom but also a certain discipline to duck typing. When you ask that an object respond to << , for example, it's because there's at least *something* about << that resonates with what you're asking the object to do. If you can masquerade any old method as << , it seems to me you're actually creating a way to circumvent duck typing, or at least encouraging it to be done in a less disciplined, less semantically integral way.
David Black
I don't really care the the method name is. It doesn't have to be "duck". I called it that because you are making an object that walks like, talks like the duck the the method needs.
You are correct in that this proposal is allowing one to easily circumvent the original intent the method writer had for the arguments. I think there is a lot of power in that compared to the polymorphism of other languages. I see no reason not to take advantage of it. It also gives ruby some polymorphic bragging rights over other languages.
For the opponents to this RCR, what would be your solution to the problem I posed - using #include? instead of #=== for a pattern object you want to give to Enumerable#grep? Manually create an object an new object that mapped #=== to #include?, add another method to Enumerable, use other methods and more code to accomplish the same functionality, or what?
I think the grep example shows exactly how much of a stretch this is. You'd end up with things like:
%w{ a b c }.grep(%w{ a d e }.duck(:===, :include?) # => ["a"]
which I find quite obscure. I would much rather use select, which is designed for this purpose:
%w{ a b c }.select {|x| %w{ a d e }.include?(x) } # => ["a"]
With the fill-in-the-blank functionality provided by iterators like select, there shouldn't really be a need to (in effect) reprogram methods like grep.
Yes, that probably is the better solution for the functionality of the non-block form of Enumerable#grep. But what about the block form?
You don't always have the luxury of having multiple methods doing the same thing with changes in what methods are used. Most classes/modules aren't like Enumerable in this respect.
In general, having the method be written using arguments (or a block) treated as a Proc (#call) or even a lookup (#[]) is the easiest to get flexibility when the argument needs to respond to only one method. But, methods are usually written to directly use the common case objects (i.e. Enumerable#grep was likely written for Regexp objects). And in those cases where it needs multiple methods of an argument, you couldn't easily use Proc (or block).
Eric
It might even be extensed to handle mutiple methods.
T.
This RCR demonstrates a lack of understanding of what duck typing really is. David Black has nicely deconstructed most (if not all) of the flaws behind this, but the quick summary is that duck typing is not a typing system (which this seems to want to introduce) but is rather an approach to programming. Formalising it as something the compiler can deal with is, IMO, a mistake made by novices or theoretical purists who aren't happy with Ruby but can't find anything better. -Austin
Trans, the above implementation does the first example you are talking about very easily:
In your second example, I'd still propose just to use multiple Proc's:
Object.duck(
)Austin, you are going off on a tangent. You are talking about the method definition. I've never proposed formalizing anything in the code. I have talked about better describing the "duck-type" in the documentation in the method definition, but that is it. What am I formalizing? I'm only talking about adding another method (or two) to better take advantage of the duck-typing that already exists. I'll add a concrete usage example from the core library - Enumerable.grep. And you can describe how you would solve that example.
There is no duck-typing system that already exists. There exists a *typing* system, which you can deploy, if you choose, in a manner which Dave Thomas has described as "duck typing". It's also plausible to say, as Jim Weirich has, that Ruby is a "duck-typed language" -- that is, that Ruby's typing system always has something of the duck-typing ethos about it, whether one considers oneself to have elected to do duck-typing or not.
Having a method called "duck" adds a fixity and rigidity to all of this which does not play well with either the existing typing system or the concept of duck typing. Asking an object to "duck" also does not make sense semantically, in my view.
Furthermore, as I understand it, there is a lot of freedom but also a certain discipline to duck typing. When you ask that an object respond to << , for example, it's because there's at least *something* about << that resonates with what you're asking the object to do. If you can masquerade any old method as << , it seems to me you're actually creating a way to circumvent duck typing, or at least encouraging it to be done in a less disciplined, less semantically integral way.
David Black
I don't really care the the method name is. It doesn't have to be "duck". I called it that because you are making an object that walks like, talks like the duck the the method needs.
You are correct in that this proposal is allowing one to easily circumvent the original intent the method writer had for the arguments. I think there is a lot of power in that compared to the polymorphism of other languages. I see no reason not to take advantage of it. It also gives ruby some polymorphic bragging rights over other languages.
For the opponents to this RCR, what would be your solution to the problem I posed - using #include? instead of #=== for a pattern object you want to give to Enumerable#grep? Manually create an object an new object that mapped #=== to #include?, add another method to Enumerable, use other methods and more code to accomplish the same functionality, or what?
I think the grep example shows exactly how much of a stretch this is. You'd end up with things like:
which I find quite obscure. I would much rather use select, which is designed for this purpose:
With the fill-in-the-blank functionality provided by iterators like select, there shouldn't really be a need to (in effect) reprogram methods like grep.
Yes, that probably is the better solution for the functionality of the non-block form of Enumerable#grep. But what about the block form?
You don't always have the luxury of having multiple methods doing the same thing with changes in what methods are used. Most classes/modules aren't like Enumerable in this respect.
In general, having the method be written using arguments (or a block) treated as a Proc (#call) or even a lookup (#[]) is the easiest to get flexibility when the argument needs to respond to only one method. But, methods are usually written to directly use the common case objects (i.e. Enumerable#grep was likely written for Regexp objects). And in those cases where it needs multiple methods of an argument, you couldn't easily use Proc (or block).
Eric