Re: Question on LSP
- From: "H. S. Lahman" <h.lahman@xxxxxxxxxxx>
- Date: Wed, 03 May 2006 16:18:08 GMT
Responding to Kazakov...
However, I think that is beside the point. The issue here is whether ClassY* is related to ClassY via subclassing or subtyping.
OK. But I don't want to distinguish subclassing and subtyping.
But they are very different! Class systems are about set membership and identity while type systems are about property access signatures.
That might be what they are used for, but technically each class is a type.
So type relations cover the case of class ones. I don't see anything
special in classes that deserves a special treatment.
We are in serious disagreement here. Class systems need to be unambiguously mappable into type systems between OOA/D and OOP. And both are branches of set theory. But beyond that they are conceptually apples & oranges. I am not sanguine about resolving this on a newsgroup, so I think we need to just agree to disagree here.
Yes. It describes referential semantics. That's a subtype. When it
describes an identity semantics, which wasn't inherited from the target
type, then it is not a subtype (in this part.) I don't see any
contradiction here, because to me there is no full subtypes, they would be
useless. Each new type is both a subtype and not, depending on which part
of semantics is considered.
I still see a contradiction. For either subclassing or subtyping there must be a semantic link (e.g., shared properties) that is intrinsic to both abstractions. A reference is not an object. An object is not a reference. So one cannot make ClassY a subtype of ClassY* or vice versa.
I don't care about "is-a", I can access the target object, that's all. I
don't care about how this happens. That is an implementation detail.
But this is comp.object where subclassing and subtyping are used (and only used!) to express is-a relationships.
This just underscores the nature of our disagreement. I don't care about linguistics and 3GL grammar design. So to me one cannot talk about subclassing or subtyping or LSP without an is-a context. That is exactly why I cannot see ClassY* being related to ClassY through any sort of subtyping (outside the language design meta model).
Calling methods through pointers is subtyping?!? Sorry, that notion is so alien to me that I don't even know where to push back. B-)
It looks like substitution, it works like substitution... (:-))
A pointer always gives one exactly the same thing every time it is invoked so there is no substitution.
You mean pointer-specific operations here. But I mean that a substitution
happens when you pass pointer where an object of the target type is
expected.
I see this as a quite different issue that has nothing to do with pointers per se. There are three aspects of OO relationships that one has to deal with during OOA/D/P: implementation, instantiation, and navigation.
Pointers are <one of several> implementation mechanisms for relationships at the OOP level. That implementation is fixed regardless of the dynamics of collaboration. Passing the pointer as a method argument is <one of several> mechanisms for navigating OOA/D relationships at OOP time.
Your substitutability, OTOH, is an issue for instantiation. If the pointer, whether passed or as an embedded attribute, is never changed after the initial instantiation, then there is no substitution; the receiver always sees exactly the same object with exactly the same behaviors. If the pointer is instantiated differently each time it is passed (or an embedded pointer attribute is reset) before each navigation, then one has your substitutability because the receiver now interacts with a different object with different behaviors during each collaboration.
However, I don't think that substitutability has anything to do with the nature of pointers or passing them as arguments. It depends solely upon the dynamics of instantiating the pointer.
[There is a more esoteric view of substitutability where all that matters is that a given object /could/ collaborate with objects from different service subclasses. That is, at the Class Diagram level any client object could interact with any service object. However, in the actual implementation every individual client object might actually interact with exactly the same service object. So there is may be no substitutability for individual objects but there is for the collection of client objects. I submit my argue above extends to this view.]
That's true even if the 'thing' is an object that is accessed through the root superclass or supertype. The polymorphic dispatch only comes into play through which specific object is assigned to the pointer. But once it is assigned I see no substitution when navigating the pointer.
[Implicit] navigation *is* substitution. You "navigate" from derived type
to the base in the same way, but call it substitution. There is no semantic
difference as long as implementation is abstracted. Navigation /
substitution may include pointer dereferencing, view conversion, creation
of temporal objects, marshaling them over the network. I don't care about
this. It is hidden.
But subclassing relationships are not navigable. In an is-a relationship, like Highlanders, There Can Be Only One. That's why the dynamic_cast in C++ represents a language deficiency. In an is-a relationship, there is only one object in hand at a time that incorporates the entire tree so there is nothing to navigate.
LSP substitutability requires that one can substitute different members of the root class set dynamically in the same relationship. If the receiver is passed exactly the same object every time the relationship is navigated, then there is no substitution. [Subject to my esoteric caveat above.]
I see that as the issue with pointers. One always gets the same object regardless of whether the referenced object is a member of a subclass or not. So there is no substitution unless one can instantiate the pointer differently for each collaboration at run time through some sort of dynamic dispatch mechanism. And that has nothing to do with the nature of pointers themselves because the instantiation is at a different level of abstraction. Thus in the GoF pattern:
* R1 1
[Client] --------------- [Strategy]
A
| R2
+------+------+
| | |
... ... ...
The substitutability lies in instantiating R1 at run time. But R1 can be implemented in a variety of ways besides pointers or argument passing, so those implementation details aren't crucial. Similarly in any given collaboration between Client and Strategy there is no navigation of R2. One gets exactly the object that was used to instantiate R1.
IOW, LSP and substitutability are related to the dynamic dispatch mechanism for instantiation, not the pointers, argument passing, or other 3GL relationship implementation details.
No problem again. It is not a LSP subtype in in-methods, clearly null
cannot be passed in there. But I don't care, I have generalized ClassY
exactly for that reason, to have a new value: null. Otherwise, I would use
pointers without null, some languages support them.
But that value is incompatible with the "value" (identity) of a member of the ClassY set. In an OO context object identity exists in the problem space and it is necessarily unique to an individual entity. NULL is not the identity of an entity; it is a negative definition -- the value of there being no entity.
= it is not substitutable. So what? It was designed this way. You stick to
absolute substitutability, but there is no such thing in real programs.
I don't think substitutability is relevant here. A Class defines a suite of responsibilities that all member objects /must/ share. It has no meaning for an object without exactly those properties.
This is equivalent to substitutability in my model. Class is defined as a
set of all subtypes. So if subtyping requires substitutability (=LSP), then
class automatically enforces its properties on all objects. One could say
that the class is these objects.
One of the remarkably few things that Kay & Co got wrong with Smalltalk was using 'class' when they really meant 'type'. [Of course it is tough to blame them because much of modern type theory didn't exist back then. B-)]
I have difficulty following this argument because it is doing the same sort of mixing of paradigms between class and type systems. You have to choose one. Classes aren't types and vice versa. But this is back to our fundamental disagreement from the opening. At this point we can't even communicate because I am applying a profoundly different mindset to the words.
The problem with this otherwise nice construct, is that because LSP is
unrealistic, one would like to relax things a bit. So some properties might
get lost. But if you ensured that no objects without properties of interest
exist at run-time, then everything would be OK again. This is like circles
and ellipses. Just don't resize that damned circles! (:-))
This sentiment I agree with. [I think. B-)]
NULL defines a null set of properties which is a direct contradiction of the class definition. So that can't be substitutable semantically.
Yes, but I buy it.
LOL. So just what are you buying in contrast here? That NULL is useful anyway? That there can be non-semantic substitutability?
[I buy the notion that there are orthogonal semantics contexts, such as language design, where my objections don't carry. So in such contexts one could think of values as objects, references as objects, and reference types and object types are related through subtyping.]
The only substitutability lies in the nature of /references/ because a reference's "value" can be defined to include a null set as well as a class reference set. But that isn't really substitutability because the reference isn't an object. It is just a set definition around the reference's data domain, which is quite different than the target object's responsibility domain.
After all you can always add Dereference_Error exception to the target type
contract and everything will be perfectly substitutable. (:-))
Not in a well-formed OOA/D. B-)) That would lead to a cohesion problem for the target abstraction. Whatever the problem space entity underlying the target abstraction has as intrinsic characteristics, they surely doesn't include exception processing.
Apropos of the point below about our having different viewpoints, the notion of ANY as a Mother Of Types only has academic interest for the design of languages and whatnot. [The notion is analogous to kludges like CObject in MFC. One only needs such things explicitly in an application because of language deficiencies (e.g., to use dynamic_cast in C++) or because a library designer needs a place to implement language-specific stuff (e.g., new) behind the scenes. IOW, one should never, ever have to refer explicitly to CObject or CObect* in application code.]
I agree, "everything is object" is rubbish. A type without methods is
useless. But there are cases where ANY might have methods. I mean things,
which are methods, but usually aren't considered as ones. It is
1. identity
2. copying
3. other factories
4. things like sizeof()
Identity I might concede, but that is a knowledge responsibility, not a behavior responsibility. Since inclusion polymorphism and LSP is primarily about behavior substitution I don't think that counts. B-)
There are inner and outer substitutability. Identity is for the outer
world. It should not break clients.
We seem to be in agreement here. However, I was thinking of knowledge attributes in general. On thinking about it, I have to retract this particular statement because knowledge attributes can be the root of LSP problems. I have seen Shape trees where the real problem was that completely different knowledge <private> attributes were defined for subclasses and superclass for the same semantics:
Rectangle:
majorSide.
minorSide.
Square:
side.
This is just asking for trouble with the behavior substitutability because the implementations that the behaviors assume are incompatible.
<snip>
Again, I agree. I also agree with your point about 3GL. nGL forces you to
refrain from considering substitutability as an abstract problem. It is
true that if everything is OK, that will be automatically substitutable.
(We believe that God created our world in accordance with LSP. (:-)) But
how can you tell if your design is OK? To me the substitutability problem
is has a value of its own. I want to be able to handle it at the level of
3GL, without inspecting the problem space. The problem is the power of 3GL.
It seems that LSP is inconsistent with this power. I am not ready to
sacrifice it by going to nGL, even for the sake of LSP conformity.
So our real differences lie in the vagaries of 3GL type systems, which I argue are not relevant at the 4GL level -- precisely because they have been abstracted away by decoupling message from behavior. But you don't buy the notion of a 4GL because of a Catch-22: you can't extend your type systems to that level of abstraction, so that level of abstraction can't exist. B-) You need to get out of the type system mud and smell the abstractions. B-))
Sort of. But, maybe, you'll reinvent types when you will try to describe
commonalities at your abstraction level. (:-))
Rolling up my sleeves to show no hidden mechanisms...
But I don't need to. B-) Remember, I've been a translationist for two decades. One can unambiguously do full 3GL code generation from any well-formed OOA model. That model has no types in it, other than attribute ADTs. Even better, that model is executable so I can validate correctness (i.e., that the functional requirements have been satisfied) even before code generation.
*************
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
hsl@xxxxxxxxxxxxxxxxx
Pathfinder Solutions -- Put MDA to Work
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
(888)OOA-PATH
.
- Follow-Ups:
- Re: Question on LSP
- From: Dmitry A. Kazakov
- Re: Question on LSP
- References:
- Re: Question on LSP
- From: Dmitry A. Kazakov
- Re: Question on LSP
- From: H. S. Lahman
- Re: Question on LSP
- From: Dmitry A. Kazakov
- Re: Question on LSP
- Prev by Date: Re: Set Theory and OO (was: Question on LSP)
- Next by Date: Re: Searching OO Associations with RDBMS Persistence Models
- Previous by thread: Re: Question on LSP
- Next by thread: Re: Question on LSP
- Index(es):
Relevant Pages
|