Post #175,844
9/22/04 10:20:23 PM
|
Once again, it's the terminology
It is made by a combination of how you set up the classes and what object is passed to that code at runtime. Unless the code randomly generates data to pass into constructors, the programmer has to decide what data to pass in. I agree with your view that that is just moving the decision point out of the class into the code that calls it. That may be good for the class, but it's still a decision point. Oh, and: Suppose that A is inherited from by classes B and C. ... That's polymorphism. That's also multiple inheritance, if I'm reading you right? The situation you described can't happen in PHP4. B and C can both extend A, then I have to write a factory method with the "case" logic to generate either an A, B or C and return it. I can't just instantiate A and have it return the correct version of itself. (I've tried.)
===
Implicitly condoning stupidity since 2001.
|
Post #175,850
9/23/04 12:05:47 AM
|
That's not multiple inheritance
First of all I'm confused about why you keep on talking about having to write code to return an A, B, or C. At the point where you create an object, you have to call the constructor for A, B, or C. Deciding which constructor to call decides what you get returned to you. Most of the methods that you call on that object will not return an A, B, or C - they do something and/or return something as appropriate for that method. Beyond that, the situation that I described is single-inheritance. Single inheritance is when each class directly inherits from one other class. Other things can inherit from the same class. The parent class itself may inherit from another class. The resulting mess of classes and inheritance will be a tree like this: \n GrandDad\n | \\\n | \\\n | \\\n Dad UncleJim\n /| \\\n / | \\\n / | \\\n / | \\\n Me BrotherJohn CousinRobbie\n (Where I've given classes names of plausible people.) Even though Dad has two children, and even though I have 2 ancestors, there is a simple chain of inheritance from each class to its parents. Every OO language allows you to set up class relationships like this. (Well, every OO language with classes...) By contrast multiple inheritance is where you inherit directly from two different classes. \n Mom Dad\n \\ /\n \\ /\n \\ /\n Me\n With more realistic classes, Mom might decide what kind of I/O routines I have, while Dad decides how I perform key calculations. OO languages disagree on whether it is good to allow this, and disagree on how to handle the situation where you get the same method from both parents. Of particular trouble is "the dreaded diamond". That is an inheritance relationship that looks like this: \n GrandDad\n / \\\n / \\\n / \\\n Mom Dad\n \\ /\n \\ /\n \\ /\n Me\n The problem arises because if some decision needs to visit every parent class, you're going to wind up visiting GrandDad's side of the family twice. This causes various subtle problems. I don't want to go into exact details, but suffice it to say that incest is generally agreed to be as bad an idea in OO design as it is in real life. Cheers, Ben
About the use of language: it is impossible to sharpen a pencil with a blunt axe. It is equally vain to try to do it with ten blunt axes instead. -- Edsger W. Dijkstra
|
Post #175,859
9/23/04 2:46:35 AM
|
Ramble ramble ramble
(me rambling on, that is)
> That's also multiple inheritance, if I'm reading you right?
No, as Ben explained quite well.
> The situation you described can't happen in PHP4. > B and C can both extend A, then I have to write a > factory method with the "case" logic to generate > either an A, B or C and return it.
Well, you have to make that decision *sometime*. If you do it at compile-time or earlier, you've removed a "decision point", IMO.
|
Post #175,862
9/23/04 3:57:24 AM
|
Yes and No
Many times you get polymorphism as follows. Take the following example from the JDK. There is an abstract class AbstractList which implements the List interface which has a number of subclasses among them ArrayList and LinkedList. When you initially create a List you decide whether you want a LinkedList or an ArrayList. Then when you list.get(index) is called the right method is called polymorphically. The decision point is when you originally create the list what concrete class you instantiate. That doesn't really show up in the code as a decision point. That shows up as a variable assignement List list = new ArrayList(). This is not a runtime decision but a development time decision.
There are cases where at run time you decide what to instantiate using a factory class. Take the following example. You are modeling credit card transactions so you have an interface CreditCard and an abstract base class and 3 subclasses Visa, MasterCard and Amex. The way this would usually work would be that the user selects the credit card type and based on that your factory instantiates the correct implementation. Your factory class could just be a switch statement if (amex) instantiate amex etc. or it could do it some other way (use a Map of names to implementations, e.g. "amex" maps to the class Amex and you would then instantiate a new instance). In this case I agree that you have moved a decision point to your factory class.
However, even in the factory case where you moved a runtime decision to the factory, you have still most probably reduced the number of decision points. If the credit cards handle authorization, payment, and billing differently then those 3 decision points where in a procedural implementation would have been if (amex) else if (visa) etc. are now gone. You have only the 1 decision point of what type to create and then all other decisions where types do things differently are handled by polymorphism.
|
Post #175,882
9/23/04 10:07:50 AM
|
I mis-read Ben
When he said "A is inherited from by both" I read that as "A inherits from both". Ain't language fun? As to your other point, I still disagree with you. And I think Ben has expressed the same thing. However, even in the factory case where you moved a runtime decision to the factory, you have still most probably reduced the number of decision points. If the credit cards handle authorization, payment, and billing differently then those 3 decision points where in a procedural implementation would have been if (amex) else if (visa) etc. are now gone. You have only the 1 decision point of what type to create and then all other decisions where types do things differently are handled by polymorphism. First, I don't care about decision points at runtime or compiletime. Those decision are made by the computer, and they're done very quickly. The decision I care about are the ones the programmer has to make. Now in the case where you decide what parameters to pass to a factory class, it's true that the class object returned will handle the rest of the implementation. But the programmer has to know what object is being returned and write code apropriately. Unless every method in every class exists in every other class. If any of the possible child classes has a public function that doesn't exist in the others the programmer has to know not to call it. In properly written code, this won't appear to be a decision point, because there will be no inappropriate calls to the function. But the programmer has to decide not to call a non-existant function.
===
Implicitly condoning stupidity since 2001.
|
Post #175,889
9/23/04 10:30:21 AM
9/23/04 11:20:06 AM
|
You misunderstand interfaces and factories ...
You stated the following: "But the programmer has to know what object is being returned and write code apropriately. Unless every method in every class exists in every other class. If any of the possible child classes has a public function that doesn't exist in the others the programmer has to know not to call it."
In a statically typed language like Java what you wrote is simply not true. A factory should always return an interface. Therefore any Object that you get back from the factory by definition implements all of the methods in the interface. Therefore the only, methods that you can call are the interface methods. The programmer doesn't have to know anything more then the interface. From his perspective the only methods that exist are those that the interface declares and any object that he gets backs is guaranteed to implements them therefore there are no decisions.
In a dynamically typed like language like Smalltalk what you said is theoretically possible but from experience almost never happens. Factories return classes that implicitly implement some interface and those are the methods that are used.
In fact, in a dynamically typed language you never whether an Object implements a method, it is only checked at runtime. In reality, that is not an issue. You know what type of Object you are supposed to be getting.
Edited by bluke
Sept. 23, 2004, 10:50:40 AM EDT
Edited by bluke
Sept. 23, 2004, 11:20:06 AM EDT
|
Post #175,926
9/23/04 12:38:44 PM
|
Drew is right.
Some person or bit of code at some time must decide whether to instantiate an object of class B or one of class C. Find out where and when that happens in your language of choice and you can stop talking past each other.
|
Post #175,986
9/23/04 5:00:13 PM
|
My point was
thatin OO code you make that decision once and then polymorphism works for you. In procedural code that decision is scattered all over the place.
|
Post #175,900
9/23/04 10:55:24 AM
|
I'm actually on the fence
If the code really has been designed in accord with the Liskov Substitution Principle, then you really shouldn't care what type of object you're given.
However while I'm aware of the theory, I'm also aware of the fact that in wading through actual code I do wind up being aware of the abstraction layer. Sometimes painfully so.
Cheers, Ben
About the use of language: it is impossible to sharpen a pencil with a blunt axe. It is equally vain to try to do it with ten blunt axes instead. -- Edsger W. Dijkstra
|
Post #175,902
9/23/04 11:00:41 AM
|
That is with implementation inheritance
These days implementation inheritance is looked down upon. The recommended practice in Java is to always program gainst an interface. Your implementation may use implementation inheritance but this is transparent to the users of the interface. When dealing with an interface this is usally not an issue.
|
Post #175,906
9/23/04 11:08:29 AM
|
That is both with interface and implementation inheritance
Interfaces do not always get implemented correctly...
Oh, the right methods might be there. They just might not do quite the right things.
Cheers, Ben
About the use of language: it is impossible to sharpen a pencil with a blunt axe. It is equally vain to try to do it with ten blunt axes instead. -- Edsger W. Dijkstra
|
Post #175,907
9/23/04 11:15:36 AM
9/23/04 11:17:39 AM
|
With interfaces it is less of a concern
You can say that about any library. at some point you have to trust that the implementation is correct. I believe (it is a gut feeling, I have no proof) that implementation inheritance cause violation of the Liskov principle much more often then interface implementation.
I get the impression that many people who do OO development have never heard of Liskov and therefore when they subclass feel free to break substitubality or do it accidently without paying attention. With interfaces it is much harder to do, you are constrained by the interface.
Edited by bluke
Sept. 23, 2004, 11:17:39 AM EDT
|
Post #175,925
9/23/04 12:36:16 PM
|
Hadn't heard of LSP
But that's exactly what I was thinking about. We haven't been concerned with substitutability. Just getting all the old prodedural code moved into classes has been enough work.
What bluke is saying about interfaces doesn't exist in PHP. There is nothing in the language (currently) that prevents you from implementing public methods in one subclass that don't exist in other subclasses of the same parent, or in the parent itself. I've been thinking lately that this was a Bad Thing™, but now I have something to point to to support my feeling.
===
Implicitly condoning stupidity since 2001.
|
Post #175,934
9/23/04 1:23:55 PM
|
Huh?
"We haven't been concerned with substitutability. Just getting all the old prodedural code moved into classes has been enough work."
I don't see the benefit then.
OO is all about substitutabilty.
Otherwise your "classes" are really just modules. Still not OO.
That was lovely cheese.
--Wallace, The Wrong Trousers
|
Post #176,070
9/24/04 12:30:58 AM
|
Don't get all religious on me
The last large system I worked on, every class in the system was descended from one root class. I understand that in Smalltalk everything is descended from a root Object. Does that mean than any object in Smalltalk is substitutable for every other object? Or that not every instance of inheritance has to be substitutable? Or maybe that substitutability isn't an absolute requirement to call something OO?
Obviously I vote for the last. Frankly, I think a language (or style) can be OO even without polymorphism. Granted, you're giving up a huge potential advantage. But saying, "Your OO isn't real OO without substitutable polymorphism," sounds like something Bryce would say.
===
Implicitly condoning stupidity since 2001.
|
Post #176,075
9/24/04 1:01:56 AM
|
Going to disagreed on this point
[...] Frankly, I think a language (or style) can be OO even without polymorphism. Granted, you're giving up a huge potential advantage.
I'm going to respectively disagree on this one. Of the two notable features of OO (inheritance and polymorphism), I find that it is polymorphism that most greatly defines the OO style. Take inheritance out of an OO language, and you can still do most of the things that OO enables. Take polymorphism out of an OO language and you are dead in the water.
In fact, I will assert that it is runtime/dynamic polymorphism that is required. Static/compile time polymorphism isn't enough.
-- -- Jim Weirich jim@weirichhouse.org [link|http://onestepback.org|http://onestepback.org] --------------------------------------------------------------------- "Beware of bugs in the above code; I have only proved it correct, not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
|
Post #176,089
9/24/04 4:01:49 AM
|
agreed
I've argued that MI is unneeded, and SI is derivative. Its P that is essential - mapping of name to behavior at will.
-drl
|
Post #176,076
9/24/04 1:11:21 AM
|
Re: Don't get all religious on me
I understand that in Smalltalk everything is descended from a root Object.
Yes.
Does that mean than any object in Smalltalk is substitutable for every other object?
No. Just because two classes inherit from a common base class does not mean instances of those classes are substitutable for each other. But both are substitutable for instances of the common base class. (I.e. Instances of Dog and Cat are both substituable for instances of Animal, but dogs and cats are not interchangable).
Or that not every instance of inheritance has to be substitutable?
There are certainly reasons to inherit without maintaining substitutability (Meyer's OOSC[1] gives a lot of reasons for using inheritance). This is (one of the reasons) why subclassing and subtyping are not the same thing. But non-substitutable inheritance is the exception rather than the rule.
[1] "Object Oriented Software Construction" -- Bertrand Meyer.
-- -- Jim Weirich jim@weirichhouse.org [link|http://onestepback.org|http://onestepback.org] --------------------------------------------------------------------- "Beware of bugs in the above code; I have only proved it correct, not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
|
Post #176,129
9/24/04 10:34:42 AM
|
And that's the key point
Just because two classes inherit from a common base class does not mean instances of those classes are substitutable for each other. But both are substitutable for instances of the common base class.
Substitution is a one-way street. The specific can substitute for the generic, but the generic cannot substitute for the specific. Nor can one specific substitute for another.
For instance code which expects to get an object should work with any object, of whatever type. Code which expects to get a receipt should work with different kinds of receipts. But code that expects to get a receipt should not be expected to work properly if it gets an invoice.
Cheers, Ben
About the use of language: it is impossible to sharpen a pencil with a blunt axe. It is equally vain to try to do it with ten blunt axes instead. -- Edsger W. Dijkstra
|
Post #176,248
9/24/04 3:18:39 PM
|
Someday I've got to take a class
Substitution is a one-way street. The specific can substitute for the generic, but the generic cannot substitute for the specific. Now it makes sense. Yes, in ours any specific can substiture for a generic. I got the impression that bluke was saying that any two child classes of the same parent had to be substitutable. The [link|http://c2.com/cgi/wiki?LiskovSubstitutionPrinciple|c2 wiki] I where I looked up LSP also gave that impression. Along with wide disagreement on whether it was a requirement of OO. So the way we do it -- typically a child class is the parent class with additional functionality layered on top -- still counts as substitution? If so then yes, we have been doing that.
===
Implicitly condoning stupidity since 2001.
|
Post #176,252
9/24/04 3:54:21 PM
|
..when I get my inheritance
-drl
|
Post #176,254
9/24/04 4:00:08 PM
|
Yup. No generic substitute for that.
|
Post #176,261
9/24/04 4:20:45 PM
|
Good idea in this instance.
After all, OO programming is a members-only club...
Regards,
-scott anderson
"Welcome to Rivendell, Mr. Anderson..."
|
Post #176,281
9/24/04 5:44:34 PM
|
I object; it's part of a general pattern
|
Post #176,288
9/24/04 6:17:48 PM
|
Ah, but I have a cunning strategy...
Longtime visitors to this forum should recognize the facade of generalization I am presenting here. Private reflection should instantiate understanding, to wit: construction of a public collection of like-minded individuals (a set of peers, as it were) requires interfacing through a common protocol of thought. Without this self-affirming list of congruencies, members of the group will discover that they have begun to substitute incompatible parameters in their world view (Liskov's rules of order notwithstanding).
Without a proper shared language, the chain of command breaks down; proxies are invoked, semantics differ from one person's understanding of the social contract to the next, and we are left with a merely functional proposition of useless orientation.
Now, I have compiled a List of charter singletons the properties of which should bear up under inspection:
1) That all people are to be objectified equally (this is in there for the feminists). 2) That sorting people into distinct types for purpose of evolving break-out discussion groups should be performed dynamically, as opinions can change. 3) That static organizations die if not fed new ideas periodically. 4) That members should be private in their speculations, and public in their memberships. 5) That closure in rancorous conversations (private message passing is not to be tolerated) can only be achieved through proper allocation of public discussion blocks in the forums. 6) That in most instances one should scope one's thoughts locally, and allow only global actions.
I believe I've encapsulated succinctly the behaviour of our group above. Objectors are kindly asked to make sure that they has a valid argument before submitting it to the Club Secretary Isa, as she gets grumpy when presented with more than a single thing at a time...
Regards,
-scott anderson
"Welcome to Rivendell, Mr. Anderson..."
|
Post #176,291
9/24/04 6:26:44 PM
|
Bah. Overridden.
Glad you have more time to compile than I do to interpret.
|
Post #176,294
9/24/04 6:31:13 PM
|
Overloaded your capacity for understanding, eh?
Typical. Basic cogitation yields continuing bad results.
You replied just in time; I'm off to void someone else's warranty package.
Ta Ta For New.
Regards,
-scott anderson
"Welcome to Rivendell, Mr. Anderson..."
|
Post #176,293
9/24/04 6:29:07 PM
|
Ashton, is that you?
:-)
I've heard that the Club Secretary is a party ooper.
Cheers, Scott.
|
Post #176,296
9/24/04 6:33:02 PM
|
Better than the treasurer...
He's looking for an assistant, but he's a stickler for proper resumes. He spends all his time counting references...
Regards,
-scott anderson
"Welcome to Rivendell, Mr. Anderson..."
|
Post #176,301
9/24/04 6:59:43 PM
|
He'll have to wait - I'm collecting garbage
It is a circular reference, he won't get it.
Cheers, Ben
About the use of language: it is impossible to sharpen a pencil with a blunt axe. It is equally vain to try to do it with ten blunt axes instead. -- Edsger W. Dijkstra
|
Post #176,323
9/24/04 8:48:18 PM
|
Coincidentally, there's a fellow around here named Mark...
Sweeps up the place after people are done heaping up the trash.
He applied for the job, but he and the treasurer don't get along. Too much of a generational gap.
Regards,
-scott anderson
"Welcome to Rivendell, Mr. Anderson..."
|
Post #176,332
9/24/04 9:11:32 PM
|
I'm sorry but that pointer is dangling
Buffer luck next time, you wouldn't want to overflow.
Cheers, Ben
About the use of language: it is impossible to sharpen a pencil with a blunt axe. It is equally vain to try to do it with ten blunt axes instead. -- Edsger W. Dijkstra
|
Post #176,389
9/25/04 6:26:13 AM
|
Some people have too much time on their hands...
Something obviously failed; better backtrack and try a different goal
Wade.
I don't know if icon do much better than that pun...
|
Post #176,400
9/25/04 9:35:21 AM
|
You're a real LALRf riot.
At least your grammar is good. You might bison new terms for your lexicon, though, before people start feeling the need to flex their stomachs and yacc.
Now, I have to say that I'm glad we're keeping this conversation lighthearted. Otherwise it would seem like a bad Film Bacchus Naur...
Regards,
-scott anderson
"Welcome to Rivendell, Mr. Anderson..."
|
Post #176,403
9/25/04 10:12:54 AM
|
So you sed. Personally, I think it's a Perl in the Blinker.
|
Post #176,309
9/24/04 7:27:18 PM
|
Uuuuuhh...
C'mon, It's Friday evening, ferchrissakes! Can't you save something like this for Monday?!?
(Nicely done, dammit!) ;-)
jb4 shrub\ufffdbish (Am., from shrub + rubbish, after the derisive name for America's 43 president; 2003) n. 1. a form of nonsensical political doubletalk wherein the speaker attempts to defend the indefensible by lying, obfuscation, or otherwise misstating the facts; GIBBERISH. 2. any of a collection of utterances from America's putative 43rd president. cf. BULLSHIT
|
Post #176,387
9/25/04 3:08:51 AM
|
The cun.. er, clever linguist suffers Code 715
-715 PROGRAM program-name WITH MARK 56064 release-dependency-mark FAILED BECAUSE IT DEPENDS ON FUNCTIONS OF THE RELEASE FROM WHICH FALLBACK HAS OCCURRED
ie A stitch, in time has FAILED TO SAVE 9
//so this is how the neurons twitch hereabouts; it is thought that thoughts think themselves via inherited synapience (until compilations by later scholars of the Twelve Original koans reconstruct a hashish table with passed toke(n)s?)
Ummm, methinks Sanskrit is hard, but a
-904 UNSUCCESSFUL EXECUTION CAUSED BY 57011 AN UNAVAILABLE RESOURCE. REASON reason-code, TYPE OF RESOURCE resource-type, AND RESOURCE NAME resource-name
suggests that This is harder... Resources Are scarce, maybe scarce as REASON ..and the penalty appears to be: EXECUTION!
Y.P.B. Aummmm mighty sorry fer y'all
The ridiculous way is sometimes also the best way that we have to think about things. The LRPD of Small Gods
er, :-\ufffd
|
Post #176,354
9/24/04 10:56:23 PM
|
Or an interface
(rimshot here)
Seriously, the practical example is something like you have an abstract class WriteStream. You have concrete implementations FileWriteStream and SocketWriteStream. The idea is that you could hand either a FileWriteStream or a SocketWriteStream to anything that expects a WriteStream.
Does that make more sense?
That was lovely cheese.
--Wallace, The Wrong Trousers
|
Post #176,438
9/25/04 10:04:33 PM
|
Yes, and that's what we do
Although PHP doesn't have a concept of an abstract class. We could probably write that way anyway if we wanted to.
===
Implicitly condoning stupidity since 2001.
|
Post #176,440
9/25/04 11:47:26 PM
|
Language doesn't need to support abstract class
to have one.
Smalltalk doesn't have an abstract class per se either. Its quite possible to construct an instance of Object (and its occasionally done to create non-nil sentinel values).
You just decide/document something is abstract and don't instance it anywhere.
That was lovely cheese.
--Wallace, The Wrong Trousers
|
Post #176,451
9/26/04 2:30:26 AM
|
That was not what I meant
Sorry if I was unclear. What I was trying to say is that if 2 classes implement an interface then they are substitutable for the interface or if 2 classes inherit from the same base class they can substitute for the base class.
|