Conflicts between using respond_to? and extending Ruby

T

Trans

Hi--

I recently cam across an interesting conflict between open-uri.rb and
Facets rendition of kernel/metaid.rb. Facets defines a general
extension Kernel#meta, and open-uri defines OpenURI::Meta#meta. open-
uri uses OpenURI::Meta to extend StringIO via singleton. This is all
fine, but then open-uri checks to see if a StringIO object has been
extended by doing:

io.respond_to? :meta

And that's where the problem lies, b/c if you've loaded 'facets/kernel/
metaid' you're going to get a false positive here. Now the best remedy
is open-uri to be more precise:

io.is_a? OpenURI::Meta

That fixes the the problem. But it raises an interesting question.
I've used #respond_to? myself from time to time thinking it was oh, so
duck-type kosher; never realizing that it might clash with general
extensions.

So where lies the fault in this conflict? Are extensions the bad guy,
or is respond_to? really not a good oop concept? Or..?

T.
 
D

David A. Black

Hi --

Hi--

I recently cam across an interesting conflict between open-uri.rb and
Facets rendition of kernel/metaid.rb. Facets defines a general
extension Kernel#meta, and open-uri defines OpenURI::Meta#meta. open-
uri uses OpenURI::Meta to extend StringIO via singleton. This is all
fine, but then open-uri checks to see if a StringIO object has been
extended by doing:

io.respond_to? :meta

And that's where the problem lies, b/c if you've loaded 'facets/kernel/
metaid' you're going to get a false positive here. Now the best remedy
is open-uri to be more precise:

io.is_a? OpenURI::Meta

That fixes the the problem. But it raises an interesting question.
I've used #respond_to? myself from time to time thinking it was oh, so
duck-type kosher; never realizing that it might clash with general
extensions.

So where lies the fault in this conflict? Are extensions the bad guy,
or is respond_to? really not a good oop concept? Or..?

I think this is just the age-old issue about adding methods to
existing classes and hitting conflicts. #respond_to? is relatively
dumb; it can't tell you what the method actually does. I think of it
as an important tool for "soft" duck typing, in contrast with "hard"
duck typing where you just send the object the message.

What does your Kernel#meta do? If it's what's usually called
#singleton_class, you might change it to #singleton_class :) Or
something like that (#metaclass, if you're into that terminology) -- a
little more descriptive and less likely to clash. There's no perfect
solution, though. Using #extend on specific objects, instead of adding
methods to Kernel, could make clashes much less likely, though if you
happened to add #meta to a StringIO object via #extend, you'd still
have the same problem.


David

--
Upcoming training from Ruby Power and Light, LLC:
* Intro to Ruby on Rails, Edison, NJ, October 23-26
* Advancing with Rails, Edison, NJ, November 6-9
Both taught by David A. Black.
See http://www.rubypal.com for more info!
 
T

Trans

Hi --











I think this is just the age-old issue about adding methods to
existing classes and hitting conflicts. #respond_to? is relatively
dumb; it can't tell you what the method actually does. I think of it
as an important tool for "soft" duck typing, in contrast with "hard"
duck typing where you just send the object the message.

That's interesting. It makes me wonder if it's worth "hardening" with
something like:

respond_to?:)meta, OpenURI::Meta)

So that Ruby will check that it would respond to a #meta that's
defined in OpenURI. But yea, really, I agree with you. I never really
realized it before, but respond_to? is pretty weak.
What does your Kernel#meta do? If it's what's usually called
#singleton_class, you might change it to #singleton_class :) Or
something like that (#metaclass, if you're into that terminology) -- a
little more descriptive and less likely to clash.

Sort-of, but it wraps the singleton in a Functor, so you can call
methods against it as if you had opened it up yourself. For example:

class X
meta.attr :x
end

Defines a class attribute.

There's no perfect solution, though. Using #extend on specific objects, instead of adding
methods to Kernel, could make clashes much less likely, though if you
happened to add #meta to a StringIO object via #extend, you'd still
have the same problem.

Indeed.

T.
 
S

Stefan Rusterholz

Trans said:
respond_to?:)meta, OpenURI::Meta)

I'm sorry, but that looks just so wrong to me. Take the case on .each.
You don't test if an object respond_to?:)each, Enumerable), you just
need the .each.
I don't think there's a solution to the problem as you sacrifice one or
the other thing. You can't know by the name of a method whether it does
what you want or not. So either you jump into the cold water and assume
it does or you sacrifice flexibility and test if it's derived from
something you know.

Regards
Stefan
 
R

Rick DeNatale

