From: H. S. Lahman on
Responding to Bouma...

>>> Isn't that somewhat like bending reality to meet a certain
>>>definition D of said reality? Because I find the requirement to
>>>implement type definitions only at the leaf level too restrictive,
>>>and to me it seems this requirement is invented not to be practical
>>>but to be able to meet a given principle's demands.
>>
>>The primary goal of the OO paradigm is to provide software that is
>>maintainable in the face of volatile requirements over time. The
>>debates over LSP themselves demonstrate that polymorphic dispatch in
>>generalization structures is fragile, especially during maintenance.
>>Practical experience has indicated that implementation inheritance is
>>especially prone to foot-shooting during maintenance.
>>
>>That's because overrides add an addition dimension to resolving
>>object properties. Without overrides the client can safely access
>>the generalization structure at the highest level when a
>>responsibility appears -- always. To provide a client collaboration
>>the developer only needs to understand what the superclass'
>>responsibility semantics are.
>>
>>In contrast, with overrides the developer must understand the entire
>>tree and _where the overrides are located_. For example:
>>
>> [Service]
>> + doIt()
>> A
>> |
>> +--------+--------+
>> | |
>> [ServiceA1] [ServiceB1]
>> <+ overrideA>
>> A
>> |
>> +-------+-------+
>> | |
>>[ServiceA11] [ServiceA12]
>>
>>The fact that the override exists for [ServiceA1] indicates that the
>>behavior Service.doIt is unacceptable for that limb of the tree. One
>>already has an LSP problem because that notion of 'unacceptable'
>>already says that Service.doIt and ServiceA1.doIt are not
>>substitutable. That lack of substitutability is what forces the
>>developer to understand the whole tree when deciding where a
>>collaboration should access the tree.
>
>
> I see your point when you look at the material from the POV you're
> describing, however what about this:
> at the point of ServiceA1, the TYPE ServiceA1 requires a specialization
> of doIt(), the original doesn't fit in anymore. IMHO that's tied to the
> TYPE ServiceA1. If you're using a ServiceA1 type, you thus know what
> that type implies and does, how else would you decide which type to
> use? So if ServiceA1 documents that it overrides doIt(), you therefore
> know it has its own implementation of doIt. If you NEED the
> implementation of the superclass, don't use ServiceA1.

I don't think the issue is about types at all. The example I provided
is a Class Model from OOA/D where there are no types (other than
attribute ADTs).

Your last sentence is the key point here. Whoever provides the client
collaboration must understand where the overrides are done in the tree
to access it properly, which adds a dimension of complexity to defining
the collaboration. That, in turn, segues to the maintenance
foot-shooting...

>>Let's assume that only ServiceA1.doIt is acceptable to a particular
>>client, the developer implements the collaboration only with members
>>of the [ServiceA1] set.
>>
>>Now let's assume that some maintenance is done:
>>
>> [Service]
>> + doIt()
>> A
>> |
>> +--------+--------+
>> | |
>> [ServiceA1] [ServiceB1]
>> A
>> |
>> +-----+--------------+
>> | |
>>[Intermediate] [ServiceA13]
>><+ overrideA>
>> A
>> |
>> +-----------------+
>> | |
>>[ServiceA11] [ServiceA12]
>>
>>This has immediately broken the original client accessing [ServiceA1]
>>because it can now access ServiceA13.doIt, which will have the
>>unacceptable Service.doIt behavior. IOW, when the maintenance was
>>done the access of the collaboration should have been modified to
>>access only members of the [Intermediate] set.
>
>
> Yes sure it has broken it, but didn't ServiceA1 change? Didn't the
> behavior of ServiceA1.doIt() change? It did. Because it did, the TYPE
> ServiceA1 changed, because as I described above, ServiceA1.doIt()
> apparently needed a different implementation because the TYPE suggested
> it. Changing that, by factoring it out to another class, changes the
> TYPE, and therefore you can't use the same lib with the same client,
> need to bounce the version number.

The problem is that when maintenance was done ServiceA1.doIt() /did/
change. But the change was invisible to the client. It was also
invisible to the maintainer unless the maintainer actually checked the
collaboration context.

>>That means that whenever one changes the level at which overrides are
>>done one must go an check every client context to see whether they
>>have been broken. That is a major no-no for efficient maintenance
>>and it opens up a lot of opportunities for defects.
>
>
> That's not necessary: because the Type has changed, they're broken by
> definition. You then have to test again indeed if they're working with
> the new lib. But that's required anyway, because unittests will show
> that your new lib, with the new classes will fail your tests because
> the behavior of a method in a shipped interface has changed.

