From: Austin Ziegler Date: 2002-10-29T00:46:21+09:00 Subject: Re: Inheritance Problem in Dynamic/Typeless Language On Mon, 28 Oct 2002 23:49:39 +0900, William Djaja Tjokroaminata wrote: > Jim Weirich wrote: >> The problem is retraining class writers (myself included) to do >> it the right way. > I don't think retraining will solve the vast existence of codes > that have been written in the "old" way, including the basic Ruby > built-in classes themselves. That's why I am very interested > whether from OO design point of view, the current design is > "flawed". (I think OO has been around for a long time, so it is > hard to believe that this kind of problem is not > encountered/solved before.) I think it is flawed. Personally. >> This problem has little to do with static vs dynamic typing and >> can easily occur in C++ programs. > > Well, it may occur in C++ programs, but it is not the intention. > Suppose > > derived a; > parent b; > parent c; > .... > a = b + c; > > Assuming that this code compiles and executes, here we are > guaranteed that the class of a is "derived" (i.e., a will respond > to methods that are defined for class derived). There may be some > semantic/logic error depending on the overloadings of the '+' and > '=' operators, but that is a separate issue. This is where Ruby's typeless variables (not typeless objects) causes problems. In the compiled language, the variable 'a' has a distinct type. With respect to your example, I would *expect* that 'a' would take on the type of Parent in Ruby. What I don't expect, however, is for: a = a + b to take on the type of Parent. After all, we're really doing: a = a.+(b) So the typeness of a should be carried, even though it's the Parent's operator which is called. It's rather like the operator had been declared without 'virtual' in C++. Matters are made rather worse because there's no clear way of doing typecasting (yes, there is 'coerce', but that's not really typecasting) of objects. Additionally, because the variables themselves are typeless, doing: a = b + a # a = b.+(a) Will result in a being a reference to a Parent, even though in C++, the result would remain a Derived because types are associated with variables. Jim's solution (self.class.new) works quite well for the first case (a += b), but it works not at all for the second case (a = b + a). It's correct, and it's consistent, but it still *feels* wrong. (There's a point where, at least IMO, if you're dealing with Parent and Derived and only those two classes are involved, then the results should be coerced into Derived. This, however, results in problems if you have DerivedA and DerivedB, both children of Parent. Which class should then be used as the result?) It's not an easy problem. Jim's solution is a decent one, and it might be that some syntactic sugar could be provided. If I do: class Foo def bar Foo.new end end it could be interpreted as: class Foo def bar self.class.new end end because we are in the context of "class Foo". I'm not sure if this would be a good idea or not, but it would at least make Jim's solution 'automatic.' -austin -- Austin Ziegler, austin@halostatue.ca on 2002.10.28 at 09.56.17