I think this is just the age-old issue about adding methods to
existing classes and hitting conflicts. #respond_to? is relatively
dumb; it can't tell you what the method actually does. I think of it
as an important tool for "soft" duck typing, in contrast with "hard"
duck typing where you just send the object the message.

Okay, I'm claiming stake to coining what I hope becomes as much of a
meme as duck typing:

http://talklikeaduck.denhaven2.com/articles/2007/10/22/chicken-typing-isnt-duck-typing
 
D

David A. Black

Hi --

Okay, I'm claiming stake to coining what I hope becomes as much of a
meme as duck typing:

http://talklikeaduck.denhaven2.com/articles/2007/10/22/chicken-typing-isnt-duck-typing

Be careful what you wish for :) In any case, I'm glad to have
provided the impetus, if not the name.

What I've always called the soft/hard duck typing distinction isn't
quite the same as what you're calling the chicken/duck distinction,
though, in the sense that I rule is_a? and kind_of? completely out of
bounds as duck typing of any kind. Duck typing, as I understand it
from various writings by, and exchanges with, Dave Thomas, starts
where is_a? leaves off. respond_to? starts to enter the duck-typing
orbit, in the sense that at least it's focused on the object and its
capabilities, rather than its class/module ancestry (and that's the
most decisive line to cross). Since it still falls short of simply
asking the object to do something, I consider it a "soft" form of duck
typing. It's object-driven, but not atomic.


David

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
* Advancing with Rails, Edison, NJ, November 6-9
* Advancing with Rails, Berlin, Germany, November 19-22
* Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.rubypal.com for details!
 
D

David A. Black

Hi --

What I've always called the soft/hard duck typing distinction isn't
quite the same as what you're calling the chicken/duck distinction,
though, in the sense that I rule is_a? and kind_of? completely out of
bounds as duck typing of any kind.

I didn't put that very clearly, since you do too. What I mean is, it's
like this:


Rick:

Chicken-typing
is_a?/kind_of?
respond_to?
Duck-typing
obj.message

David:

Class-checking:
is_a?/kind_of
Soft duck:
respond_to?
Hard duck:
obj.message


or something.


David

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
* Advancing with Rails, Edison, NJ, November 6-9
* Advancing with Rails, Berlin, Germany, November 19-22
* Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.rubypal.com for details!
 
R

Rick DeNatale

What I've always called the soft/hard duck typing distinction isn't
quite the same as what you're calling the chicken/duck distinction,
though, in the sense that I rule is_a? and kind_of? completely out of
bounds as duck typing of any kind. Duck typing, as I understand it
from various writings by, and exchanges with, Dave Thomas, starts
where is_a? leaves off. respond_to? starts to enter the duck-typing
orbit, in the sense that at least it's focused on the object and its
capabilities, rather than its class/module ancestry (and that's the
most decisive line to cross). Since it still falls short of simply
asking the object to do something, I consider it a "soft" form of duck
typing. It's object-driven, but not atomic.

One difference between kind_of? and respond_to? is that it's slightly
more likely that a particular method or methods mean what the chicken
typer expects when using kind_of? than respond_to?, since kind_of? is
testing an implementation relationship, but that's by no means
guaranteed.

The notion of 'type' held by the user of an object is often more
complex and or general than just being in a particular implementation
hierarchy, or responding to a certain set of verbs at the lexical
level. So I don't see so much of a distinction between respond_to?
and kind_of?
 
D

David A. Black

Hi --

One difference between kind_of? and respond_to? is that it's slightly
more likely that a particular method or methods mean what the chicken
typer expects when using kind_of? than respond_to?, since kind_of? is
testing an implementation relationship, but that's by no means
guaranteed.

The notion of 'type' held by the user of an object is often more
complex and or general than just being in a particular implementation
hierarchy, or responding to a certain set of verbs at the lexical
level. So I don't see so much of a distinction between respond_to?
and kind_of?

The distinction I see is proximity to the object. respond_to? is
asking the object about its capabilities, whereas kind_of? is asking
it about its ancestry. So respond_to? is a tighter fit with the object
as it is at a given point in runtime.


David

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
* Advancing with Rails, Edison, NJ, November 6-9
* Advancing with Rails, Berlin, Germany, November 19-22
* Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.rubypal.com for details!
 
A

ara.t.howard

The distinction I see is proximity to the object. respond_to? is
asking the object about its capabilities, whereas kind_of? is asking
it about its ancestry. So respond_to? is a tighter fit with the object
as it is at a given point in runtime.

it all depends - consider the case of trying to tell wether or not a
hash, array, or rbtree is passed to a method. you can't use
'respond_to?("[]")', 'respond_to?("size")', etc. you can sometimes
pick the 'right' method but, other times you cannot and

