From: dblack@... Date: 2003-11-07T06:51:05+09:00 Subject: Re: Managing metadata about attribute types Hi -- On Fri, 7 Nov 2003, Ryan Pavlik wrote: > On Thu, 6 Nov 2003 21:57:15 +0900 > dblack@wobblini.net wrote: > > > > > This is the fundamental philosophical disagreement, or > > > miscommunication, or what have you. If an object fits the bill, and > > > its class/ancestry is wrong, then there is a error in design. > > > It should not be the case that this happens, or you have found an > > > error in your code. > > > > At this point you're waging a battle directly against the design of > > Ruby. Ruby allows you to extend objects at runtime; to decide that > > this is sloppy or wrong or a second-rate programming technique is > > entirely arbitrary. > > Not at all. The fact you _can_ do something doesn't mean you must do > it all over the place. The fact you _can_ extend objects has no > bearing on what the fact your class hierarchy documents the behavioral > pattern well, either. My point was that it was not, ipso facto, a program design error to pass to a method an object which does what it should but doesn't have a class name drawn from a particular pre-existing list. There's no reason to decide up front that doing such a thing in Ruby is wrong or bad. > > When you check whether or not an object's response to #is_a? includes > > an element you've specified, that's the one and only thing you're > > checking. It's not as if Ruby somehow pulls up its socks and > > straightens its tie and says "Better stop this dynamic stuff!" when it > > sees a call to #is_a? It doesn't; it remains dynamic, and the > > programming techniques required to ascertain the interface of an > > object do not change. (Besides, its socks and tie were just fine to > > start with :-) > > You seem to have the preconception that #is_a? and "this dynamic > stuff" are mutually exclusive in some way. This is not the case. The > fact you're asking #is_a? just means you're asking if at some point it > had a parent that was related to this class. Right -- exactly. And since objects in Ruby can be extended dynamically, that question (#is_a?) has no necessary relation to what you really need to know about the object (its type/behavior/ interface). What I'm suggesting is that pressing #is_a? into service as a "type" checker doesn't take the dynamism into account. #is_a?-style information isn't updated when an object's type changes. > * When writing code, you will never specifically want a type you > do not know about. But I will want anonymous types, like: c = CGI.new c.extend(MyCGIModule) def c.another_method; ...; end The *class* of c is CGI, and the module/class *ancestry* of c is [MyCGIModule,CGI,Object,Kernel] (or something), but the *type* of c, Ruby being Ruby, is "the type which is the type of objects which have c's type". And that's just fine; there's no need for me to have a name for the type (since it's not encapsulated anywhere except in the interface of c anyway), as long as I design, test, and use c in a sensible manner. I only needed the name of a class to bootstrap the object, and the name of a module to modify it. Then type takes over. > * When using the code later, you can provide a specific subclass > unknown to the original code. > > * Thus, when type checking, you are not limited in any manner, > because you are asking for what you want (generally), and > getting it (specifically). I haven't seen any type checking in what you're describing, only class name and ancestry checking. > > Also, remember that you're never 100% assured that #[] or any other > > method means what you want it to. It's ducks all the way down :-) > > (http://www.the-funneled-web.com/hawking.htm) Every method call > > operates under the same conditions as every other. You can light a > > candle, dance a jig, call #is_a? twenty times... but in the end, > > obj#[] is whatever obj#[] is. You can't change Ruby for a few > > nanoseconds at a time through sheer willpower. > > This is only correct when blindly assuming that if #[] exists, it must > act like you want. Having the class/module tie gives you a semantic > that further assures you it _does_ act like you want. As always, that depends on (a) the non-existence of the little code-changing gremlins we all try to anticipate :-) and (b) testing and robust design. I'm not saying there's no way to achieve those things, only that calling #is_a? habitually is not a specially privileged or comprehensive way of doing so, nor, in my opinion, very closely tailored to the problem. > This can, of course, be broken. Many things can be broken in ruby > though, but it is not desirable to do so. > > > Hence the quest to harness the dynamism, rather than wishfully think > > that it comes and goes. > > There is no lack of dynamicism here. Nor does type checking make the > ability to extend classes on the fly go away or become less useful. > I rely heavily on the strongtyping module in Mephle; I also do some > modification to many base classes. Just because something is a > singleton, does not mean it's also not of the original class. But it does mean that its type is not documented by the original class. (Which may or may not matter.) > Have another look :-) It's more like "class name checking isn't 'type checking' to begin with, and all it does is a kind of stylistic imitation of static typing". Or, if you prefer, a stylistic imitation of dynamic type checking in a language where an object's type is immutably connected to its class. I only want to add that I'm not doctrinaire about the #is_a? method, nor campaigning to get people never to use it. Introspection, like dynamic extension of objects, is a cool part of Ruby :-) My main goal here is to keep alive the important distinction between class/module hierarchy and type in Ruby. David -- David Alan Black home: dblack@wobblini.net # New email address work: blackdav@shu.edu Web: http://pirate.shu.edu/~blackdav David -- David Alan Black home: dblack@wobblini.net # New email address work: blackdav@shu.edu Web: http://pirate.shu.edu/~blackdav