Is Inheritance a Pillar of OO?
started 3/12/2003; 9:50:08 AM - last post 3/18/2003; 10:36:51 AM
|
|
Dan Shappir - Is Inheritance a Pillar of OO?
3/12/2003; 9:50:08 AM (reads: 3970, responses: 49)
|
|
Is Inheritance a Pillar of OO? |
An interesting, or at least amusing, discussion about inheritance and its importance to OOP
In my (limited) experience, nobody at a university has any clue as to what OOP really is about. In one "advanced" Java class, the professor once said that he had never been able to find a purpose for inheritance and that it would be best not to use it...
Posted to OOP by Dan Shappir on 3/12/03; 9:50:56 AM
|
|
|
|
Reilly Hayes - Re: Is Inheritance a Pillar of OO?
3/12/2003; 10:20:36 AM (reads: 2826, responses: 3)
|
|
In my (limited) experience, nobody at a university has any clue as to what OOP really is about.
OO is much too young for the theoretical framework to be solid. The apparent lack of "clue" in academia is a a result of the fact that the field is still fluid. Consider the still-open issue of message passing vs. generic functions. Nobody can answer the question "what is and is not OO?".
Inheritance of implementation is grossly overrated. Inheritance of interface is useful in a variety of ways, including as an aid to polymorphism (particularly in a non-inferred statically typed environment). This conversation seems to be about inheritance of implementation. While I can't entirely agree with the "Java Professor", he probably did the entire class a service with his statement. The developers who care most about inheritance inevitably write the hardest to maintain code. Too much knowledge ends up being embedded in the class structure.
|
|
Ehud Lamm - Re: Is Inheritance a Pillar of OO?
3/12/2003; 10:42:14 AM (reads: 2863, responses: 2)
|
|
I'll comment about OOP theory later, but let me just add that I am much more afraid of people that think they know why inheritance is great than of people who confess they still haven't found valid uses.
|
|
Brian Hurt - Re: Is Inheritance a Pillar of OO?
3/12/2003; 11:00:47 AM (reads: 2817, responses: 0)
|
|
Why inheritance of implementation is important: code sharing. If two classes have implementations in common, they should probably have a common superclass, where that common implementation actually resides.
Snarky response: I can see why an academic professor would never see a need to share code.
I fear people who like composition. The gravest sin of OO programming is confusing 'is a' and 'has a' relationships. But composition encourages you to munge those concepts.
Note that strict inheritance requires you to either have a perfect design from the get-go (so that you never end up with two classes with similiar implementations but no common ancestors) or that you be able to refactor your class structures occassionally. Personally, I don't think refactoring is that awful a thing, myself.
|
|
Ed Heil - Re: Is Inheritance a Pillar of OO?
3/12/2003; 11:04:35 AM (reads: 2785, responses: 0)
|
|
I thought that "Object Oriented" when you boil it down really meant "resembling Smalltalk in some way"....
Never mind that most modern OO languages do not share Smalltalk's original goals...
|
|
Toby Reyelts - Re: Is Inheritance a Pillar of OO?
3/12/2003; 11:37:48 AM (reads: 2857, responses: 1)
|
|
I'll comment about OOP theory later, but let me just add that I am much more afraid of people that think they know why inheritance is great than of people who confess they still haven't found valid uses.
Are you trolling again Ehud?
Inheritance is the key to separation of interface and implementation, and hence polymorphism, in a statically typed OO language. This is perhaps the primary facet which separates languages like Java from "object-based" languages like VB.
Frankly, I don't know how projects of any significant size are accomplished using dynamically-typed languages, with their lack of interface inheritance.
|
|
Luke Gorrie - Re: Is Inheritance a Pillar of OO?
3/12/2003; 11:48:18 AM (reads: 2766, responses: 1)
|
|
I was about to make a snide comment along the lines of "How would you write a GUI toolkit in Java without using inheritance? Without subclassing you would need to add a hook interface for every imaginable behaviour of every component!"
Then I started to remember how Swing is written :-)
|
|
Toby Reyelts - Re: Is Inheritance a Pillar of OO?
3/12/2003; 12:17:31 PM (reads: 2798, responses: 0)
|
|
Then I started to remember how Swing is written :-)
Can you elaborate? I've written windowing code for OS/2 (PM), Windows (32-bit Windows API, MFC), Smalltalk (Squeak), and Java (AWT, Swing). I've been by far the most impressed with Swing. I find it very flexible and useable (Example, create a tree with animated items that lazily loads from the database - trivial). Certainly the pluggable, MVC approach of Swing is orders of magnitude better than the deep inheritance hierarchy nightmare that is MFC.
|
|
Neel Krishnaswami - Re: Is Inheritance a Pillar of OO?
3/12/2003; 12:44:17 PM (reads: 2721, responses: 0)
|
|
Luke: you can use first-class functions to add behaviors to widget instances. (I assume you know this?) I greatly prefer this style, because it keeps the class hierarchy smaller and more comprehensible. When you combine it with a small custom DSL to specify layout (like Dylan's DUIM) you can make writing GUIs very fast.
|
|
Ehud Lamm - Re: Is Inheritance a Pillar of OO?
3/12/2003; 1:01:42 PM (reads: 2841, responses: 0)
|
|
Of othe uses of inheritance, interface inheritance is indeed the easiest to endorse.
I wasn't trolling, by the way.
|
|
Patrick Logan - Re: Is Inheritance a Pillar of OO?
3/12/2003; 2:18:49 PM (reads: 2662, responses: 0)
|
|
you can use first-class functions to add behaviors to widget instances
Sure. For example a button could be given a closure to execute whenever it is clicked.
In Smalltalk...
someButton action:
[ :button |
Transcript show:
'The button was clicked...' + button asString ]
This is similar to adding an anonymous Listener in Java's Swing.
|
|
Isaac Gouy - Re: Is Inheritance a Pillar of OO?
3/12/2003; 2:33:31 PM (reads: 2660, responses: 0)
|
|
Frankly, I don't know how projects of any significant size are accomplished using dynamically-typed languages, with their lack of interface inheritance.
And yet, there are large Smalltalk systems chugging-away in investment banks, and manufacturers, and...
(And you can implement interfaces in Smalltalk, if it's pleasing to you)
I'm unrepentant - let me have that old-time implementation inheritance ;-)
|
|
Toby Reyelts - Re: Is Inheritance a Pillar of OO?
3/12/2003; 8:25:49 PM (reads: 2572, responses: 0)
|
|
Isaac wrote:
And yet, there are large Smalltalk systems chugging-away in investment banks, and manufacturers, and...
I'll try not to make this another static vs dynamic typing war. I've written in both Smalltalk and Lisp before. I quite seriously don't understand how large systems are written with dynamically typed languages. How do you separate interface/specification from implementation?
As an example in the large, Sun is able to publish Java class libraries which are solely specifications. This allows engineers to develop entirely against an interface, and stick in any conforming implementation as desired. This same process of specification applies in the small too. Interfaces enforce specifications and implementations across team boundaries. How does this work in a dynamic language? (Are there never projects that span a single small team of people? For example, my last project was with a group of 30 engineers spread across several teams - more the rule than the exception). From what I've seen, developers who work in dynamically typed languages depend upon the ability to look at the source code of the implementation they are using to be able to discern the appropriate "interfaces" to implement. What do you do when there is no implementation? What do you do when there is an implementation, but there is no source code? As a provider of an implementation, how do you ensure that a subtle change that you made in a method didn't change the implied interface of a parameter? Those kinds of problems are pure anathema to any project of significant size. As another example, it is this exact same exposure of implementation details that wreaks havoc with developers using C++ templates.
Ehud wrote:
I wasn't trolling, by the way.
You sure fooled me. As I see it, interface inheritance is quite indeed the "pillar of OO", just as function prototypes and pointers are the "pillars of procedural programming". They are the means of describing the interface and the corresponding implementation of a system. To me, that is the crux of software development.
I hope I haven't scared you, Ehud. :)
Addendum
Argh. I suppose I'm guilty of commenting before reading. I now realize that the term "inheritance" was thrown around recklessly in the article to refer solely to implementation inheritance, and it occurs to me that Ehud was probably just carrying that over in his post. If it's not apparent from my posts, I hold little passion for implementation inheritance, as I find the important details of a system to lie in the specification and interface design - and I prefer that that be in terms of purely abstract interfaces.
|
|
Toby Reyelts - Re: Is Inheritance a Pillar of OO?
3/12/2003; 8:38:36 PM (reads: 2552, responses: 0)
|
|
This is similar to adding an anonymous Listener in Java's Swing.
Indeed. Extremely similar. In fact, Gilad Bracha (a Sun engineer responsible for many of the existing Java language changes) has been working on some syntactic sugar to bring anonymous inner classes even closer to first-class closures.
|
|
Dominic Fox - Re: Is Inheritance a Pillar of OO?
3/13/2003; 12:57:53 AM (reads: 2477, responses: 0)
|
|
I code...*muffled sob*...Visual Basic in my day job; it has some support for interface inheritance and none at all for implementation inheritance. Mostly I don't miss implementation inheritance (there are plenty of other things about the language to swear at before one needs to start worrying about that sort of thing), but recently I needed to create a large number of somewhat similar classes and ended up having to resort to cutting and pasting the code to delegate methods to an instance of the "base" class for all of them. Implementation inheritance in this scenario would have made everything look a lot cleaner.
More frustratingly, if you want to use a base class as a template and defer part of its implementation to a subclass, the implementation-inheritance-based technique of having methods in the superclass call other methods that are virtual in the superclass and overridden in the subclass has no straightforward equivalent using interface-only inheritance. Of course there are workarounds, but what they are working around is the lack of implementation inheritance. Alexandrescu-style template abuse in C++ (policy classes, etc.) offers another approach, I suppose, but neither VB nor (until very recently) Java has support for generic programming of this type.
No doubt what's really wanted here is higher-order functions, of course...
|
|
|
To me, "Is Inheritance a Pillar of OO?" is wholly uninteresting, it is time (actually it was time 10 years ago) to completely forget about the concept of "OO". Anyone who in 2003 still says he practises "OO" programming (as opposed to what?) or thinks a language should be "OO" to be worthy is seriously confused.
What may be important is whether a language supports inclusion polymorphism or not, and inheritance is just one of many ways to achieve that (and a rather messy one at that). Inclusion polymorphism is the only new concept the "OO" wave brought us over strictly procedural languages. Most people by now will agree that other things associated with "OO" such as datahiding and reuse work better at module/component level anyway, i.e. they are completely orthogonal to inclusion polymorphism (even procedural languages can produce nicely reusable black boxes).
I program. My program contains different types of objects behaving differently for certain actions, and I use the language's inclusion polymorphism feature to implement that. Maybe for my problem I value locality over extensibility and I use a switch() instead :) Big deal, they are all just tools in my toolbox.
|
|
Isaac Gouy - Re: Is Inheritance a Pillar of OO?
3/13/2003; 5:12:46 AM (reads: 2409, responses: 0)
|
|
they are all just tools in my toolbox
Agreed.
Toby wrote:
I've written in both Smalltalk and Lisp before
But not with other people?
class libraries which are solely specifications
Wouldn't you use Smalltalk Interfaces for the same purpose?
How do you separate interface/specification from implementation?
If you decide not to use explicit interfaces (such-as Smalltalk Interfaces) then the separation can only be tacit.
How does this work in a dynamic language?
The people talk with each other, a lot. Sometimes they document stuff.
a group of 30 engineers
Ah, maybe you mean a large team rather than a large task? With more productive tools you can do the large task with a smaller team.
Interfaces enforce...
As someone who has used Smalltalk and Lisp, you know that dynamic languages aren't about enforcement.
What do you do when there is no implementation?
I'm not clear what you mean - are we talking about design?
no source code?
Decompile! No that's Java... ;-)
Mostly there is source code. If there's no source code you need a spec (Isn't that what a Java API is?)
|
|
Toby Reyelts - Re: Is Inheritance a Pillar of OO?
3/13/2003; 7:29:10 AM (reads: 2349, responses: 1)
|
|
But not with other people?
Yes, with other people, but never on a project that involved more than four people.
Wouldn't you use Smalltalk Interfaces for the same purpose?
Because SmallInterfaces aren't a standard part of the language, I can't depend upon 3rd parties to use them. In fact, most 3rd parties will not. Apparently,
there is no support for explicit and dynamically inferred interfaces within Smalltalk which is portable across all Smalltalk variants.
(Once you require interfaces in a language, is there any point of checking them at runtime, when you could have checked them at compile time?)
If you decide not to use explicit interfaces (such-as Smalltalk Interfaces) then the separation can only be tacit.
And that, I fear, is the crux of the matter.
The people talk with each other, a lot. Sometimes they document stuff.
And I know that this works in a small team of good engineers, but what happens when you're trying to use some other 3rd party framework or library, or trying to integrate with folks located in another country in a timezone that is 8 hours off from your own, or heck, trying to integrate with another team on a different floor in your building?
Ah, maybe you mean a large team rather than a large task?
With more productive tools you can do the large task with a smaller team.
There is some truth to that, however, it obviously only scales so far. For example, the same project I mentioned earlier had over 5000 pages of requirements and specifications. That's not something you will implement with a small team of engineers in a short period of time. To take this a step further, I would say that almost every single non-trivial Java program relies on at least one major 3rd party library.
As someone who has used Smalltalk and Lisp, you know that dynamic languages aren't about enforcement.
Quite right. They also appear to not be about programming in the large.
I'm not clear what you mean - are we talking about design?
No, I'm talking about when there is only specification and no implementation. For example, I can download the "specification" for JMS as a group of Java .class files, and then I can build against those .class files knowing that I can plug in any JMS implementation at any time. Within projects, across teams, it is very common to deliver specifications before implementation.
Mostly there is source code.
This is a major stumbling block for most vendors. Even in the face of decompilation, most vendors refuse to release source code, or if they don't refuse, will only do so at an overwhelming cost.
you need a spec (Isn't that what a Java API is?)
Sure. A specification (in the form of Javadoc) comes from a set of interfaces - not an implementation.
|
|
Isaac Gouy - Re: Is Inheritance a Pillar of OO?
3/13/2003; 9:23:51 AM (reads: 2293, responses: 0)
|
|
Toby, maybe we're bringing in too many things at once?
Let's step back and see if we can bring at least this one to a conclusion.
If you decide not to use explicit interfaces... then the separation can only be tacit.
And that, I fear, is the crux of the matter.
Do I think it would have been good to have something like SmallInterfaces in the language 20 years ago?
Yes, I think so.
Has the lack of explicit interfaces (in the language) been some kind of insurmountable problem for large projects?
They also appear to not be about programming-in-the-large
(ooops house is being fumigated for termites... later)
|
|
Neel Krishnaswami - Re: Is Inheritance a Pillar of OO?
3/13/2003; 9:45:54 AM (reads: 2270, responses: 0)
|
|
I've just been looking at Flatt, Felleisen and Krishnamurthi's 1998 paper "Classes and Mixins". (http://citeseer.nj.nec.com/flatt98classe.html) This looks like a nice way of getting the benefits of interface inheritance (code reuse) without its downside (loss of compositionality).
|
|
Reilly Hayes - Re: Is Inheritance a Pillar of OO?
3/13/2003; 10:11:10 AM (reads: 2260, responses: 0)
|
|
I find the important details of a system to lie in the specification and interface design - and I prefer that that be in terms of purely abstract interfaces.
I couldn't agree more. And I am a big fan of interface inheritance in supporting this approach in statically typed languages. It is nice, but not absolutely essential to polymorphism (as implied elsewhere), in dynamically typed languages.
|
|
Patrick Logan - Re: Is Inheritance a Pillar of OO?
3/13/2003; 10:31:36 AM (reads: 2243, responses: 0)
|
|
[Dynamic languages] appear to not be about programming in the large
This has been covered in several long message threads in LtU already. Search for them.
This statement is false. Those threads will include information refuting this statement by presenting real world evidence.
|
|
Patrick Logan - Re: Is Inheritance a Pillar of OO?
3/13/2003; 10:35:22 AM (reads: 2242, responses: 0)
|
|
Smalltalk does not need interface inheritance as a language construct. But you should have interface documentation and test cases, at least in the form of protocols and unit tests.
|
|
water - Re: Is Inheritance a Pillar of OO?
3/13/2003; 10:55:26 AM (reads: 2293, responses: 0)
|
|
> The people talk with each other, a lot. Sometimes they document stuff.
And I know that this works in a small team of good engineers, but what happens when you're trying to use some other 3rd party framework or library, or trying to integrate with folks located in another country in a timezone that is 8 hours off from your own, or heck, trying to integrate with another team on a different floor in your building?
They write unit tests, and both sides use those as shared formal documents of the behavior of their code. That's the contract instead of just a method's type signature.
|
|
Patrick Logan - Re: Is Inheritance a Pillar of OO?
3/13/2003; 11:00:00 AM (reads: 2230, responses: 0)
|
|
what happens [in dynamic languages] when you're trying to use some other 3rd party framework or library, or trying to integrate with folks located in another country in a timezone that is 8 hours off from your own, or heck, trying to integrate with another team on a different floor in your building?
Whether it is dynamic or static typing, you still need the same documentation and test cases to use it effectively. Just static types alone will not be a sufficient condition. And based on real world experience, it is not even a necessary condition. The latter is all that is needed. This has been demonstrated many times over several decades of dynamic language experience in production quality systems.
There is no controvery, just lack of awareness on the part of programmers who have not been involved in the dynamic language segment of the population.
|
|
Toby Reyelts - Re: Is Inheritance a Pillar of OO?
3/13/2003; 11:14:09 AM (reads: 2232, responses: 0)
|
|
This has been covered in several long message threads in LtU already. Search for them.
Patrick, I've already read the entire archives of LtU. It's why I said I didn't want to turn this into YAWODTVST (yet another war on dynamic typing versus static typing). In any case, I've made an effort to remain objective in both my queries and my statements.
Smalltalk does not need interface inheritance as a language construct.
Apparently, others hold a differing opinion.
But you should have interface documentation and test cases, at least in the form of protocols and unit tests.
This is a good example of something which has already been discussed. You can write infinite test cases, or you can use a compiler that can prove type safety, spending your extra time doing something more productive. I know which one I prefer.
|
|
Ehud Lamm - Re: Is Inheritance a Pillar of OO?
3/13/2003; 11:56:32 AM (reads: 2212, responses: 0)
|
|
I wanted to say a a few things from a foundational (i.e., theoretical) point of view. Note that I am not attempting to present a full theory of OOP, merely to state some important results. Nor is this an historical account.
We start by thinking about information hiding (cf. Parnas), encapsulation and abstraction. Other terms referring to (roughly) the same issue: seperation of interface and implementation, abstract data types.
An ADT specified as an interface can be seen as a set of axioms that must be satisfied by any given implementation. The goal here is to be able to reason about programs algebraically. This very goal is also sought by functional programming enthusiasts, and led to the importance of category theory in works on the foundations of programming.
The emphasis on information hiding and encapsulation led to so called, object based languages, that support modules that include both data and methods. The classic language in this family is CLU (code example). Another dominant language in this category was Ada83.
Trying to incorporate ADTs into programming language type systems led to the important result that Abstract Types Have Existential Type (Mithcell, Plotkin; 1988).
Next comes inheritance. Inheritance can be used (as was mentioned in this thread earlier) to connect (abstract) interfaces with (possibly mulitple) implementations. However, it can also be used for code reuse (implementation inheritance) and for incremental implementation (i.e., extendibility). Alas, the programming language has no way to tell which of these (very different) semantic interpretations applies in each case.
The semantics of inheritance relations in most porgramming languages support subclass polymorphism. Barbara Liskov (of CLU fame) and Jeannette Wing managed to turn this into A Behavioral Notion of Subtyping, fondly called The Liskov Substituion Principle or the LSP (I also recommend Robert Martin's more down to earth article).
That being said, we should keep in mind that Inheritance is not subtyping.
This is one reason why some find inheritance to be problematic.
Adding explicit contracts to the language (as evangelized by Eiffel) also complicates matters.
Multiple inheritance opens its own can of worms, which I will not discuss here.
These are but a few pointers.
So is Inheritance a Pillar of OO? It depends, of course, on what you are interested in. Are you talking OOD, OOPLs, or object oriented programming best practices, for example?
From a foundational point of view, inheritance raises many questions. The original concepts of data abstraction, information hiding and modularity led to important results and useful techniques (e.g., algberaic specification, deriving programs from their specifications etc.)
However, these fundamental concepts found their way into programming languages that aren't traditionally considered OOP, especially into functional languages.
|
|
Anton van Straaten - Re: Is Inheritance a Pillar of OO?
3/13/2003; 1:08:11 PM (reads: 2173, responses: 0)
|
|
Reading this thread, and having participated in some of the earlier ST/DT discussions, something is puzzling me. I think "dynamically-typed" languages may be a little too broad for the issues being discussed. I'm quite willing to accept that there are ways to address these issues of interfaces and types in Smalltalk, and in Lisp, both of which are very powerful languages with long histories of use for some pretty complex applications. As a result, their environments and libraries are rich and extensive, and the languages themselves are very extensible, and have already been extended to meet all sorts of needs.
However, both of these languages are hard to find in commercial environments, to say the least. In fact, I've seen both companies and developers moving away from Smalltalk, in particular.
So I'm interested in what other DT languages people here might really be using to do complex or heavyweight commercial work with - something more than the ubiquitous, but almost uniformly lightweight, web scripting. As I see it, what's true for Smalltalk & Lisp may not in fact be true for, say, Python. For example, Isaac mentioned Smalltalk interfaces. Does Python have an equivalent?
More generally, what kinds of complex or heavyweight apps are being implemented in DT languages *other* than Smalltalk and Lisp, and what kinds of companies are using these languages for their core IS needs? Or are we really just talking about evangelizing the DT languages, that they're capable of playing a much bigger role? If so, which languages specifically are being evangelized: just Lisp and Smalltalk, or does it extend to Python, Ruby, or even Perl, or any others?
|
|
Dan Shappir - Re: Is Inheritance a Pillar of OO?
3/13/2003; 2:08:30 PM (reads: 2147, responses: 0)
|
|
I'm glad to see that my post generated such a vigorous debate.
An interesting anecdote that springs to mind is Microsoft's COM lack of implementation inheritance (BTW it's not surprising that COM shares this trait with VB since both technologies significantly influenced one another). When COM was introduced it was regularly lambasted for not being real OO because that missing functionality. COM evangelists went to great lengths to argue that this was an intentional design choice rather than a side-effect of COM's design. Every COM book had a chapter explaining why implementation inheritance is bad (fragile base class argument) and describing two alternatives - delegation and aggregation.
Aggregation was a somewhat convoluted mechanism by which one COM object could wrap and extend another (providing the object to be wrapped allowed this). In Later books the COM specialists admitted that aggregation was added because the lack of implementation inheritance was perceived to be a bigger problem than it actually was.
All this did not stop Microsoft from making implementation inheritance a cornerstone of its new component framework .NET . Indeed this was often one of first features listed. And to one-up Java, .NET allows implementation inheritance across PL boundaries. Many .NET facilities, such as ASP.NET rely on implementation inheritance, that is you derive your class from a specific base and override the appropriate methods.
|
|
Anton van Straaten - Re: Is Inheritance a Pillar of OO?
3/13/2003; 2:56:04 PM (reads: 2143, responses: 0)
|
|
Back on the main topic, inheritance definitely seems to be an "unsolved problem" in OO languages. As already mentioned, it involves so many competing forces: typing, interface vs. implementation, single vs. multiple, etc. As a result, languages have typically picked some workable compromise, and lived with the limitations this produces.
Smalltalk picked single inheritance, and no explicit distinction between interface & implementation. By having dynamic typechecking, it supports multiple interfaces implicitly, which is very important - e.g. so that classes unrelated by inheritance can support common interfaces for cross-cutting kinds of requirements. Smalltalk has made use of this capability from very early on. One of the criticisms of this approach relates directly to the ST/DT discussion: heavy use of implicit interfaces can be difficult to manage - interfaces can kind of hide in the code, and be easy to make mistakes with.
Java in some ways tries to be a statically-typed Smalltalk. To retain the multiple interface capability, it provides an explicit interface construct. Classes can implement multiple interfaces, but can only singly inherit implementation. This can be a real problem if you make heavy use of interfaces, because there's no good way to reuse interface implementations - unless you use something like an aspects tool, or pathologically structure your implementation inheritance (defeating the purpose of separating interface from implementation), you can end up cutting and pasting interface implementations, which is highly undesirable.
In C++, anything goes. It supports interfaces in the form of abstract classes, and multiple implementation inheritance, combined with templates and composition/aggregation as appropriate, allows interface implementations to be reused unrestrainedly. But, this can be messy and hard to reason about. One system that makes heavy use of this approach is Microsoft's COM, since COM interfaces essentially are C++ virtual function tables, i.e. C++ interfaces. Implementing a COM class using e.g. Microsoft's ATL library involves inheriting all the COM interfaces you plan to implement, and possibly using some standard implementations for those interfaces, using multiple inheritance and templates. Although C++ doesn't compromise much in terms of what it allows, it also doesn't provide much by way of support for the complexity that its flexibility introduces. And it's low level (or plain messy) in other ways, which tends to detract from its OO power.
Languages like Eiffel, and systems like CLOS, almost seem to go too far in terms of capabilities. They offer a lot of features, and if you use them all, they tend to completely take over the structure of an application. Most of these features are intimately tied to inheritance - pre/post conditions, before/after methods, etc. But, somewhat like the situation with comprehensive class frameworks like J2EE, this structure can dominate the design of a program to a point where it seems to lose productivity, and you find yourself coding around the restrictions imposed by the structure. Of course, you're not necessarily forced to use all the features.
It still seems to me that none of these languages, or any of the others I'm familiar with, manage to exploit the full potential of interface *and* implementation inheritance, in a completely clean and manageable way.
When it comes to implementation inheritance, I think a big problem is that this has been one of the only automated reuse mechanisms available to working programmers, and it therefore naturally gets abused. Implementation *reuse* ought to be the real goal in this area, and OO-style implementation inheritance is only one means of getting there.
|
|
Patrick Logan - Re: Is Inheritance a Pillar of OO?
3/13/2003; 4:21:21 PM (reads: 2101, responses: 0)
|
|
However, both of these languages are hard to find in commercial environments, to say the least. In fact, I've seen both companies and developers moving away from Smalltalk, in particular.
Smalltalk and Lisp are a more difficult sell than ever because the popular languages are so much closer to these languages than in the past. This is a cultural/psychological/economic thing, more than a technical thing.
If so, which languages specifically are being evangelized: just Lisp and Smalltalk, or does it extend to Python, Ruby, or even Perl, or any others?
Python looks like the winner of this lot, but the current implementations are not as robust as the current (and more mature) implementations of Smalltalk and Lisp.
Apparently, others hold a differing opinion... that Smalltalk does not need interface inheritance as a language construct.
Actually this is not subject to argument. By definition and by example Smalltalk does not *need* an interface inheritance mechanism.
What you meant to say is the some people (a small minority of actual Smalltalk programmers) *prefer* an interface inheritance mechanism.
|
|
Patrick Logan - Re: Is Inheritance a Pillar of OO?
3/13/2003; 4:25:09 PM (reads: 2103, responses: 0)
|
|
|
Anton van Straaten - Re: Is Inheritance a Pillar of OO?
3/13/2003; 7:24:15 PM (reads: 2057, responses: 0)
|
|
[Ward Cunningham] captures the essence of objects, and it is not inheritance. It is the message send.
Well, the message send is a shorthand for the idea of abstracting objects behind interfaces. Whatever term you use, and whether the interfaces are single, multiple, implicit, or explicitly declared, different types of object can support the same interface, allowing OO-style polymorphism. (Some Smalltalk folk don't like this view of things, or at least didn't used to, but it is nevertheless just a different view of the same capability.)
But by this definition alone, Visual BASIC qualifies as OO-enough for Ward Cunningham. I wonder what he'd think of that?
Also, many functional languages would qualify as OO by that definition, which probably isn't quite right. In particular, the notions of object identity and mutation of objects are characteristic of traditional OO, and "message sends" alone does not capture this.
"Message sends" could be said to be the central pillar of OO, but it's hard to argue that inheritance is not *a* pillar of current OO languages. Remove inheritance from Smalltalk or Java, and you'd have some major redesigning to do - and some alternative would be needed to replace what inheritance does for those languages. OO as currently formulated needs inheritance, whether it wants it, or should have it, or not. Which in a sense, is where existing OO languages run into some trouble - they haven't all dealt well with separation of concerns relating to inheritance vis a vis other features.
|
|
Michael Vanier - Re: Is Inheritance a Pillar of OO?
3/13/2003; 10:57:26 PM (reads: 2031, responses: 2)
|
|
I think the key aspect of object-oriented programming is polymorphism, which is the ability to respond to a message differently depending on your type. Thus, saying that message sending is the essence of OO is essentially correct.
Studying the language Sather was an eye-opener for me. In Sather, there is an *explicit* separation between the concepts of subtyping (equivalent to implementation of interfaces in java) and code inclusion (almost equivalent of inheritance in java). This makes it clear that implementation inheritance serves two purposes:
1) to reuse code
2) to support a subtyping relationship between classes
The first is just a convenience, although sometimes a major one. The second one is what OO is really about. If you have code that works for some type (interface), then to get a new class to work with that code all you have to do is make sure your class is a subtype of the type (implements the interface). As mentioned, in Smalltalk this is all implicit; you can implement an "interface" without inheritance as long as your class instances respond to the correct set of messages. I think of this as the "if it looks like a duck, walks like a duck, and quacks like a duck, it IS a duck" theory of objects ;-)
|
|
Ehud Lamm - Re: Is Inheritance a Pillar of OO?
3/14/2003; 1:05:16 AM (reads: 2041, responses: 0)
|
|
But IS A circle-duck a kind ellipse-duck, I wonder?
|
|
Ehud Lamm - Re: Is Inheritance a Pillar of OO?
3/14/2003; 4:13:03 AM (reads: 2012, responses: 0)
|
|
I never managed to fully understand the difference between message-passing and function-calling. Can anyone enlighten me?
|
|
Reilly Hayes - Re: Is Inheritance a Pillar of OO?
3/14/2003; 5:39:27 AM (reads: 1918, responses: 1)
|
|
The differences between message passing and function calls dynamically dispatched by a single object are small. The difference between message passing and generic functions is pretty large. Generic functions are not "directed" at a single object and are dispatched by pattern matching on the objects in the parameter list. The simple case of dispatching on a single object is functionally (no pun intended) equivalent to message passing. There are obvious syntactic differences between the two, as message passing is typically represented by some type of "object <- message" construct, while generic functions look like "function -> object1 object2". Of course, "->" is a placeholder for the syntactic sweetener of your choice.
CLOS implements the generic function model. A few other languages do as well, but I think they are all Lisps. I am partial to the generic function model because it allows combining the object and functional styles without horrible cognitive dissonance.
Clearly, I don't agree that message passing is core to OO.
|
|
Daniel Bonniot - Re: Is Inheritance a Pillar of OO?
3/14/2003; 6:23:02 AM (reads: 1942, responses: 0)
|
|
Not all languages with generic functions are Lisps dialects. In particular, an important direction has been to statically type generic functions, and to do that in a modular way. This is the case of Cecil (optional static typing) and my own language Nice (static typing) that compiles to the JVM (homepage: http://nice.sourceforge.net).
I consider those languages OO, since they can be seen as a natural extension to OO languages. More precisely, they make you see message passing languages as an (annoying!) restriction.
So, I would agree with you that message passing in that sense is not core to OO. What is common to both approaches is inclusion polymorphism (something you find neither in procedural languages, nor in core ML).
|
|
Anton van Straaten - Re: Is Inheritance a Pillar of OO?
3/14/2003; 8:29:03 AM (reads: 1895, responses: 2)
|
|
One recent non-Lisp that implements generic functions is Needle. A much older one is C++. Here's a C++ version of an example from Neel's talk at LL2:
class Thing []
class Rock : public Thing [];
class Paper : public Thing [];
class Scissors : public Thing [];
bool beats(Rock, Scissors) [ return true; ]
bool beats(Paper, Rock) [ return true; ]
bool beats(Scissors, Paper) [ return true; ]
bool beats(Thing, Thing) [ return false; ]
I can't, for the life of me, get curly braces to appear in the above code; so pretend that's what the square brackets are...
|
|
Isaac Gouy - Re: Is Inheritance a Pillar of OO?
3/14/2003; 10:42:19 AM (reads: 1860, responses: 1)
|
|
24 hours is a long-time on LtU!
So I'm interested in what other DT languages people here might really be using to do complex or heavyweight commercial work
Erlang ? Have a look at this recent thread on comp.lang.functional
Implementation *reuse* ought to be the real goal in this area, and OO-style implementation inheritance is only one means of getting there.
I'm in wild agreement with that!
"Message sends" could be said to be the central pillar of OO
Alan Kay seems to think something like that - The big idea is "messaging"
IS A circle-duck a kind ellipse-duck
Maybe the duck-typing viewpoint would be - for my present purpose yes it is, but on another occasion the opposite my suit my needs better?
duck-type punning duct-tape?
|
|
Isaac Gouy - Re: Is Inheritance a Pillar of OO?
3/14/2003; 10:44:14 AM (reads: 1846, responses: 0)
|
|
|
Neel Krishnaswami - Re: Is Inheritance a Pillar of OO?
3/14/2003; 11:19:50 AM (reads: 1828, responses: 0)
|
|
I should note Needle's core type system is closely related to Daniel's Nice -- I based the type inference on his work, for one thing! The differences between Needle and Nice are primarily lie above the core: I'm interested in adding macros, continuations and embedding DSLs into Needle, and Daniel is hijacking Java's huge class library. I expect that the two languages will one day feel different to program in, much as Python and Smalltalk feel different to program in despite having a common semantic core. But they still have a common ancestry, and I encourage people to check out Nice, since it is much more developed than Needle is.
|
|
scruzia - Re: Is Inheritance a Pillar of OO?
3/14/2003; 12:01:34 PM (reads: 1861, responses: 0)
|
|
duck-type punning duct-tape?
See my weblog entry about it from last month ... http://radio.weblogs.com/0100945/2003/02/11.html
Reminiscent of Duct Taping something together: not always the most perfectly elegant way to do something, but often the way that works now. May not last forever, but may well last as long as it is needed.
Sounds best when spoken with an Australian accent.
|
|
Dan Shappir - Re: Is Inheritance a Pillar of OO?
3/14/2003; 2:27:14 PM (reads: 1804, responses: 0)
|
|
I find it interesting that the issue of multiple implementation inheritance vs. single implementation inheritance was so slightly mentioned in this thread. It used to be such a debatable issue. Seems that the validity and merit of implementation inheritance in itself has superceded it. I personally find the IS A relationship embodied by implementation inheritance to be eminently useful (yes, you can do without but I don't want to). And it seems to me that in order to model realistic IS A relationships you need multiple inheritance. Yes, this introduces lots of complexity into the picture, but in most cases you need to worry about it only if you want to.
It is indeed true that inheritance if often misused, but this is true of many PL features. It's also true that the IS A rule is often misunderstood or ignored, but again, this is not a reason to drop a useful feature. And yes, inheritance is less amenable to complex models and refactoring than delegation, but delegation generally involves much more implementation overhead.
Alexandrescu's use of C++ templates and policy classes was mentioned above. This is an example where the combination of generics and multiple implementation inheritance results in a powerful and compelling methodology. Implementing such constructs may not be for the faint of heart, but using them is fairly staightforward and offers lots of opportunities for code reuse (and enhanced performance to boot). BTW, this use of inheritance (policies) has nothing to do with polymorphism. And, you just can't do stuff like this with delegation.
Sather was also mentioned above, which I find interesting as it was with that language that I was also introduced to the different types of inheritance. Unfortunately, coming from C++ (which I had just began to master) I must admit the distinction was lost on me at the time. It took COM to get me to gork the concept of interfaces (I did COM well before I did Java). I'm now a big fan of the use of interfaces (even with C++ only code) and it is one of the main things I miss when I work with a dynamic language such as JavaScript (though I still believe that what Microsoft has done in the form of JScript.NET to introduce interfaces undermines the spirit and intent of the language).
In all the PLs and frameworks that I'm familiar with, interfaces do not constitute a sufficiently detailed contract so that there is no need for documentation. But the ability to express many of the requirements in such a terse fashion, as well as to automate much of the verification, is something I find eminently useful. In this sense this issue is indeed very reminiscent of the ST/DT debates.
|
|
Anton van Straaten - Re: Is Inheritance a Pillar of OO?
3/14/2003; 3:31:39 PM (reads: 1832, responses: 0)
|
|
Erlang - great example, thanks Isaac!
I think a big reason for the "old-time" debates on single vs. multiple implementation inheritance were actually not specifically focusing on implementation inheritance at all: they were being conducted related to languages that didn't do a good enough job of separating interface from implementation, to be able to talk about implementation inheritance independently of interface inheritance. So there were too many conflated and not-fully-recognized concepts being discussed at once, which made for an endless source for debate.
Nowadays, with that distinction more widely recognized and understood, and with languages that have explicit concepts of interface, the question of multiple implementation inheritance alone is nowhere near as interesting. Particularly, as the current thread has indicated, implementation inheritance is no longer likely to be the major focus of reusability mechanisms, going forward.
The blog entry mentioned above references a post by Matz which nicely summarizes one extreme view of the message-sending OO model:
There's one more thing I can tell you. "type" in Ruby is just an
illusion. It doesn't really exist, but in our mind. We emulate it
sometimes using a class of an instance, sometimes using set of methods that an instance can respond.
If it is merely an illusion, why should we care that much?
I think Matz is dead wrong, though - I think knowledge and understanding of types, and acknowledgement of implicit types, is useful even in a pure OO/DT language. It can be an asset to one's design abilities, and help promote clearer thinking. That, to me, is what formal CS is about: to expose the patterns underlying even the most mundane tools that we may have to rely on, to help us deal with them more effectively.
To take a stab at Ehud's question about the difference between message passing and function calling: traditional function calling in the procedural languages had no element of selective dispatch involved. The name of a function determines entirely which piece of code will be invoked. Message passing was the metaphor used by Smalltalk, to conceptually introduce a layer of indirection: you send a message to an object, and the object decides what to do with it. The same message could invoke any number of different functions (methods), depending on which object it is sent to. So it's a metaphor for a particular kind of function dispatch based on object type.
I agree with other comments here that it's not good enough as a general characterization of OO, though. Focusing on the polymorphism aspect, rather than a specific mechanism for implementing it, seems preferable.
BTW, message passing was also used by Carl Hewitt's "actors" model, which led to Scheme. In Guy Steele's own words, from
Objects have not failed:
The Scheme programming language was born from an attempt in 1975 to explicate object-oriented programming in terms that Gerry Sussman and I could understand. In particular, we wanted to restate Carl Hewitt's theory of actors in words of one syllable, so to speak. One of the conclusions that we reached was that “object” need not be a primitive notion in a programming language; one can build objects and their behavior from little more than assignable value cells and good old lambda expressions. Moreover, most of the objects in Hewitt's theory were stateless and unchanging once created; for those, lambda expressions alone were sufficient.
That was a useful theoretical observation–and not original with us, though Scheme did help to spread the word–but it was not a good guide to designing practical programming languages. Soon both Scheme and Common Lisp felt the pressure to graft on facilities to make it easy, not merely possible, to program in an object-oriented style.
This was part of a debate entitled Objects Have Failed at OOPSLA 2002, which may be relevant to the current discussion...
Sorry for exacerbating the page-loading times around here, with these long messages! We need a more sophisticated threading model...
|
|
Daniel Bonniot - Re: Is Inheritance a Pillar of OO?
3/17/2003; 9:35:07 AM (reads: 1627, responses: 1)
|
|
Commenting on the above C++ code:
This code does not define a generic beats function. It only declares four overloaded functions. beats(t1, t2) will only return true if the static type of t1 and t2 matches one of the winning cases. So for any useful usage, it will return false.
A true generic function would be virtual, that is, it would choose the value to return based on the runtime value of the arguments.
C++ does not include the possibility to define generic functions (also called multi-methods). It does allow overloaded functions, where selection occurs at compile-time, and thus are less expressive.
|
|
Ehud Lamm - Re: Is Inheritance a Pillar of OO?
3/17/2003; 10:45:03 AM (reads: 1641, responses: 0)
|
|
That's what I thought. We are talking about so-called multi-methods.
|
|
Anton van Straaten - Re: Is Inheritance a Pillar of OO?
3/18/2003; 10:36:51 AM (reads: 1549, responses: 0)
|
|
Oops - silly me. Thanks for the correction. Actually, I'm kinda glad to hear that C++ is not in fact the ultimate multi-paradigm language...
|
|
|
|