Exforsys

Free Training

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

Go Back   Exforsys > Testing > Software Patterns

Exforsys.com

  #11 (permalink)  
Old 08-14-2003, 10:21 AM
=?ISO-8859-1?Q?Thomas_Gagn=E9?=
Guest
 
Posts: n/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


Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Sponsored Links
  #12 (permalink)  
Old 08-15-2003, 02:46 AM
Mark van Gulik
Guest
 
Posts: n/a
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].
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #13 (permalink)  
Old 08-19-2003, 01:11 AM
panu
Guest
 
Posts: n/a
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)


Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #14 (permalink)  
Old 08-19-2003, 02:21 AM
Michael Lucas-Smith
Guest
 
Posts: n/a
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 +
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #15 (permalink)  
Old 08-19-2003, 10:55 AM
panu
Guest
 
Posts: n/a
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


Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #16 (permalink)  
Old 08-21-2003, 11:55 PM
cstb
Guest
 
Posts: n/a
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
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #17 (permalink)  
Old 08-23-2003, 03:47 PM
panu
Guest
 
Posts: n/a
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

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #18 (permalink)  
Old 08-24-2003, 12:38 AM
cstb
Guest
 
Posts: n/a
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
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #19 (permalink)  
Old 09-12-2003, 06:15 PM
Guillermo Schwarz
Guest
 
Posts: n/a
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
> ------------------------------------------------------------------



Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #20 (permalink)  
Old 09-13-2003, 08:43 PM
Carl Gundel
Guest
 
Posts: n/a
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
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply

Bookmarks

Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



All times are GMT -4. The time now is 08:55 PM.


Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.0
Copyright 2004 - 2009 Exforsys Inc. All rights reserved.