Exforsys
+ Reply to Thread
Page 2 of 3 FirstFirst 123 LastLast
Results 11 to 20 of 22

Re: Extends is evil?

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 ...

  1. #11
    =?ISO-8859-1?Q?Thomas_Gagn=E9?= Guest

    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





  2. #12
    Mark van Gulik Guest

    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].



  3. #13
    panu Guest

    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)





  4. #14
    Michael Lucas-Smith Guest

    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 +



  5. #15
    panu Guest

    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





  6. #16
    cstb Guest

    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 #atut: 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



  7. #17
    panu Guest

    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




  8. #18
    cstb Guest

    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



  9. #19
    Guillermo Schwarz Guest

    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
    > ------------------------------------------------------------------






  10. #20
    Carl Gundel Guest

    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



    •    Sponsored Ads



Latest Article

Network Security Risk Assessment and Measurement

Read More...