"Markus" <markus@reality.com> schrieb im Newsbeitrag
news:1097680148.21256.85.camel@lapdog.reality.com...
> I see we have a quite different understanding of Duck Typing. IMHO
with
> Duck Typing you just invoke a method and get bitten by the
NoMethodError
> if it's not there. After all, what do you want to do if you discover
that
> an instance does not support a method you expect it to? Through
testing
> you ensure that the programm is well behaved. And I think, my
> understanding is close on what Dave and others say.
Sure, if you had only one trick in your trick bag, you would just
call it and hope/expect it to work. That's the old "never test for an
error condition you don't know how to handle" rule. But if (as in the
case in question) you have multiple ways to do what you are trying to
do, some of them appropriate to some kinds of values, some appropriate
to others, you'd be nuts to just use the one and hope the other cases
never arose.
Instead, you'd either 1) test for method signatures with
responds_to? or 2) implement the most common case and then rescue
NoMethodError and try the rare cases. The first is (IMHO) was cleaner
but I have seen cases where the second was used effectively.
You are rigth: this seems to be an application of DT indeed. Although I
have to admit, that I find the one trick situation a much more elegant
application of DT than the multiple trick situation you describe. In
those cases I prefer to switch to a type mapping based approach (although
that has it's drawbacks in the light of singleton methods) like I
demonstrated in another posting (basically, create a HashMap with classes
as keys and lambdas as values).
> > > Now, while this is certainly a good idea for methods like to_s,
to_i
> etc.
> > > it's a bad idea for functionality that is special to a part of
your
> > > application. For example, if you had a class Foo and defined
methods
> > > String#to_foo and Fixnum#to_foo etc. that might come in handy for
a
> > > certain lib or module and a lot of libraries do this, class
interfaces
> of
> > > standard classes get cluttered with methods totally specific to
> certain
> > > parts of the application. Also the likeliness of name clashes
> increases.
> >
> > This is another thing that is not quite duck typing.
>
> Clearly, as I was not talking about Duck Typing here but instead about
> certain design rationales independent of the typing model.
So here is a language that gives you many workable ways to
accomplish a reasonable goal, but none of them are usable because they
every one of them violates some design principle or an other? Is it
possible that the set of design principles you are trying to employ is a
tad too restrictive?
That may be, but please note that I didn't ban the "modify std class"
approach for all cases. I said that this should be done with care for
libs and larger apps.
If I want to write a polymorphic routine, but am not supposed to
test the class (since it provides no guarantee of behavour) or the
method signature, am not allowed to extend the core classes or sub class
them, how pray tell is it to be done?
See above for an example. However, it's difficult to discuss this without
a concrete example.
If the behavior is specific to the application (and added by the
application) it can as well be encapsulated within the application. To
a first approximation, this will be the case simply because the code
which extends them lives in the application.
Just note, that I explicitely mentioned large applications and libraries.
If you aren't using it, it
isn't there. (Though looking back, I see that several of your points
seem to assume that this is not the case--e.g., the documentation
point.) If this is still worrisome, you can extend the interface only
of objects turned over to (or created by) your application. You can
even (if you really feel the need to go this far) remove them from any
objects you export.
In that case, you can as well use another class internally (possibly by
employing delegation).
As for the name space issues, you can, if you like,
package your extensions in a companion object, "under-write" them (with
method missing, use reflection to detect and report collisions before
they occur, etc.)
Hm... I prefer a simpler solution. After all, what would you do it you
had libA and libB which both add method String#foo and which both are able
to detect the name clash and report it? You'll most likely get an
exception and can't use libA and libB together. Of course, those libs
could be written to automatically choose appropriate names, possibly even
with dynamic generated prefix. But this likely becomes unmanageable fast.
All of these precautions can be neatly encapsulated themselves, so
you don't even need to mess with them while you're working on your code.
It really does seem to me that this is a "rule" rooted more in the
limitations of other languages than abstract software design principles
and not a good match for ruby.
I don't think so. Name clashes and building proper components with clean
and consistent interfaces (i.e. interfaces that can be used by humans who
have to understand them) are not restricted to particular programming
languages and I think in fact are quite fundamental to software
engineering.
There are too many good ways to deal
with the potential problems to write the whole technique off with an
"almost never" prohibition.
As you might have guessed, I don't regard the ways to cope with name
clashes of auxiliary methods in std classes as good as you do.
But
that's a personal judgement and we're all free to differ here.
For my part, I am not saying it is _always_ bad to extend standard
classes, but (if done judiciously) it can be a very useful technique,
I couldn't agree more. (Ooops, something wrong here? :-))
and is no more dangerous than any other language feature of similar
power and generality.
I leave that judgement for another thread. 
Thanks for taking the time to go through all this! I'm sorry that I'm so
stubborn about things that I'm convinced of.
Kind regards
robert