You are placing a lot of faith in your test suite. B-) As I pointed
out these sorts of problems can be very subtle and infrequent so testing
is problematic. You never want to rely on solely testing for product
quality, so you have to go and check every client context.

>>Problems with this sort of thing can be quite subtle and intermittent,
>>which makes
>>diagnosis tricky and increases the cost of repair. For that reason
>>most shops have decided to sacrifice the convenience of
>>implementation inheritance to avoid downstream maintenance headaches
>>and field escapes.
>
>
> Well, it depends on your language of course. In java for example,
> where every method is virtual unless stated otherwise, you will run
> into this more often than in other languages where virtual methods are
> a decision made by the library writer.

The language makes no difference. Th
From: ulf on
H. S. Lahman wrote:
> Responding to Ulf...
>
> > IMHO, a class system is - on the right level of abstraction - a type
> > system in the second sense.

IOW, a class system is a system of types.

> [Class systems and type systems]
> are obviously unambiguously mappable because they share property
> sets, but I don't think they are the same thing. Class systems are
> about member identity and classification while type systems are about
> interfaces and access.

But types are about classification! - Classification of "values" in
some sense.
Cf. Cardelli & Wegner's "On understanding types, data abstraction and
polymorphism".
Hence a system-of-types (type system) is about classification. Types
talking about interfaces is just a means for classification where the
"values" are objects. Isn't the same done in class system's where
objects are classified (among others!) based on their message
interface?

Last time I checked, UML included access specification for members as
part of the class model. Do you mean they can be in the class model but
not in the class system? Then I would seem to need from you a
definition what you mean by a class system.

>From type theory I can tell you that access specifications are only
relevant in the system-of-typing-rules (type system 1st sense) for
determining which accesses are type correct. They are usually not
represented in the system-of-types (type system 2nd sense) - but maybe
they better should?

So maybe after all you are right and here is a difference between class
systems and type systems (in the sense of system-of-types)? - just that
it is the other way around than you thought :)

Could you elaborate in what sense class systems "are about member
identity"?

> For example, one cannot deal with class systems
> without talking explicitly about sets ... while one can
> easily talk about types systems without mentioning sets at all.

If I claim "Carnivore is a specialization of Animal" - where is there
the "explicit" talk about sets? Or does this not fall under "dealing"
with a class system?

