This is a discussion on Re: Extends is evil? within the Software Patterns forums, part of the Testing category; Mark van Gulik wrote: >Ok, OrderedCollection has these subclasses in VisualWorks 5i.2 (with >some parcels loaded): > -SortedCollection (probably a ...
|
|||||||
|
|||
|
Re: Extends is evil?
Mark van Gulik wrote: >Ok, OrderedCollection has these subclasses in VisualWorks 5i.2 (with >some parcels loaded): > -SortedCollection (probably a mistake) > -LinkedOrderedCollection (workable) > -FontDescriptionBundle (ChessClub) > -EncodedOrderedCollection (missing visitor pattern for literal >encoding) > -MessageHeaders (ChessClub) > -AHSPersistentOrderedCollection (should be generated code or >aspect) > >Similar nonsense exists in the Dictionary hierarchy. A trivial >example is CEnvironment, which (1) is a Dictionary that has strings >for its keys and values [oooh, ahhh], (2) is effectively a singleton >with a #postCopy method for some unknown reason, and (3) is a place to >put class methods that are directly and indirectly related to OS >environment variables. > > I'm missing what the problem is you're identifying. The base classes kinda stop after LinkedOrderedCollection. And what's the problem with SortedCollection? Why would that be a mistake. It's a collection of items that are created sorted, and additions to the collection are inserted in their sorted order. And why not implement CEnvironment as a Dictionary with special behavior? It sould have been a composed class but it works as a subclass too. What's wrong with that? -- ..tom remove email address' dashes for replies opensource middleware at <http://isectd.sourceforge.net> http://gagne.homedns.org |
| Sponsored Links |
|
|||
|
Re: Extends is evil? [long ramble]
Thomas Gagné <tgagne@wide-open-west.com> wrote in message news:<3F3B8CC3.4030605@wide-open-west.com>...
> Mark van Gulik wrote: > > >Ok, OrderedCollection has these subclasses in VisualWorks 5i.2 (with > >some parcels loaded): > > -SortedCollection (probably a mistake) > > -LinkedOrderedCollection (workable) > > -FontDescriptionBundle (ChessClub) > > -EncodedOrderedCollection (missing visitor pattern for literal > >encoding) > > -MessageHeaders (ChessClub) > > -AHSPersistentOrderedCollection (should be generated code or > >aspect) > > > >Similar nonsense exists in the Dictionary hierarchy. A trivial > >example is CEnvironment, which (1) is a Dictionary that has strings > >for its keys and values [oooh, ahhh], (2) is effectively a singleton > >with a #postCopy method for some unknown reason, and (3) is a place to > >put class methods that are directly and indirectly related to OS > >environment variables. > > > > > I'm missing what the problem is you're identifying. The base classes > kinda stop after LinkedOrderedCollection. And what's the problem with > SortedCollection? Why would that be a mistake. It's a collection of > items that are created sorted, and additions to the collection are > inserted in their sorted order. And why not implement CEnvironment as a > Dictionary with special behavior? It sould have been a composed class > but it works as a subclass too. What's wrong with that? The difference is that when you inherit from Dictionary you are re-exporting its entire interface, which is *completely* inappropriate. Furthermore, the hierarchy claims that CEnvironment is a *specialization* of Dictionary, but it fails this claim because it doesn't alter/extend the implementation of Dictionary (other than an unused #asStrings method, an inappropriate #postCopy method, and class side methods that should not be there). It's kind of unusual to argue against SortedCollection inheriting from OrderedCollection. However, SortedCollection "removes" the ability to perform random writes. While it may seem clever to inherit the good parts and "uninherit" the bad parts, what happens if the protocol in OrderedCollection is complicated and interwoven enough that you can't tell if it relies on the bad parts? And that's just the *implementor*'s problem. How about a client trying to *use* this half-headed beast? The other half of the argument is that a SortedCollection can not be passed when an OrderedCollection is expected. Another poster (cstb@pacbell.net) seems to think that C++'s joke of a type system is inadequate to support subtyping. I agree. I also agree that Java has most of the same problems -- it seems even worse for some things. However, the inadequacy of these type systems is hardly an argument against subtyping, any more than George Bush (substitute elected representative of your choice) is an argument against democracy. The fact that George and Java are what most people have should not affect *philosophy* of types (which is what we're discussing). For those that think tests are a substitute for sound types, consider this: The tests you write for OrderedCollection wouldn't work for SortedCollection. Why even have tests if they don't work with subclasses? You go to all the trouble to ensure some abstract class X meets its tests while the entire subtype hierarchy beneath it fails the tests. By design, no less. To rework OrderedCollection and SortedCollection to avoid improper subtyping, try this: ReadableOrderedCollection defines a protocol and OrderedCollection implements it. SortedCollection then properly inherits from ReadableOrderedCollection (because it meets its protocol). To avoid having two similar concrete representations, one can *additionally* implement SortedCollection via a reference to an OrderedCollection. While you may think this this solution is too tangled, consider that in some Smalltalks OrderedCollection contains a reference to an Array. Exemplary design - OrderedCollection cites Array instead of being its sequel. The existing hierarchy of Sequenceable versus Arrayed etc. is inappropriate because these are not abstractions: they're implementation constraints. Interval is not a valid subtype of SequenceableCollection -- maybe half of its supertype's operations actually work for it. Interval might, however, be a workable subtype of ReadableSequenceableColection. Smalltalk has a paucity of *mechanisms* for inheritance -- no multiple inheritance, no *structure* of any kind (e.g., no parametric types). Thus, the type of types you can construct is very limited. You can define a #sum operation in Collection, but you can't check a program to find places where a Collection of things other than ArithmeticValues are being passed. Tests must (should?) find that, but as I mentioned before, non-subtyping inheritance even foils the usefulness of tests. As I said in another post, multiple inheritance (and more complex type constructions) have their fate tied to strong typing. One without the other is a disaster. However, we are at the brink of possibly the largest refactoring ever to be attempted -- introducing both strong typing and complex type constructions like multiple inheritance into Smalltalk *at the same time*. I know the place exists, but I'm not sure you can get there from here. Java's not the answer because its type system doesn't have enough "structure". Maybe some day it will, or maybe it's just as stuck as Smalltalk for other reasons. Maybe Dave Simmons will pull it off. My suggested refactorings tend to favor separation of change and state, so maybe the functional crowd has the core answer. Maybe all of them can pull it off. One thing I'm pretty sure of is that if you can't safely reason about software you can't build big things that (A) work, and (B) continue to work if you do /this/ >bzzzt< [now you go guess what I changed - the tests alone won't tell you, nor will a type-check, nor will run-time assertions]. |
|
|||
|
Re: Extends is evil?
Anthony Lander wrote:
> panu wrote: say: "A set of people can be a *subset* of a ChessClub". > > > Actually, a chess club has a collection of people; The collection of people > is a part of the chess club. No different than an engine is part of a car. That seems to make sense, but ... Every *member* of the club is *a part of* it. Yet the "set of *all* members" is not *a part of* it. Why? We wouldn't say that the set of all members is in the same relation to the club as each individual member is. Just because each member is part of the club, we wouldn't say that the set of all (or some) members of the club *is* part of the club as well. Or if it is, then at least it is *part of* in a very different sense. Modeling with Collections is tricky. No wonder Bertrand Russel came up with his paradox. PART-OF and SUBSET-OF are clearly different relationships. However I'm unaware of any formal definition of PART-OF whereas SUBSET-OF and MEMBER-OF have a well-defined formal basis in set theory. Therefore I prefer using them over the more vague "part of". If a "collection of people is a part of the chess-club", then what might be its other parts? Would you say that "Bylaws of the club are *part* of the club"? This seems vague. Would every object "associated with" the club then be "part of it" as well, automatically? -Panu Viljamaa > > >>I gather what you're saying is that if there is a proper >>type-of relationship between two classes, /then/ it is ok >>(= safe) for the subtype to inherit implementation from >>its supertype. Right? > > > Code sharing and subtyping are orthogonal. You can have code sharing > relationships with no subtyping, and you can have subtyping relationships > with no code sharing. > > In Smalltalk, it so happens that there is only one hierarchy, namely the > code sharing hierarchy, which forces us to conflate code sharing and > subtyping. On the surface this looks like a compromise, but in reality it > is quite elegant: Code sharing (good for the implementor) and > substitutability (good for the user) are expressed in exactly the same data > structure! > > -anthony (a Wilfian dogmatist if ever there was one) |
|
|||
|
Re: Extends is evil?
On 19-Aug-2003, panu <panu@fcc.net> wrote: > Every *member* of the club is *a part of* it. > > Yet the "set of *all* members" is not *a part > of* it. Why? We wouldn't say that the set of > all members is in the same relation to the > club as each individual member is. That's not entirely true. That's an englishism where we've shortened what we're saying and the understanding is not lost. Every member of the club is just that, a member of the club. You are not a part of the club, the club is not comprised only of it's members - that's a humanism. The clubs members is made up of people, so people are a part of the clubs membership. In fact, people often hold a membership to a club, but are not actually 'part of' a club. + Language is tricky + |
|
|||
|
Re: Extends is evil?
Michael Lucas-Smith wrote:
> On 19-Aug-2003, panu <panu@fcc.net> wrote: ....We wouldn't say that the set of >>all members is in the same relation to the >>club as each individual member is. > > That's not entirely true. That's an englishism where we've shortened what > we're saying and the understanding is not lost. I think the meaning is more or less lost if it's more or less ambiguous. In English it is, but we're talking about how to translate a chess-club into an OO program. Of course we can say that "People will understand what we *meant*" but that's not the point. We all know what a chess-club is. Now what is the best way to represent it in OO, that's the question. > Every member of the club is just that, a member of the club. Right. But the *set of members* - seen as an object of its own - is not a member of the club. Right? English easily breaks down when we try to see our statements as describing a model to be build. Naturally if there is no intention of creating a software artifact, then the vagueness of English doesn't matter. > You are not a part of the club, the club is not comprised only of it's > members - that's a humanism. The clubs members is made up of people, so > people are a part of the clubs membership. In fact, people often hold a > membership to a club, but are not actually 'part of' a club. This just pinpoints the vagueness again. What is the difference between having a membership and being part of the club? In English these may have different connotations, but we're trying to state the problem in OO terms here. To do that most analysts will strive to simplify the real world descriptions of a chess-club, into having just one kind of "being member". > + Language is tricky + Depends on the language. English is tricky, Smalltalk is not. -Panu Viljamaa |
|
|||
|
Re: Extends is evil? [long ramble][long woven reply][hot shots-partdeaux]
Mark van Gulik wrote: > >cstb@pacbell.net > > >...snip... > > implementers have in effect created multiple, incompatible > > protocols through the 'accident' of implementing behavior > > based on what can be done efficiently for each particular case, > > rather than implementing one protocol polymorphically, ...snip... > > Yes. Does this count as an anti-pattern, or is it broader > than that? Maybe "Focused on how instead of what"? > "Context over Essense"? "Form over Function"? "YA[re]GNI"? As anti-pattern, its a variant of premature optimization. But anti-pattern doesn't really fit - the collection hierarchy as-is wasn't constructed to solve a problem in a context, rather it is synthesized from various solutions, and has evolved over time, forming collections of solutions that solve widely varied problems in widely varied contexts. Only when you step back and look at the totality of the current hierarchy is it clear that a unifying principle would improve it even further. In comparison, the equivalent of "collection hierarchy" in most other languages is mostly missing and without any apparent structure, polymorphic or otherwise. One fascinating aspect of Smalltalk is that it seems to guide even the discovery of how to improve its own implementation. [complete BS, but a useful fiction for PR purposes -ed] I don't recall ever having the experience of, say, looking at large chunks of C libraries, and exclaiming: "Wow! Look at this - its nearly brilliant ;-). Just needs another pass, applying its own principles, and look what we'll get!" > > I'm all for protocols, as long as you can attach code to them (having > tools to *mechanically* reason about them is nice, too). Right. Dolphin has started exploring the former, for example. > if you have an Orderable protocol which Magnitude and String can > choose to implement, then you shouldn't have to implement > #between:and: in both places (and everywhere else). Why not? If I can *write* it once, then ditto the implementation into any class that wants to 'implement' it {unchanged}, I get the same advantage (OAOO). What's missing is that protocols are not first class - they currently have no runtime representation or behavior (except in Dolphin). >...snip... > > If the protocol is for read-like access then this can work, but > Smalltalk isn't normally structured into these protocols. For > example, the #at: and #at ut: methods of OrderedCollection are both> in the category "accessing". Categories are not protocols - that's a misnomer on the part of one vendor. Protocols need to be first class. >...snip... > > protocols are hardly a description of a system instance. > They are a description of "code". Thus, they are a static > description. It is their static nature that is useful. Your notion > of protocol is simply my notion of static type. Ok. (I'll suggest that changing your nomenclature would be a plus - the overloaded meaning misleads; the contexts overlap. ) >...snip... > > if you don't have a subtyping relationship between > ReadableOrderedCollection and OrderedCollection, then behavior like > "reversed" or "asArray" can't be defined in one-and-only-one place. Sure it can: 1) In Collection (the usual place) 2) In Object (the preferred place) > Hence the code smell of singular (and zero) *inheritance*. > > Alternatively, if you allow protocols fullfilment and implementation > inheritance to diverge, I don't believe you can (A) correctly reason > in the absence of complete source code, and (B) determine the scope > of a change, even of a pure implementation method. Perhaps this is just nomenclature again, but I'm confining the term 'inheritance' to the super-sub class hierarchy. Hence, protocols could be 'inherited' from the super chain, and also 'mixed-in' (copied) from the 'reference implementation', as well as fulfilled but reimplemented in-situ. >...snip... > > I assert it is impossible unless obligations exactly > match benefits. Thus, the obligations (protocol fullfilment) must > correspond with the benefits (protocol-method inheritance). Protocol obligations are fulfilled by reference, inheritance, or reimplementation. Benefits are derivable from cross-pollination as well as from inheritance - benefits can (should) extend by way of interface-set-membership, rather than constrained to inheritance through the class hierarchy. [Still hierarchical, and inheritable, but from the protocol hierarchy. The two (class and protocol) hierarchies intersect in multiple places, yet are not synonymous. The class hierarchy (code reuse) is seen to be a proper subset of the protocol hierarchy (behavior reuse), hence protocols are more powerful than classes. ] > Refinement of protocols is another feature one would be foolish to > live without. It doesn't make much sense to be able to define a > protocol like ReadableOrderedCollection without being able to refine > it to "ReadableAndRandomWritableOrderedCollection". If by 'refinement' you mean 'a convenient notation and tools' so that one can define new protocols by reference: protocolB ::= protocolA + {additional selectors} and be systematically assured that all protocols are unique, sure. > > > >SortedCollection then properly > > > inherits from ...(wrong answer snipped)... > > > > ...anything the implementers choose, because the controlling idea > > is -implements the protocol-, not -inherits from some particular > > place-. > > They're inseparable because of the symmetric nature of the contract > (assuming the protocol can provide actual functionality). Not! Obligation occurs with respect to the protocol hierarchy, whereas implementation occurs with respect to the class hierarchy. > ...snip... > > I don't know where the fallacy of separable hierarchies came about, > but I have yet to see anything useful added to the literature > as a consequence. Strongtalk appears (to me) equivalent to what I'm describing, and is published. There may be room for expounding further though. > I'm certain Java's > protocol-ish type system was only implemented as a stop gap measure > to avoid being *completely* crippled by single inheritance, without > spending vast fortunes getting a C++-ish multiple inheritance model > operational. And it is far less powerful, *because* it is tied to the bumper of a statically typed vehicle. > > > Inheritance is (in Smalltalk) an implementation detail. > > Unlike a statically typed language, where inheritance has effects > > which are forcibly exposed, in Smalltalk they can all be > > encapsulated. > > [They aren't, always, but they can be. And should be]. > > Correct, *except* for code duplication. Note that code duplication > snowballs when a poorly supported or poorly trained programmer, regardless of > protocol attempts to actually > provide something (i.e., behavior). Why would anyone use a protocol > system in which ...snipped... No reason to. Again, the only protocol *system* I've seen implemented so far is that of Strongtalk. > >...snip... implementation details ...snip... > > unless I get some useful property as a result of this choice. > > > >...snip... > > The issue is obvious. (Safe) code reuse. See also modularity. Ok. But like tennis shoe sniffing at the airport, constraints can and should be relaxed, if they don't provide actually increased safety. > ... snip ... > > > > Interval might, however, be a workable subtype > > > of ReadableSequenceableColection. > > > > Not a terribly useful notion, in any case. > > Huh? It's the whole premise of Interval being a collection in the > first place! .. snip ... I should have elaborated here. Not terribly useful, as compared to supporting the full collectionProtocol. *Part* of its implementation might benefit from immutability, but not Interval as a whole. That's the premature optimization thing again, seems to me. The more interesting properties of Interval as collection are o known to have a dense representation o known to be a monotonically increasing discrete (sub)range In the general case, I don't see much advantage to branching the protocol hierarchy at 'Sequenceable', as 'sequence' constraints arise from how/why the collection is enumerated, not from how it is implemented. Are there boundary conditions/ordering dependencies at play in the algorithm which is driving this enumeration? Each *use* of enumeration should make this distinction. Some implementations of collection really need to supply distinct variants of enumeration, while other collections do not. {An implementation might fail to provide the full collection protocol - we might call this a 'feature', but it isn't a 'property'.} > > ..snip... > > > non-subtyping inheritance even foils the > > > usefulness of tests. > > ...snip... > > but rather that > > >>canSum > > ^(self allSatisfy: [:elt| elt understandsArithmetic]) > > is true whenever the collections of interest to the system under > > test are sent the message #sum. > > At first this seemed an interesting point, encapsulating the > structure ...snip... In this case the double-dispatch is > probably inappropriate, to do this: aRuntimeObject>>calculateTotal someCollection canSum ifFalse: [^self errorBadContents]. ^someCollection sum but probably ok to do this: TestCaseSubclass>>testSumability fixture := SomeCollection loadedFrom: someSource. self assert: fixture canSum although neither is my preferred path. Similarly, your suggestion > as a named structured type > (i.e., "Summable ::= Collection of ArithmeticValue") not only > solves the problem but names the abstraction. is an improvement over the god awful statically typed collection contents approach, but again misses the mark. In detail - If I actually want to be assured of a container that has only arithmetic values, there are two ways to do this without static types: 1) Verify the constructed contents at key points prior to use (the canSum) approach 2) Verify that the construction process allows only arithmetic values to be added. (equivalent to net result of a named structured type, or of any container with statically typed contents ) Ideally, we'll pick (2), as the error is caught closest to its source, and the overhead is incurred just once. So the extra 'typing' is just allowing us to 'trust' the *contents* of a passed-in container, without seeing the client code. The problem is this - I now have a name that guarantees sumability. It even says so. But that isn't what I actually want. Why? Too specific. I'll need billions of these things. In this example, what I probably want to ensure (without realizing it yet - too early/not enough refactoring) is that the thing 'passed-in' is reducibleToArithmeticValue. Because if it is, I can treat the parameter as a composite - so if I ask it to plus-reduce, and it *is* anArithmeticValue (scalar) -> it answers itself, otherwise, it sums itself and answers the sum. Hence, the protocol I'm after is #reducibleToArithmeticValue, and said protocol is *not* a named structured type. I claim that, in general: Protocols are not obtained via the composition of named types. Protocols must be 'learned', i.e. discovered, and then implemented on purpose. Static typing leads one to believe that the phenomenon of accidental success (named composition yielding useful results) is 'the way' to go about extending; Hey, it works. [ Equations of the form {ax^2 + by^2 = 0} can be solved by selecting {x=0, y=0}; Hey, it works. ] Static typing sends the developer down the rat hole of over-specification, leading to premature optimization, and over time, to exceptionally brittle (aka static) systems. > Your #canSum is completely inappropriate, since it neither part > of a protocol nor part of an implementation. Right - it is only there because I'm developing test first. It is part of the testing protocol, and otherwise unused. > *Every* collection must understand it (and therefore > implement it), regardless of the protocols those collections > purport to support. If we push #sum up to Collection, yes. Otherwise, just those onto which #sum has been grafted. We seem to agree it was a bad idea - I was eliminating your criteria for badness, to force using mine ;-) > Thus, only by building things *outside* your type system > can you support this apparently simple concept. Either reductio ad > absurdum, or this simple concept can not be safely typed (like Arrays > in Java). Umm - not my type system, just my response of a way of getting results beyond what you suggested was possible in a hypothetical situation. In order to hone our arguments. > > > > ..snip ... > > > multiple inheritance (and more complex type constructions) > > > have their fate tied to strong typing. One without the > > > other is a disaster. > > > > Static typing - yes. > > But one with the other is also a disaster, so no harm done, right? > > ;-} > > Most implementations of both have been disasters, Agreed. > but I believe (1) a > proper synthesis is possible, Q: Having worked through the above, do you still believe it? > and (2) I have produced the core of such > a viable synthesis in Avail. The key has almost nothing to do with > how little or how much functionality to include, but rather *which* > meta-abstractions produce the right kinds of systems. Sort of like > almost ignoring the axioms but choosing the substitution rules with > great care. I'd like to see it - can you email some links/reference material? Thanks Mark - a lot of work to get through, but a wonderful exploration, and useful exchange. Regards, -cstb |
|
|||
|
Protocols as Contracts Re: Extends is evil? [long ramble][long wovenreply]
Mark van Gulik wrote:
> I'm all for protocols, as long as you can attach code to them (having > tools to *mechanically* reason about them is nice, too). I agree. In Smalltalk you have *abstract classes* which serve the role of 'protocol' or 'interface'. In Java you can define Interfaces, but you can't attach code to them. In my opinion (and yours I believe) it's better to have the protocol objects do some useful work as well: offering their inheritable methods as 'default implementations' to the concrete subclasses. There's a few different ways to define what is an abstract class: 1) A class which is never instantiated 2) A class which can not be instantiated 3) A class without instance variables. The last definition (3) may be my own, and you may in fact want to call it something else - "Stateless Class" for instance. The important thing about all 3 types of classes above is that *none of them carry state* - and /therefore/ they can be interpreted as representing *contracts*. Thus they can be used for the same purpose as an interface or 'protocol' would be. Whether your subclass 'obeys' the contract represented by its (abstract) superclass is another matter. My position is: if you say it does, then there exists a contract between you and me. If you can convince me to enter into this contract with you, good enough. Naturally any automated type-inference support will be useful to convince me that you are standing by your contract. Basically this 'programming paradigm' can be stated as: "There can be no contracts between software components - only between programmers who create the components". -Panu Viljamaa |
|
|||
|
Re: Protocols as Contracts Re: Extends is evil? [long ramble][longwovenreply]
panu wrote: > > Mark van Gulik wrote: > > > I'm all for protocols, as long as you can attach code to them > > (having tools to *mechanically* reason about them is nice, too). > > I agree. In Smalltalk you have *abstract classes* > which serve the role of 'protocol' or 'interface'. An Abstract class could serve *in* the role of *a* protocol, but must first be augmented to support the 'protocol' protocol. > > In Java you can define Interfaces, but you can't > attach code to them. In my opinion (and yours I > believe) it's better to have the protocol objects > do some useful work as well: offering their inheritable > methods as 'default implementations' to the concrete > subclasses. Can't speak for Mark, but I agree. A protocol should offer its methodSelectors to *any* class (subclasses just get them *for free*) and in several variations, nominally: o copyAsSubclassResponsibility o copyAsTBD o copyReferenceImplementation such that the initial selection of copyRule is retained, and utilized in the future to auto-generate implementations of any new methods added to the protocol. (See Dolphin for an almost-but-not-quite example). > > ... a few different ways to define what is > an abstract class ... snipped ... > > Naturally any automated type-inference support > will be useful to convince me that you are > standing by your contract. Inference isn't really needed for this, as a class should normally 'declare' that it supports a protocol: >>respondsToProtocolX ^true and/or >>respondsTo: aProtocol ^self supportedProtocols includes: aProtocol but a default implementation of Object>>respondsTo: aProtocol ^aProtocol selectors allSatisfy: [:each| self respondsToSelector: each] might be nice (especially during development). Protocol inference is useful for determining the *one* protocol which most fully characterizes the result of a message sent to a particular receiver. I say 'most fully', because the resulting protocol is not, in general, statically determinable, but becomes knowable with increasing accuracy as execution proceeds. I say 'knowable', because the partial results of inference could be cached/merged over the lifetime of an object, and if they were, the completely descriptive protocol would eventually be discovered. The current {even if partial} state of protocol discovery could be useful in development, as back propagation would allow each parameter of a method to display its currently-known-protocol (as a tool-tip would be cool), until the developer is confident enough to freeze the protocol into a contractual requirement. {RB does some of this, but doesn't bring it to the surface}. -cstb |
|
|||
|
Re: Extends is evil?
"Carl E Gundel" <carlg@shell01.TheWorld.com> escribió en el mensaje news:bhc3bl$iok$1@pcls4.std.com... > Guillermo Schwarz <guillermo_schwarz@hotmail.com> wrote: > > : "Peter van Rooijen" <peter@vanrooijen.com> escribi en el mensaje > :> > :> It seems that there is some confusion over what the term "implementation > :> inheritance" actually means. > :> > :> Implementation inheritance refers to the situation where one class > : inherits > :> another, without a resonable subtyping relationship between the two. > :> > :> An example would be to think that a chess club is a set of people, and > :> translating that into defining a class ChessClub that inherits Set. > > : Why? It has a set of people, why would that be a problem? > > The ChessClub should have an instance variable to hold the collection. > The Set (or whatever kind of collection you wish to use) of people is just > one attribute of ChessClub. > > What if I have a subclass of ChessClub and I want to use some other kind > of collection other than Set (a Dictionary maybe, or some sort of > persistence managed store for example)? That's the main accepted reason not to use implementation inheritance, but aggregation. > Do I add an instance variable to > my subclass of Set to hold this special kind of collection? Get's ugly. > If the instance of set is in an ivar, I can change it to whatever I like. Exactly! > Also, maybe my ChessClub has no need for all the semantic baggage of Set > (more than 60 methods in the flavor of Smalltalk I use). Exactly the opposite. A ChessClub is a set anyway, if I can do any operation on a set (union, intersection, etc.) I want to instantly have it available in ChessClub. Having to redefine a method on demand once a while is not bad, but it can become tiresome. Cheers, Guillermo. > > -Carl > ------------------------------------------------------------------ > Carl Gundel carlg@libertybasic.com Shoptalk Systems > author of Liberty BASIC, twice a PC Magazine Awards Finalist! > http://www.libertybasic.com > ------------------------------------------------------------------ |
|
|||
|
Re: Extends is evil?
"Guillermo Schwarz" <guillermo_schwarz@hotmail.com> wrote in message news:<3f623ffe@news.totallyobjects.com>...
> "Carl E Gundel" <carlg@shell01.TheWorld.com> escribió en el mensaje > news:bhc3bl$iok$1@pcls4.std.com... > > > > Also, maybe my ChessClub has no need for all the semantic baggage of Set > > (more than 60 methods in the flavor of Smalltalk I use). > > Exactly the opposite. A ChessClub is a set anyway, if I can do any operation > on a set (union, intersection, etc.) I want to instantly have it available > in ChessClub. Having to redefine a method on demand once a while is not bad, > but it can become tiresome. Perhaps ChessClub isn't a Set, but a Club. If I compute the union of two clubs, should this return yet another instance of club? Smells wrong to me. If I need to perform set arithmetic on the members of two ChessClubs, I'll just stick each club's membership in a new Set, and go at it. Of course if I already have an instance variable in my ChessClub object which holds a Set of my members, it gets easier. ;-) -Carl |
![]() |
| Bookmarks |
| Thread Tools | Search this Thread |
|
|