case obj
when Array
...

is safer and more accurate. i think it really depends on the use
case - i personally use both.

cheers.


a @ http://codeforpeople.com/
 
A

ara.t.howard

Hi--

I recently cam across an interesting conflict between open-uri.rb and
Facets rendition of kernel/metaid.rb. Facets defines a general
extension Kernel#meta, and open-uri defines OpenURI::Meta#meta. open-
uri uses OpenURI::Meta to extend StringIO via singleton. This is all
fine, but then open-uri checks to see if a StringIO object has been
extended by doing:

io.respond_to? :meta

And that's where the problem lies, b/c if you've loaded 'facets/
kernel/
metaid' you're going to get a false positive here. Now the best remedy
is open-uri to be more precise:

io.is_a? OpenURI::Meta

That fixes the the problem. But it raises an interesting question.
I've used #respond_to? myself from time to time thinking it was oh, so
duck-type kosher; never realizing that it might clash with general
extensions.

So where lies the fault in this conflict? Are extensions the bad guy,
or is respond_to? really not a good oop concept? Or..?

T.

respond_to? + arity it sometimes better. other alternatices are to
mark objects with modules

module Marker; end

object.extend Marker

if Marker === object

so you have a more controlled environment - facets could easily use
this approach. btw, this is something pervasives addresses and which
is use quite heavily in meta-programming: for production code i think
it's best not to ask objects if they do 'x' or 'y' using either
'respond_to?' OR come 'is_a?' test, rather you should, if possible,
simply *ensure* that they do. here is an example

cfp:~ > cat a.rb
class BlankSlate
instance_methods.each{|m| undef_method m unless m['__']}
end

bs = BlankSlate.new

Object.instance_method('instance_eval').bind(bs).call{ @a = 42 }

class << bs; attr :a; end

p bs.a #=> 42


cfp:~ > ruby a.rb
42


so, here, we simply *force* the object to 'respond_to?' the method we
want in exactly the way that we want it to. this isn't always an
option but, imho, any general purpose library should at least attempt
this approach - attributes.rb just just this so as to make the
smallest amount of assumptions about an objects type/behavior as
possible.

cheers.

a @ http://codeforpeople.com/
 
D

David A. Black

Hi --

The distinction I see is proximity to the object. respond_to? is
asking the object about its capabilities, whereas kind_of? is asking
it about its ancestry. So respond_to? is a tighter fit with the object
as it is at a given point in runtime.

it all depends - consider the case of trying to tell wether or not a hash,
array, or rbtree is passed to a method. you can't use 'respond_to?("[]")',
'respond_to?("size")', etc. you can sometimes pick the 'right' method but,
other times you cannot and

I don't think there even is a right method for this purpose; I don't
think respond_to? ever enters into the picture when you want to know
the class of an object. It doesn't convey that information.
case obj
when Array
...

is safer and more accurate. i think it really depends on the use case - i
personally use both.

It does indeed depend; they do totally different things. I was
describing the differences, specifically in the context of duck typing
(or alternatives to duck typing): respond_to? gives you information
about an object at a given moment, and kind_of? tells you about its
ancestry.


David

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
* Advancing with Rails, Edison, NJ, November 6-9
* Advancing with Rails, Berlin, Germany, November 19-22
* Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.rubypal.com for details!
 
A

ara.t.howard

It does indeed depend; they do totally different things.

not entirely - they both allowing pre-testing to see if code is going
to work or explode...
I was
describing the differences, specifically in the context of duck typing
(or alternatives to duck typing): respond_to? gives you information
about an object at a given moment, and kind_of? tells you about its
ancestry.

well sortof:

OpenStruct.new.respond_to?:)foo) #=> false

OpenStruct.new.foo() #=> nil

as i said, i think it's 100% situational and you really can't make
blanket rules.

cheers.


a @ http://codeforpeople.com/
 
R

Rick DeNatale

Trans posted a reply to my article saying that I was being too hard on
is_a?/kind_of? I responded there but thought that I should repeat
what I said here:

Trans said:
I think you're a little too hard on is_a?/kind_of? though. I don't
think they fit the "chicken" typing character quite as well. Yes, they
aren't 100% in a dynamic language such as Ruby's, however they are
much much more dependable than respond_to? b/c modules and class
intend to represent an encapsulation of behavior. If we ask 'is_a?
Enumerable', we can be pretty sure that we are working with something
that responds to #select or what have you as the way we'd expect.

