Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.forth > #26939 > unrolled thread
| Started by | Doug Hoffman <glidedog@gmail.com> |
|---|---|
| First post | 2013-11-25 06:59 -0500 |
| Last post | 2013-11-27 11:58 -0600 |
| Articles | 15 — 5 participants |
Back to article view | Back to comp.lang.forth
Inheritance Doug Hoffman <glidedog@gmail.com> - 2013-11-25 06:59 -0500
Re: Inheritance Bernd Paysan <bernd.paysan@gmx.de> - 2013-11-25 20:01 +0100
Re: Inheritance Doug Hoffman <glidedog@gmail.com> - 2013-11-26 05:11 -0500
Re: Inheritance Bernd Paysan <bernd.paysan@gmx.de> - 2013-11-26 22:09 +0100
Re: Inheritance the_gavino_himself <visphatesjava@gmail.com> - 2013-11-27 15:25 -0800
Re: Inheritance Bernd Paysan <bernd.paysan@gmx.de> - 2013-11-28 01:39 +0100
Re: Inheritance Mark Wills <markrobertwills@yahoo.co.uk> - 2013-11-28 01:53 -0800
Re: Inheritance Andrew Haley <andrew29@littlepinkcloud.invalid> - 2013-11-25 15:28 -0600
Re: Inheritance Doug Hoffman <glidedog@gmail.com> - 2013-11-26 05:11 -0500
Re: Inheritance Bernd Paysan <bernd.paysan@gmx.de> - 2013-11-26 22:28 +0100
Re: Inheritance Doug Hoffman <glidedog@gmail.com> - 2013-11-26 17:12 -0500
Re: Inheritance Bernd Paysan <bernd.paysan@gmx.de> - 2013-11-27 23:07 +0100
Re: Inheritance Andrew Haley <andrew29@littlepinkcloud.invalid> - 2013-11-26 17:11 -0600
Re: Inheritance Doug Hoffman <glidedog@gmail.com> - 2013-11-27 06:25 -0500
Re: Inheritance Andrew Haley <andrew29@littlepinkcloud.invalid> - 2013-11-27 11:58 -0600
| From | Doug Hoffman <glidedog@gmail.com> |
|---|---|
| Date | 2013-11-25 06:59 -0500 |
| Subject | Inheritance |
| Message-ID | <52933ba3$0$294$14726298@news.sunsite.dk> |
I have been reading that inheritance is falling from favor when using OOP. I agree that inheritance overuse can lead to harder to read/understand/debug code. Of course the use of inheritance is completely controlled by the programmer. Seems to me that using inheritance more sparingly should lead to the following: 1) One should embed objects as instance variables (the "has a" paradigm) instead of inheriting (the "is a" paradigm). At least do so more often when needing to add behavior to an object and that behavior already exists in another class. Sometimes, though, using shallow inheritance is the best way to go because more "pass-through" methods need not then be defined. 2) Late binding to self (aka open recursion) is only used with inheritance. So if we are not using inheritance as much then the default for messages to self should be an early bind for speed. Late binding can still be used when wanted (use a syntax such as [self]). 3) Early binding to self should make using inheritance easier and less prone to bugs. Not to say that late binding to self(inheritance) should never be used. Sometimes it is perfect and greatly enhances code reuse, but again only with inheritance. 4) Messages sent to objects-as-instance-variables should always be early bound, again for speed. The class compiler can do this transparently because the class of the object is known at compile time and the class of the embedded object will not change. Of course objects in a *container* instance variable could be of any class and so late binding is then required (also done transparently). No extra effort needed from the programmer either way. The above techniques will result in object-oriented code that is noticeably faster and easier to write and maintain. -Doug
[toc] | [next] | [standalone]
| From | Bernd Paysan <bernd.paysan@gmx.de> |
|---|---|
| Date | 2013-11-25 20:01 +0100 |
| Message-ID | <l706q6$c5o$1@online.de> |
| In reply to | #26939 |
Doug Hoffman wrote: > I have been reading that inheritance is falling from favor when using > OOP. I agree that inheritance overuse can lead to harder to > read/understand/debug code. Of course the use of inheritance is > completely controlled by the programmer. Seems to me that using > inheritance more sparingly should lead to the following: > > 1) One should embed objects as instance variables (the "has a" paradigm) > instead of inheriting (the "is a" paradigm). At least do so more often > when needing to add behavior to an object and that behavior already > exists in another class. Sometimes, though, using shallow inheritance > is the best way to go because more "pass-through" methods need not then > be defined. > > 2) Late binding to self (aka open recursion) is only used with > inheritance. So if we are not using inheritance as much then the > default for messages to self should be an early bind for speed. Late > binding can still be used when wanted (use a syntax such as [self]). > > 3) Early binding to self should make using inheritance easier and less > prone to bugs. Not to say that late binding to self(inheritance) should > never be used. Sometimes it is perfect and greatly enhances code reuse, > but again only with inheritance. > > 4) Messages sent to objects-as-instance-variables should always be early > bound, again for speed. The class compiler can do this transparently > because the class of the object is known at compile time and the class > of the embedded object will not change. Of course objects in a > *container* instance variable could be of any class and so late binding > is then required (also done transparently). No extra effort needed from > the programmer either way. > > The above techniques will result in object-oriented code that is > noticeably faster and easier to write and maintain. You forgot one important thing, that is the "combination" stuff. You might not have deep inheritance trees, but combine different objects into one. E.g.: In MINOS, every widget has an actor. An actor is a class that gets called for actions, like clicks or keystrokes. There are not too many actor classes with the same interface; usually they don't inherit from each other (so the hierarchy is flat). Those actors are not instance variables, but instance pointers. Calling them absolutely requires polymorphism. The typical case I found for calling with self are "template methods", i.e. methods that do something that is filled further down in the inheritance tree. That also absolutely requires late binding. I don't understand why you are so obsessed with early binding, and argue with speed. Contemporary CPUs do quite well on vtable dispatches with their branch target buffers. They don't do well with a central dispatcher that is more complicated than a simple vtable call, so if you want speed, just make sure that you can implement your system using a vtable. The case where you actually don't have polymorphism (same method called each time) is as fast as the direct call on a Core i7, so this particular case of optimization has aleady been done by the CPU manufacturer. -- Bernd Paysan "If you want it done right, you have to do it yourself" http://bernd-paysan.de/
[toc] | [prev] | [next] | [standalone]
| From | Doug Hoffman <glidedog@gmail.com> |
|---|---|
| Date | 2013-11-26 05:11 -0500 |
| Message-ID | <529473d1$0$297$14726298@news.sunsite.dk> |
| In reply to | #26949 |
On 11/25/13 2:01 PM, Bernd Paysan wrote: > You forgot one important thing, that is the "combination" stuff. You might > not have deep inheritance trees, but combine different objects into one. > Those actors are not instance variables, but instance pointers. Are you talking about "instance variables" that are actually embedded objects? If not what are they? In FMS these are first-class-objects, not pointers to objects. Yes, the instance variables of an object are first class objects themselves. > The typical case I found for calling with self are "template methods", i.e. > methods that do something that is filled further down in the inheritance > tree. That also absolutely requires late binding. "further down in the inheritance tree". I was talking about no inheritance or shallow inheritance. > I don't understand why you are so obsessed with early binding, and argue > with speed. Because speed is important. So is code size. > Contemporary CPUs do quite well on vtable dispatches with their > branch target buffers. They don't do well with a central dispatcher that is > more complicated than a simple vtable call, so if you want speed, just make > sure that you can implement your system using a vtable. If *all* method calls are through vtables then table sizes can get large. This can be a problem. If large table sizes aren't a concern then I agree with your conclusion. -Doug
[toc] | [prev] | [next] | [standalone]
| From | Bernd Paysan <bernd.paysan@gmx.de> |
|---|---|
| Date | 2013-11-26 22:09 +0100 |
| Message-ID | <l732ms$h9k$1@online.de> |
| In reply to | #26963 |
Doug Hoffman wrote: > On 11/25/13 2:01 PM, Bernd Paysan wrote: > >> You forgot one important thing, that is the "combination" stuff. You >> might not have deep inheritance trees, but combine different objects into >> one. > >> Those actors are not instance variables, but instance pointers. > > Are you talking about "instance variables" that are actually embedded > objects? If not what are they? In FMS these are first-class-objects, > not pointers to objects. Yes, the instance variables of an object are > first class objects themselves. No, I'm very deliberate and did say they are pointed to, and not direct instances. The reason for that is that they can be different classes, and different classes have different sizes. All they have in common is the same interface. They are first-class, too. You really have to try this, sticking objects together like this to obtain various different behavior. It's a very common design pattern. >> The typical case I found for calling with self are "template methods", >> i.e. methods that do something that is filled further down in the >> inheritance >> tree. That also absolutely requires late binding. > > "further down in the inheritance tree". I was talking about no > inheritance or shallow inheritance. Shallow inheritance usually has one level further down. That's completely enough to justify such template methods. >> I don't understand why you are so obsessed with early binding, and argue >> with speed. > > Because speed is important. So is code size. You missed the point: Speed is not an issue with vtable based late binding, nor is code size. The late binding call is as big as the early binding call on x86 (native code assumed, of course). 2 bytes for the fetch the vtable, 3 bytes for jump short offset+reg, 5 bytes for a call. Identical code size, and in the case of always using the same class identical speed. The other case (real polymorphism) is slower, but then, it does have a functionality which early binding simply doesn't have. >> Contemporary CPUs do quite well on vtable dispatches with their >> branch target buffers. They don't do well with a central dispatcher that >> is more complicated than a simple vtable call, so if you want speed, just >> make sure that you can implement your system using a vtable. > > If *all* method calls are through vtables then table sizes can get > large. This can be a problem. If large table sizes aren't a concern > then I agree with your conclusion. Agreed, you shouldn't have too many methods in a class. -- Bernd Paysan "If you want it done right, you have to do it yourself" http://bernd-paysan.de/
[toc] | [prev] | [next] | [standalone]
| From | the_gavino_himself <visphatesjava@gmail.com> |
|---|---|
| Date | 2013-11-27 15:25 -0800 |
| Message-ID | <cb852263-3b7b-412a-86ad-1502280820fb@googlegroups.com> |
| In reply to | #26949 |
bernd: I noticed you added an oo package to gforth. Why not more functional stuff a la haskell or lisp? rob pike said oo programming is the roman numerals of computing: http://harmful.cat-v.org/software/OO_programming/
[toc] | [prev] | [next] | [standalone]
| From | Bernd Paysan <bernd.paysan@gmx.de> |
|---|---|
| Date | 2013-11-28 01:39 +0100 |
| Message-ID | <l763bt$tb8$1@online.de> |
| In reply to | #27014 |
the_gavino_himself wrote: > bernd: > > I noticed you added an oo package to gforth. A variant of Mini-OOF with current object; this is really small stuff. Unlike the previous Mini-OOF, it feels complete enough so that I can do actual work with it. > Why not more functional stuff a la haskell or lisp? Because that would be considerably more complex, and for the things I want to do less useful. > rob pike said oo programming is the roman numerals of computing: > > http://harmful.cat-v.org/software/OO_programming/ I'm totally with them: The way most people use OOP is to add layers and layers of abstraction just to delegate work to somebody else. That's not what I want to do. OOP has some specific places where it is useful, it is no silver bullet and not the be all and end all. For GUIs however, it has been shown its usefulness. And that's where I'm using it. -- Bernd Paysan "If you want it done right, you have to do it yourself" http://bernd-paysan.de/
[toc] | [prev] | [next] | [standalone]
| From | Mark Wills <markrobertwills@yahoo.co.uk> |
|---|---|
| Date | 2013-11-28 01:53 -0800 |
| Message-ID | <4083b20a-bcf0-4e97-acdb-3ce812b59381@googlegroups.com> |
| In reply to | #27018 |
On Thursday, November 28, 2013 12:39:25 AM UTC, Bernd Paysan wrote: > I'm totally with them: The way most people use OOP is to add layers and > layers of abstraction just to delegate work to somebody else. That's not > what I want to do. OOP has some specific places where it is useful, it is > no silver bullet and not the be all and end all. > > For GUIs however, it has been shown its usefulness. And that's where I'm > using it. Totally agree (FWIW). I'm finding it (OOP) great for SCADA too, where you have literally thousands of objects of the same type. It's perfect. The 'art' is, like you say, not to get too carried away with it. Some OOP (Java is a particular offender I think) just goes way way too far. It's like the programmers are showing off or something!
[toc] | [prev] | [next] | [standalone]
| From | Andrew Haley <andrew29@littlepinkcloud.invalid> |
|---|---|
| Date | 2013-11-25 15:28 -0600 |
| Message-ID | <96ednQd94ZBxXQ7PnZ2dnUVZ_h-dnZ2d@supernews.com> |
| In reply to | #26939 |
Doug Hoffman <glidedog@gmail.com> wrote: > I have been reading that inheritance is falling from favor when using > OOP. Well, maybe. I suspect that inheritance has been rather overused in some areas, and this is a much needed correction. "is-a" really only makes sense if the object really is an X. > 2) Late binding to self (aka open recursion) is only used with > inheritance. So if we are not using inheritance as much then the > default for messages to self should be an early bind for speed. Late > binding can still be used when wanted (use a syntax such as [self]). > > 3) Early binding to self should make using inheritance easier and less > prone to bugs. What's the point? Late binding costs little in practice, so there's no reason not to use it everywhere. If a system can optimize it into early binding, fine. But it's a waste of the programmer's time to worry about where things should be early-bound and where not. > 4) Messages sent to objects-as-instance-variables should always be > early bound, again for speed. The class compiler can do this > transparently because the class of the object is known at compile > time In general, no. Even if you know that your instance variable is an X, you don't know that it isn't a subclass of X. Early binding serves only to restrict the way code can be resued. > and the class of the embedded object will not change. Of course > objects in a *container* instance variable could be of any class and > so late binding is then required (also done transparently). No > extra effort needed from the programmer either way. > The above techniques will result in object-oriented code that is > noticeably faster and easier to write and maintain. Andrew.
[toc] | [prev] | [next] | [standalone]
| From | Doug Hoffman <glidedog@gmail.com> |
|---|---|
| Date | 2013-11-26 05:11 -0500 |
| Message-ID | <529473e2$0$292$14726298@news.sunsite.dk> |
| In reply to | #26951 |
On 11/25/13 4:28 PM, Andrew Haley wrote: > Doug Hoffman <glidedog@gmail.com> wrote: >> I have been reading that inheritance is falling from favor when using >> OOP. > > Well, maybe. I suspect that inheritance has been rather overused in > some areas, and this is a much needed correction. "is-a" really only > makes sense if the object really is an X. > >> 2) Late binding to self (aka open recursion) is only used with >> inheritance. So if we are not using inheritance as much then the >> default for messages to self should be an early bind for speed. Late >> binding can still be used when wanted (use a syntax such as [self]). >> >> 3) Early binding to self should make using inheritance easier and less >> prone to bugs. > > What's the point? Late binding costs little in practice, so there's > no reason not to use it everywhere. "Costs little" is a subjective term. This is true only for speed and only if all vtable calls are used. See my response to Bernd. If speed *and* code size are important then that changes things. > If a system can optimize it into > early binding, fine. But it's a waste of the programmer's time to > worry about where things should be early-bound and where not. With no inheritance or shallow inheritance late binding to self isn't done or is done infrequently. >> 4) Messages sent to objects-as-instance-variables should always be >> early bound, again for speed. The class compiler can do this >> transparently because the class of the object is known at compile >> time > > In general, no. Even if you know that your instance variable is an X, > you don't know that it isn't a subclass of X. Early binding serves > only to restrict the way code can be resued. In general *always* with FMS. The class of the embedded-object-as -instance-variable is not going to change. It doesn't matter if it is a subclassed object. In FMS it is impossible for the class of the embedded object to change. If it is then you are talking about a very different object model. Of course we can store the object *in* an instance variable and then yes, late binding *must* be used. FMS supports this as well. This binding to the embedded object is transparent to the programmer. No restrictions on code reuse. -Doug
[toc] | [prev] | [next] | [standalone]
| From | Bernd Paysan <bernd.paysan@gmx.de> |
|---|---|
| Date | 2013-11-26 22:28 +0100 |
| Message-ID | <l733q4$in6$1@online.de> |
| In reply to | #26964 |
Doug Hoffman wrote: > "Costs little" is a subjective term. This is true only for speed and > only if all vtable calls are used. See my response to Bernd. If speed > *and* code size are important then that changes things. See my response, a vtable call is 2+3 bytes on x86, a direct call is 5 bytes. Same number of bytes, same number of cycles (in the branch target hit case) on x86. >> In general, no. Even if you know that your instance variable is an X, >> you don't know that it isn't a subclass of X. Early binding serves >> only to restrict the way code can be resued. > > In general *always* with FMS. The class of the embedded-object-as > -instance-variable is not going to change. That is a severe limitation. I've both in BerndOOF, embedded-objects that can have only one class, and embedded-by-pointer objects that have the identical syntax for use, but can have different classes. Guess what: I never use the fixed, inflexible embedded objects. And yes, I think when I and you talk, we always talk about completely different object models. That's why I mostly gave up on standardization (of the model; maybe some meta stuff can still be standardized): Different people have so vastly different understandings of what OOP is, and it's always like talking to the blind men with the elephant. Accept it: OOP is bigger than you can comprehend. I know I'm only using a certain part. My OOP is flexible and strong, but I know it is just next to something rigid and inflexible. I've also seen OOP that is thin and not strong, but makes a lot of wind when moved, and OOP which is just a massive body (the "bloat"). -- Bernd Paysan "If you want it done right, you have to do it yourself" http://bernd-paysan.de/
[toc] | [prev] | [next] | [standalone]
| From | Doug Hoffman <glidedog@gmail.com> |
|---|---|
| Date | 2013-11-26 17:12 -0500 |
| Message-ID | <52951cdb$0$304$14726298@news.sunsite.dk> |
| In reply to | #26983 |
On 11/26/13 4:28 PM, Bernd Paysan wrote: > Doug Hoffman wrote: >> In general *always* with FMS. The class of the embedded-object-as >> -instance-variable is not going to change. > > That is a severe limitation. Sorry if I wasn't clear. In FMS one can do it either way: 1) Declare the embedded object class. The class can never change. 2) Store the embedded object in a container instance variable. The object (and class) can change a million+ times during program execution. No limitations. > I've both in BerndOOF, embedded-objects that > can have only one class, and embedded-by-pointer objects that have the > identical syntax for use, but can have different classes. You and I are providing the same functionality. -Doug
[toc] | [prev] | [next] | [standalone]
| From | Bernd Paysan <bernd.paysan@gmx.de> |
|---|---|
| Date | 2013-11-27 23:07 +0100 |
| Message-ID | <l75qfd$g1n$1@online.de> |
| In reply to | #26986 |
Doug Hoffman wrote: > On 11/26/13 4:28 PM, Bernd Paysan wrote: > Sorry if I wasn't clear. In FMS one can do it either way: > > 1) Declare the embedded object class. The class can never change. > 2) Store the embedded object in a container instance variable. The > object (and class) can change a million+ times during program execution. > > No limitations. Great. >> I've both in BerndOOF, embedded-objects that >> can have only one class, and embedded-by-pointer objects that have the >> identical syntax for use, but can have different classes. > > You and I are providing the same functionality. Then it's fine. I just so far didn't find a good use for embedded objects that have a fixed, unchangeable class. The unchangeable types usually are pretty primitive types like integers, floats, or strings, and as such don't need OOP. -- Bernd Paysan "If you want it done right, you have to do it yourself" http://bernd-paysan.de/
[toc] | [prev] | [next] | [standalone]
| From | Andrew Haley <andrew29@littlepinkcloud.invalid> |
|---|---|
| Date | 2013-11-26 17:11 -0600 |
| Message-ID | <vfKdnV3OO8IKtwjPnZ2dnUVZ_jednZ2d@supernews.com> |
| In reply to | #26964 |
Doug Hoffman <glidedog@gmail.com> wrote: > On 11/25/13 4:28 PM, Andrew Haley wrote: >> Doug Hoffman <glidedog@gmail.com> wrote: >>> I have been reading that inheritance is falling from favor when using >>> OOP. >> >> Well, maybe. I suspect that inheritance has been rather overused in >> some areas, and this is a much needed correction. "is-a" really only >> makes sense if the object really is an X. >> >>> 2) Late binding to self (aka open recursion) is only used with >>> inheritance. So if we are not using inheritance as much then the >>> default for messages to self should be an early bind for speed. Late >>> binding can still be used when wanted (use a syntax such as [self]). >>> >>> 3) Early binding to self should make using inheritance easier and less >>> prone to bugs. >> >> What's the point? Late binding costs little in practice, so there's >> no reason not to use it everywhere. > > "Costs little" is a subjective term. This is true only for speed and > only if all vtable calls are used. See my response to Bernd. If speed > *and* code size are important then that changes things. Sure, but the extra flexibility you get means that you can, as a programmer, get more done in less time because you have more reusability due to more polymorphism: you can do more with less coding. In some extreme cases yes, if you really are sunning out of cycles, you must restrict the design. But that's a special case. >> If a system can optimize it into early binding, fine. But it's a >> waste of the programmer's time to worry about where things should >> be early-bound and where not. > > With no inheritance or shallow inheritance late binding to self isn't > done or is done infrequently. > >>> 4) Messages sent to objects-as-instance-variables should always be >>> early bound, again for speed. The class compiler can do this >>> transparently because the class of the object is known at compile >>> time >> >> In general, no. Even if you know that your instance variable is an X, >> you don't know that it isn't a subclass of X. Early binding serves >> only to restrict the way code can be resued. > > In general *always* with FMS. The class of the embedded-object-as > -instance-variable is not going to change. It doesn't matter if it is a > subclassed object. In FMS it is impossible for the class of the > embedded object to change. So, it's an inflexible system that limits reuse. It means that a setX method can't be passed an instance of a subclass. Why do that? Why not allow subclassing? > If it is then you are talking about a very different object model. > Of course we can store the object *in* an instance variable and then > yes, late binding *must* be used. Sorry, you've lost me. First you say that an instance variable can't be a subclass, then that it can. > FMS supports this as well. This binding to the embedded object is > transparent to the programmer. No restrictions on code reuse. OK, let me try to be clear what I mean about reuse. The subclass relationship is that wherever an instance of Class X appears in a program, a subclass Y of Class X may be substituted without alteration to that program. All methods of Class X that are overridden by Class Y will be called as appropriate. The programmer does not have to modify any program that uses Class X in order to use Class Y. The programmer does not have to modify Class X when writing Class Y. This means, in general, that early binding to an object's methods is impossible because a caller cannot know the true class of an object, and therefore cannot know which method to call. Andrew.
[toc] | [prev] | [next] | [standalone]
| From | Doug Hoffman <glidedog@gmail.com> |
|---|---|
| Date | 2013-11-27 06:25 -0500 |
| Message-ID | <5295d6c1$0$305$14726298@news.sunsite.dk> |
| In reply to | #26988 |
On 11/26/13 6:11 PM, Andrew Haley wrote: > Sorry, you've lost me. First you say that an instance variable can't > be a subclass Where did I say that? > , then that it can. If the instance variable is a *container*, then that container can hold an object of *any* class, subclass or not. Re-read my original post for this thread. Item 4), 2nd to last sentence. > OK, let me try to be clear what I mean about reuse. > > The subclass relationship is that wherever an instance of Class X > appears in a program, a subclass Y of Class X may be substituted > without alteration to that program. All methods of Class X that are > overridden by Class Y will be called as appropriate. The programmer > does not have to modify any program that uses Class X in order to use > Class Y. Except using Class Y will break the program that was designed to use Class X if any methods are changed(over ridden) which is usually the case. > This means, in general, that early binding to an object's methods is > impossible because a caller cannot know the true class of an object, > and therefore cannot know which method to call. In practical terms early binding is often quite possible and useful, and can be done transparently (no extra effort by the programmer). This is because the compiler, if written properly, can often know the class of a given object. Sometimes it cannot, sometimes it can. I say why not use this information to advantage? -Doug
[toc] | [prev] | [next] | [standalone]
| From | Andrew Haley <andrew29@littlepinkcloud.invalid> |
|---|---|
| Date | 2013-11-27 11:58 -0600 |
| Message-ID | <iqudnZGSPslGrwvPnZ2dnUVZ_gydnZ2d@supernews.com> |
| In reply to | #26998 |
Doug Hoffman <glidedog@gmail.com> wrote: > On 11/26/13 6:11 PM, Andrew Haley wrote: > >> Sorry, you've lost me. First you say that an instance variable can't >> be a subclass > > Where did I say that? > >> , then that it can. > > If the instance variable is a *container*, then that container can hold > an object of *any* class, subclass or not. Re-read my original post for > this thread. Item 4), 2nd to last sentence. Hmm, I see. So, a container can contain anything, but an instance variable can't contain any instance other than whatever it was declared to contain. But this still seems to me to be a pain: one of the basic simplifying assumptions of OO is that wherever you see an X, you can also use a subclass of X. i.e. if Class Y is a subclass of Class X, then a Y is an X in every way that a caller cares about. Its internal implementation may be different,and it may have extra functionality, but it's still an X. >> OK, let me try to be clear what I mean about reuse. >> >> The subclass relationship is that wherever an instance of Class X >> appears in a program, a subclass Y of Class X may be substituted >> without alteration to that program. All methods of Class X that are >> overridden by Class Y will be called as appropriate. The programmer >> does not have to modify any program that uses Class X in order to use >> Class Y. > > Except using Class Y will break the program that was designed to use > Class X if any methods are changed(over ridden) which is usually the > case. It shouldn't do, as long as the contract of Class X isn't broken. That's a matter of good object-oriented design. If Class Y is a subclass of X, then it honours the contract of X. No program that is designed to use an X will break. If a class Y doesn't honour the contract of X, then it should not be a subclass of X. >> This means, in general, that early binding to an object's methods is >> impossible because a caller cannot know the true class of an object, >> and therefore cannot know which method to call. > > In practical terms early binding is often quite possible and useful, > and can be done transparently (no extra effort by the programmer). > This is because the compiler, if written properly, can often know > the class of a given object. Sometimes it cannot, sometimes it can. > I say why not use this information to advantage? That's the good kind of early binding. That's the kind everyone likes. The bad kind of early binding is the kind that restricts reuse. The problem here in c.l.f is usuelly that people don't clarify which kind they mean when they say "early binding". Good early binding is just an optimization that the system performs, transparently to the programmer. Bad early binding is what I've seen in some OO Forths where a method is early bound explicitly by the programmer at a call site in the knowledge that this will "always be an instance of Class X". It's just an accident waiting to happen. Andrew.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.forth
csiph-web