johnson@cs.uiuc.EDU (Ralph Johnson) (11/18/90)
In article <1990Nov16.065609.15460@tukki.jyu.fi>, sakkinen@tukki.jyu.fi (Markku Sakkinen) writes: |> In my opinion, inheriting only parts of superclass, say C, |> into a subclass, say D, is a highly dubious idea even for this purpose. |> One should rather have defined a fully-fledged class B containing |> those parts first, then both C and D as subclasses of B. |> It would be nice to have the kind of generalisation facilities |> that Claus Pedersen suggested in his OOPSLA'89 paper: |> that one could derive _super_classes approximately as easily |> as existing languages allow us to derive _sub_classes. Before I start agreeing with Markku (which is always boring) let me disagree a little. When you are prototyping, you often care more about the behavior of a program than its structure. Thus, prototypers want to get something working quickly, and don't care what it looks like. However, the kind of program resulting from prototyping this way should never be mistaken for elegant programs. I rewrite code that results from prototyping to make it elegant, and the rewriting often splits up classes just the way Markku says. I think that the conflict between getting something to work quickly and making it elegant could be lessened with better programming environment support. We need tools that would split up classes and derive new super classes from exisiting classes. Following the Scandianvian tradition, a program provides a model of some system. When you find that you need to reuse just part of a class then it means that your model was wrong. Instead of patching up the code, you should fix your model. Sometimes people argue against this point of view by saying that it isn't possible to revise the class hierarchy because the source code is not available, or they will say that this is going against reusable software because instead of reusing a class we are revising a class. Naturally, I disagree strongly with these points of view. The first point is just a good reason why source should always be avaliable, and the second shows that wrong definitions of software reuse are being applied. If you believe that the main purpose of a program is as a model of a system, and that it is just as important for a program to be a way of communicating between people as it is for it to be a way of communicating with machines, then changing the model is absolutely necessary when it is shown to be inadequate. Ralph Johnson -- University of Illinois at Urbana-Champaign
brucec@phoebus.labs.tek.com (Bruce Cohen;;50-662;LP=A;) (11/20/90)
> In article <1990Nov16.065609.15460@tukki.jyu.fi>, sakkinen@tukki.jyu.fi (Markku Sakkinen) writes: > > In my opinion, inheriting only parts of superclass, say C, > into a subclass, say D, is a highly dubious idea even for this purpose. > One should rather have defined a fully-fledged class B containing > those parts first, then both C and D as subclasses of B. > It would be nice to have the kind of generalisation facilities > that Claus Pedersen suggested in his OOPSLA'89 paper: > that one could derive _super_classes approximately as easily > as existing languages allow us to derive _sub_classes. > and in article <1990Nov17.174653.6291@ux1.cso.uiuc.edu> johnson@cs.uiuc.EDU (Ralph Johnson) writes: > > However, the kind of program resulting from prototyping this way should > never be mistaken for elegant programs. I rewrite code that results > from prototyping to make it elegant, and the rewriting often splits up > classes just the way Markku says. > I've recently started looking at dealing with this problem with what I call "behaviours", which are lightweight abstract classes which each incorporate the interface to one responsibility for its subclasses. Behaviours are completely disjoint in terms of interface and implementation; they may be composed into cooperating sets of behaviours, but they may not share parts of their interfaces or implementations. A given subclass will inherit from as many behavior superclasses as necessary for all of its responsibilities, in mixin style. No subclass may refuse to inherit a part of one of its superclasses (with careful design of the superclasses, there aren't any parts to object to; you either want the whole class or none of it). This style makes it easy to factor inheritance so that everything needed by a subclass is there, but the subclass doesn't get weighed down with things it doesn't need. It also makes it easy to rearrange inheritance without major surgery on a program; since the concrete subclasses largely consist of compositions of behaviours, most changes are a matter of altering the composition and removing or adding the private methods which connect the behaviors in the subclass. > I think that the conflict between getting something to work quickly and > making it elegant could be lessened with better programming environment > support. We need tools that would split up classes and derive new > super classes from exisiting classes. Tools like that would certainly be useful, especially in the case Ralph cites of trying to clean up a bloated prototype. I would like even more to have tools which allow me to build the original version in a more cleanly way, so I don't have to spend so much time cleaning up a program which already works. > Following the Scandianvian tradition, a program provides a model of > some system. When you find that you need to reuse just part of a class > then it means that your model was wrong. Instead of patching up the > code, you should fix your model. I favor making the unit of reuse very small. The smaller it is, the less of the reused object (class, code, or design) is likely to be unneeded in the reusing software. That's why I think the unit should be a part of a class; we just need to use tools which that convenient, and which don't encourage us to muddy the inheritance structure by ad hoc, and in a sense ex post facto, changes to the structure the is inherited. -- ------------------------------------------------------------------------ Speaker-to-managers, aka Bruce Cohen, Computer Research Lab email: brucec@tekchips.labs.tek.com Tektronix Laboratories, Tektronix, Inc. phone: (503)627-5241 M/S 50-662, P.O. Box 500, Beaverton, OR 97077
wdavis@x102c.harris-atd.com (davis william 26373) (11/21/90)
In article <1990Nov17.174653.6291@ux1.cso.uiuc.edu> johnson@cs.uiuc.EDU (Ralph Johnson) writes: > >Following the Scandianvian tradition, a program provides a model of >some system. When you find that you need to reuse just part of a class >then it means that your model was wrong. Instead of patching up the >code, you should fix your model. I do not agree that "the model was wrong". After you find that you "want to reuse" part of a class (not "need to resue" - there are always alternatives), how does that make what went before "wrong". Does the program you want to reuse parts of no longer work? Does it fail to perform its function in some way, now that you want to reuse part of it? If I have a single linked list implementation and find that I want to reuse parts of it (the link manipulation parts) in a double linked list, how does that make it any less "right" as a single linked list? If you find that the original model "was wrong" it must be because the model "was" not correct for the original problem or "is" not correct for what the original problem is now known to be. If you find the original model "is not correct for a new problem", then that is a different matter. In terms of software reuse, the "is vs. was" of "model wrong" is important because it determines what portions are to be reused and what portions can be easily reused. How does one draw the line between "new problem" and "new understanding of old problem"? I think that is the heart of the matter concerning ease of software reuse. > >Sometimes people argue against this point of view by saying that >it isn't possible to revise the class hierarchy because the source >code is not available, or they will say that this is going against >reusable software because instead of reusing a class we are revising >a class. Naturally, I disagree strongly with these points of view. I disagree with the first because that is just a language specific limitation. In theory, why can't object modules come with sufficient information to provide for "reuse". Indeed, if an object module can be used "only once", then how do we build multiple programs from it. Linking is only a small, albeit important, amount of reuse. The linker question has been described sufficiently in other postings but I have not seen a good solution proposed yet. Is there one that someone has already researched? >The first point is just a good reason why source should always be >avaliable, The first is also a good reason why more information is needed in an object module. Why should I be forced to go back to source to reuse things? Even when the source is available, why recompile? >and the second shows that wrong definitions of software >reuse are being applied. I agree. > If you believe that the main purpose of a >program is as a model of a system, and that it is just as important >for a program to be a way of communicating between people as it is >for it to be a way of communicating with machines, then changing the >model is absolutely necessary when it is shown to be inadequate. I agree the main purpose of a program is as a model of a system. (Actually a program is a model of a design and a design is a model of a system - different types of models). But the program exists because the model serves some purpose (achieves some result). So, the reason for the model determines the detail and biases in the model. Thus, there can be two different models of the same system for two different purposes. Neither is inherently right or wrong - the correct new of the model depends on the reason for the model. I agree it is important (maybe just as) for a program to be a way of communicating between people. But, as I have indicated already, I do not agree that the model must be changed. Indeed, I would say a new model is necessary when a given model is shown to be inadequate in a new domain. Then there will be multiple models in different domains. I think the big question of reuse is: How does one build a model in a way that allows maximum reuse of the parts of the model? This has large implications when you consider that a program and a design are both models. > >Ralph Johnson -- University of Illinois at Urbana-Champaign Bill Davis Harris GISD wdavis@x102c.ess.harris.com Disclaimer: I am not an official. So, these are not official views of any person or entity.
johnson@m.cs.uiuc.edu (11/25/90)
I said: > >Following the Scandianvian tradition, a program provides a model of >some system. When you find that you need to reuse just part of a class >then it means that your model was wrong. Instead of patching up the >code, you should fix your model. Bill Davis (wdavis@x102c.ess.harris.com) said: >I do not agree that "the model was wrong". After you find that you >"want to reuse" part of a class (not "need to resue" - there are always >alternatives), how does that make what went before "wrong". Does >the program you want to reuse parts of no longer work? Does it >fail to perform its function in some way, now that you want to reuse >part of it? Most of the time when I am programming, I am trying to build reusable software. I am trying to describe an entire problem domain, and I expect that the classes that I design will work for any problem in that domain. Thus, the model was wrong because it did not work for a particular member of the domain. A set of classes is like a scientific theory. The individual programs that you build out of these classes are the experiments that test the theory. If the programs require all sorts of weird work-arounds and hacks to work then the theory starts to look like Ptolemaic astronomy looks today. Of course, Ptolemaic astronomy seemed pretty reasonable to astronomers before Copernicus, and we often stick with an outmoded set of classes. Sometimes this is just because it is what we know. Sometimes it is because we invented it. Sometimes it is because we have lots of code that uses it, and it would be too expensive to change. As time goes on, we learn more and more about how we should have designed the classes, and eventually it is worth the price to change. A perfect example is Model/View/Controller. It was the first user interface framework, and every succeeding framework has owed a lot to it. However, it is now a decade old, and is definitely showing its age. Thus, version 4.0 of Smalltalk from ParcPlace has a new version of Model/View/Controller that seems (from the little that I have looked at it) to be a big improvement. It should be easier to learn, it should be easier to customize, and it should be easier to use as a foundation for more reusable components. On the other hand, there is a cost to converting over, both to ParcPlace and to their customers. >If you find that the original model "was wrong" it must be because >the model "was" not correct for the original problem or "is" not >correct for what the original problem is now known to be. Usually the latter. My understanding of a problem improves the longer I work on it. Ralph Johnson -- University of Illinois at Urbana-Champaign