My reply:
True enough, but I wouldn't say much more dependable. Even within an
implementation hierarchy, the signature and even the meaning of a
method can change. Consider, for example how the details of the each
method vary depending on whether the enumerable is, say, a Hash, vs.
an Array. You're typically expecting certain things to be yielded to
the block by each, and neither kind_of? or respond_to? helps predict
either the arity for the block expected, or what will be yielded.

And the flip side argument against chicken typing with kind_of? is the
false negative problem. There are interesting cases where unrelated
classes implement similar methods or families of methods.

And sometimes the method similarity can be complex, making determining
substitutability difficult. Consider how many classes implement some
form of [], and how many variations of parameters there are affecting
the semantics, even within the same class.

While some of the chicken typing persuasion might look at this as a
mess needing to be cleaned up, duck typers see it as the powerful
flexibility that gives Ruby it's agility when coupled with the right
approach and tools.
 
D

David A. Black

Hi --

not entirely - they both allowing pre-testing to see if code is going to work
or explode...

Pre-testing is what you do, not what the method does :)
well sortof:

OpenStruct.new.respond_to?:)foo) #=> false

OpenStruct.new.foo() #=> nil

You're a hard task-master :) OK, I'll try again:

respond_to?:)x) gives you information about an object at a given
moment -- namely, whether or not any of the classes or modules
currently in an object's method lookup-path has a method "x" defined
(including the object's singleton class).

kind_of?(m) tells you about an object's ancestry -- namely, whether or
not a class or module called m is among its ancestral classes and
modules.

And yes, I know you can do:

s = "hi"
def s.respond_to?(x)
true
end

and I think people have sometimes even advocated this for OpenStructs.
But the above is as watertight as I can get :)
as i said, i think it's 100% situational and you really can't make blanket
rules.

I think we're talking at cross purposes; I wasn't suggesting rules,
blanket or otherwise, just commenting on the difference(s) between
respond_to? and kind_of?


David

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
* Advancing with Rails, Edison, NJ, November 6-9
* Advancing with Rails, Berlin, Germany, November 19-22
* Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.rubypal.com for details!
 
T

Trans

should be

if CanQuack === donald

That's interesting. I've aliased #include as #is, and #extend as #can.
I should add #can? as well, then:

if donald.can? CanQuack

Or just using Quack:

if donald.can? Quack

T.
 
R

Rick DeNatale

should be

if CanQuack === donald

Which is functionally equivalent to
donald.is_a? CanQuack

it might read better, but I still maintain that checking with is_a? is
still weaker than most folks assume.
 
A

ara.t.howard

Which is functionally equivalent to
donald.is_a? CanQuack

it might read better, but I still maintain that checking with is_a? is
still weaker than most folks assume.

as i was mentioning to david, my experience is that it just depends:
if you are writing something like

case conn
when TCPSocket
when UDPSocket
end

then is_a? is probably pretty strong - as strong as it possible in
ruby since we can always

def class() Lie end

nevertheless my general rule tends to be along the lines of using
class/module/is_a? type checks for built-ins since people who muck
that too much get what they deserve if those classes stop working,
using 'respond_to?' to keep apis flexible (require as little as
possible from client code), and using something like
Object.instance_method:)instance-_eval).bind(object).call(*a, &b)
when trying to write robust meta-programming type stuff like adding
methods to object since i want to *force* compliance iff possible.

this whole thread is pretty interesting though - it shows how
flexible we as programmers have to be to accommodate the openness
ruby. i think some people would point out this as a weakness because
we have to think and talk about these things but, in reality, it's
only an issue in pretty sticky situations - situations i personally
don't attempt to get myself in using less powerful languages.

the language choice does indeed change the way we think about
problems and, as such, cannot truly be equivalent for a given task
when compared to other languages - contrary to what turing would tell
us ;-)

cheers.

a @ http://codeforpeople.com/
 
D

David A. Black

Hi --

this whole thread is pretty interesting though - it shows how flexible we as
programmers have to be to accommodate the openness ruby. i think some people
would point out this as a weakness because we have to think and talk about
these things but, in reality, it's only an issue in pretty sticky situations
- situations i personally don't attempt to get myself in using less powerful
languages.

the language choice does indeed change the way we think about problems and,
as such, cannot truly be equivalent for a given task when compared to other
languages - contrary to what turing would tell us ;-)

I've always thought that the situation with programming languages is a
lot like that with musical instruments: they (languages or
instruments) all do the same thing (implement algorithms or make
music), but there's no denying, in either case, that different ones
have very different properties and provide very different experiences.


David

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
* Advancing with Rails, Edison, NJ, November 6-9
* Advancing with Rails, Berlin, Germany, November 19-22
* Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.rubypal.com for details!
 
A

ara.t.howard

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,533
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top