Of course you may talk about type systems without mentioning sets. But
the standard way to make exact statements and research about type
systems is based on formalizing a type as a set S of "values" (this set
is the meaning of the type identifier t: [[t]] = S). And these sets can
be defined so that if t' is (or rather identifies) a subtype of t then
[[t']] is a subset of [[t]] (known as the Ideal model?).


Conclusion from my point of view (sorry for the mixed up table layout):

______________________| class system | system-of-types
purpose: classification | + | +
use: interfaces | + | +
specify access | + (-?) | - (+?)
basis: sets | + | +


Regards,
Ulf Sch√ľnemann

From: ulf on
H. S. Lahman wrote:
> Responding to Ulf...
> ...
> > I feel sth is going wrong in this discussion.
>
> sth means???

sth = something

> > 1. Could it be that in order to understand and evaluate your argument
> > it is indispensible for me to exactly know what you mean by a
> > "responsibility"? It must be sth linguistic for it has a meaning
> > ("semantics of a responsibility") and it must have an existence at
> > runtime ("clients may invoke them one a peer-to-peer basis") ...
>
> Responsibilities are basic OO properties. All object properties are
> defined in terms either [of] a responsibility for knowledge or a
> responsibility for behavior.

a. Responsibilities *are* (basic) properties
b. Properties are *defined* in terms of responsibilities (for
knowledge/behavior)
-----------------------
c. => Responsibilities are defined in terms of responsibilities ... ?

You must have meant:
b'. All *other* properties are defined in terms of responsibilities.

And in terms of what is a responsibility defined then? How is it
captured in the UML model?

My understanding was rather that properties *realize/implement*
responsibilities.

> IOW, objects are defined in terms of What
> they should know and/or What they should be able to do.

Of course. Or as I like to say it:
The dual nature of the object abstraction = data abstraction +
behavioral abstraction.


> > 2. To me it seems that you are effectively saying: If one models an
> > object's behavior upon receipt of a message m in a class X then one
> > cannot model it again in subclass Y. I have not seen a constraint to
> > this effect in the UML specification, and I have never heard of a
> > design guideline to that effect. It must be possible to refine the
> > modeling of a behavior from a more general, unspecific model in the
> > superclass context to a more specific, refined model in the context of
> > the subclass. Of course the magic word here is *refine*. ...
>
> ...
>
> However, the semantics of WHAT the responsibilities are cannot be
> multiply defined. That is, the object cannot be a member of two sets
> where the property is defined differently (i.e., in a conflicting
> manner).

Just to verify: From the following choices yours is (a), right?

a. There can be no two places/sets where the same
responsibility/property is defined.
b. There can be two places/sets but the definitions cannot be
different.
c. There can be two places/sets, the definitions can be different,
but not in a conflicting manner.

Whereas I was considering choice c.
Does anyone reading this know what the UML 2 spec is saying here?

---
> ...
>
> What I think you are talking about here (specific refinement from a
> generalization) are different implementations of the same responsibility
> semantics.

I considered the possibility of refinement specification->specification
(in the OOA/D model), not the realization/implementation of a
specification.
Maybe I should point out that I am used from OOPLs to opposing
specification/design to implementation (= what you do in the
implementation phase = implementation of the design). For an
implementation relationship within the model (not the model of a
PL-implementation) I prefer the UML term "realization".

"Implementation/realization of a responsibility/property" (for
knowing/doing) I understand. What opposed to this is an "implementation
of a responsibility semantics"? When are two responsibility
semanticses[?] the same?

> Thus I can implement a responsibility to sort a list of
> values in ascending order with a bubble sort, an insertion sort, a
> Quicksort, or any other sort algorithm in different subclasses.

Classical example.

> Similarly, I can implement a responsibility to compute withholding tax
> differently for a SalariedEmployee subclass than for a sibling
> HourlyEmployee subclass. But in both cases the semantics of the
> responsibility is exactly the same from the perspective of an external
> client for each implementation pair.

If there is only one definition of the responsibility, as you insist,
then its semantics should automatically be unique. Did you mean:

But in both cases the semantics of the *implementation* of the
responsibility is exactly the same from the perspective of an external
client ...

> Thus in an OO context LSP comes down to ensuring that the superclass
> responsibility semantics is defined with sufficient detail to be useful
> to clients while also ensuring sufficient generality so that it is
> consistent with all the subclass implementations.

I basically agreed if I could replace "responsibility semantics" to
"specification of behavior" or "modelling of actual behavior".

> ...

> >><example of Predator and Prey>
> ...
>
> In fact, that is pretty much exactly what OOA/D does when it separates
> message and method. ...
> The expectation of what /should/ happen is really at a higher level of
> abstraction than either [Predator] or [Prey]. ...
> Nor does the contract does not exist in isolation. ...

We are d'accord here.


The rest I'll have to answer another time.


Ulf Sch√ľnemann

From: ulf on
H. S. Lahman wrote:
> ...
> But the object's state does not affect substitutability.

I beg to differ. But slowly:

(1) To me: Object's state includes the current value of its attributes.
There may be more aspects (like modeled in the state machine), but only
the attribute aspects matters in my argument.
[Sidenote: Note that the far link-end(s) of an object's links may be
mapped to attribute(s) of that object.]

Do you agree?

(2) Obviously: Depending on the current attribute values, an object's
operations' semantics may be specified and/or implemented by a method.
In particular, the result of an operation/method may depend on the
current attribute values. IOW operation results depend on object state.

(3) Liskov and Wing suggest in a section about history properties:
Substitutability in their definition (LSP-subsititutability) is
affected -- even if the semantics (or implementation, as you like) of a
superclass's operation is NOT overridden! -- if new operations in the
subclass change attributes inherited from the superclass in a way that
operations of the superclass never did.

Do you believe my report about what is in Liskov&Wing's paper?
Do you agree with Liskov&Wing's suggestion?

By 1 + 2 + 3, I feel confortable saying

(A) The object's state does affect LSP-substitutability.

It would also be right to say:

(B) LSP-substitutability is affected by the set of (attribute) states
an object can reach from a given attribute state by any possible
sequence of supported state-mutating messages sent to it by any
possible environment.

> ... I was
> responding to your suggestion that substitutability could somehow be
> affected by the sequence of (history of) messages an object receives:
> ...

I want to reaffirm this. See B above for a rephrasing. I don't know how
otherwise to help you understand loss LSP-substitutability caused by
non-preservation of history properties.

> <snip>
>
> I think state variable values are a red herring. The values change the
> results of executing the responsibility based on dynamic context, not
> what the responsibility /is/.

Certainly.

> In the example above, specifying a responsibility to sort a list of
> integers in ascending order does not depend in any way on what the
> values are. ...

"not in any way"? You can you specify that the list is sorted in the
end without looking at the values in the list?


> >>They can only affect
> >>substitutability indirectly by determining how relationships are
> >>instantiated.
> >
> > ?
>
> Substitutability in an OO generalization employs relationship
> instantiation as the mechanism by which objects from different
> subclasses are substituted. ...
> This is really very fundamental OOA/D. ...

OK - You did not suggest anything fancy like different mechanisms of
relationship instantiation but simply instantiation *with participants
of different classes*. All right, forget it.

> ...
> >>Does what a
> >>behavior does depend in any way on what some other behavior does?
> >
> > Sounds odd to talk of a behavior _doing_ sth. In normal seach the
> > behavior _is_ the doing. Do you mean a behavior = a method? Maybe we
> > should distinguish actual behavior (the doing) from behavior = method
> > (the definition/implementation of what to do)?
>
> In the OO paradigm a method implements a behavior responsibility.

I thought in the OO paradigm one says a method implements an operation
(or maybe even in some indirect sense implements a message).

> The responsibility defines what the method should do.

Hm. That seems different to "operation". One wouldn't say
The operation defines what the method should do (or would one?)

> IOW, responsibility = What; method = How.

And generally, What : How = specification : implementation.
We are getting close to an answer what a responsibility is, I think:
A responsibility is like a specification to be implemented by a method.

OTOH you said that a responsibility is a (basic) object property. AFAIK
a method is also a property. Hence the specification and its
implementation are both properties of the object (there are two
properties)? Very interesting.

> ...
> >>In a well-formed OO application the answer is always No.
> >>
> >>[Obviously the /results/ of executing a behavior depends upon what the
> >>current values of the state variables are.
> >
> >
> > I disagree with the No.
>
> Alas, that is the way the paradigm works. Nothing much either of us can
> do about that. B-)

Where in the elaboration of my No do you or does the paradigm disagree?

> > In my view, what result a method calculates (and returns) is part of
> > "what it does" (the actual behavior). And this result can depend on
> > other results. Hence what one method does [in one invocation] may
> > indeed depend in some away on what some other method did [in a nested
> > invocation].

Are you suggesting I have no well-formed OO application if it includes
a method whose result depends on the result of another method [which,
as we agree, may depend on the object's state variables' current
values]???

> Recall my example of a state machine. The action associated with a
> state can depend upon nothing but the input alphabet.

[Maybe discussing how to talk about state machines is not necessary for
the actual subject, but in case it is:]

<pedantic>
I thought for a state machine there is one part of its definition
called "input alphabet", namely the set of talked about input symbols.
For each state there is a subset of this set, namely the set of input
symbols accepted in this state.

Do you mean the action depends on the definition of the
alphabet/acceptable subset (static) or on the actual input symbol
(dynamic)?

> It modifies that alphabet

An action in the state machine modifies a part of the _definition_ of
that state machine?
Do you mean: The actual input symbol selects a transition (which
triggers an action and) which may lead to another state with a
different subset of acceptable inputs?

> but it cannot depend upon what other actions have done or will do;
> it only depends upon the current state of the alphabet values it is
> handed.

I would say: An action in the state machine depends only on the actual
input symbol.
Side note: Which action is triggered by a particular input symbol
depends on the current state. The current state depends on the
pr
From: H. S. Lahman on
Responding to Ulf...

>>>1. Could it be that in order to understand and evaluate your argument
>>>it is indispensible for me to exactly know what you mean by a
>>>"responsibility"? It must be sth linguistic for it has a meaning
>>>("semantics of a responsibility") and it must have an existence at
>>>runtime ("clients may invoke them one a peer-to-peer basis") ...
>>
>>Responsibilities are basic OO properties. All object properties are
>>defined in terms either [of] a responsibility for knowledge or a
>>responsibility for behavior.
>
>
> a. Responsibilities *are* (basic) properties
> b. Properties are *defined* in terms of responsibilities (for
> knowledge/behavior)
> -----------------------
> c. => Responsibilities are defined in terms of responsibilities ... ?

Not quite. The point was that in the OO paradigm only certain kinds of
responsibilities (i.e., responsibility for knowing something or
responsibility for doing something) can be object properties. For
example, there is no direct way to abstract the notion of 'purpose' in
an object as a responsibility.

>>IOW, objects are defined in terms of What
>>they should know and/or What they should be able to do.
>
>
> Of course. Or as I like to say it:
> The dual nature of the object abstraction = data abstraction +
> behavioral abstraction.

This is a common problem for OO novices and one of the main reasons the
OO paradigm defines properties in terms of responsibilities is to avoid
this sort of correlation to hardware computational models. Notions like
'behavior' and 'data' carry a lot of baggage in the computing space.
The responsibility for knowing something does not imply a data store
(e.g., the object can satisfy its responsibility by computing a value
whenever asked). Nor does a responsibility for doing something imply
the execution of set of computations (e.g., the object can satisfy its
responsibility for doing something by simply sending a message). IOW,
the notion of 'behavior' in an OOA/D sense is a much broader and
abstract concept than in the computing space.

>>>2. To me it seems that you are effectively saying: If one models an
>>>object's behavior upon receipt of a message m in a class X then one
>>>cannot model it again in subclass Y. I have not seen a constraint to
>>>this effect in the UML specification, and I have never heard of a
>>>design guideline to that effect. It must be possible to refine the
>>>modeling of a behavior from a more general, unspecific model in the
>>>superclass context to a more specific, refined model in the context of
>>>the subclass. Of course the magic word here is *refine*. ...
>>
>>...
>>
>>However, the semantics of WHAT the responsibilities are cannot be
>>multiply defined. That is, the object cannot be a member of two sets
>>where the property is defined differently (i.e., in a conflicting
>>manner).
>
>
> Just to verify: From the following choices yours is (a), right?
>
> a. There can be no two places/sets where the same
> responsibility/property is defined.
> b. There can be two places/sets but the definitions cannot be
> different.

Technically members of each descending subset have the property as a
constraint of membership so it must be defined for each subset. But
since a single given object is a member of each descending subset, those
definitions must be the same. The OO tree for for generalization just
makes placing the definition in one place convenient. IOW, it is a
shorthand to avoid redundant specification and make is easier to
recognize the proper level of access to the generalization.

> c. There can be two places/sets, the definitions can be different,
> but not in a conflicting manner.
>
> Whereas I was considering choice c.
> Does anyone reading this know what the UML 2 spec is saying here?

That probably isn't relevant, though I suspect UML is in agreement. UML
2 is designed to serve quite different masters than just OO development.
So one really has to look at the formally defined MDA profiles for OO
development that provide additional constraints.

> ---
>
>>...
>>
>>What I think you are talking about here (specific refinement from a
>>generalization) are different implementations of the same responsibility
>>semantics.
>
>
> I considered the possibility of refinement specification->specification
> (in the OOA/D model), not the realization/implementation of a
> specification.

The OO generalization relation is about providing specialized
specifications for what particular members of the root superclass are.
However, that is a quite different thing from refining the specification
of individual properties. OO generalization provides specialization by
/adding/ properties, not modifying those that are already defined.

[Of course providing a different implementation is a form of redefining
the property. But in OO development implementations are hidden from
clients. So the issue for OO is whether that redefinition is relevant
to the client, which comes down to how one abstracts the responsibility
for purposes of collaboration.]

> Maybe I should point out that I am used from OOPLs to opposing
> specification/design to implementation (= what you do in the
> implementation phase = implementation of the design). For an
> implementation relationship within the model (not the model of a
> PL-implementation) I prefer the UML term "realization".

Alas, the OOPLs are a poor way of learning about the OO paradigm because
they are 3GLS and they must necessarily make substantial compromises
with the hardware computational models. To put it another way, OOA/D
methodologies have come a long way since Smalltalk.

>
> "Implementation/realization of a responsibility/property" (for
> knowing/doing) I understand. What opposed to this is an "implementation
> of a responsibility semantics"? When are two responsibility
> semanticses[?] the same?
>
>
>> Thus I can implement a responsibility to sort a list of
>>values in ascending order with a bubble sort, an insertion sort, a
>>Quicksort, or any other sort algorithm in different subclasses.
>
>
> Classical example.
>
>
>>Similarly, I can implement a responsibility to compute withholding tax
>>differently for a SalariedEmployee subclass than for a sibling
>>HourlyEmployee subclass. But in both cases the semantics of the
>>re