Re: Question on LSP
- From: "Dmitry A. Kazakov" <mailbox@xxxxxxxxxxxxxxxxx>
- Date: Fri, 5 May 2006 15:30:02 +0200
On Thu, 04 May 2006 16:32:18 GMT, H. S. Lahman wrote:
Responding to Kazakov...
But is-a in the problem space is not is-a in the programming language. It
is very dangerous to mix them. I can model problem space's is-a by many
ways, and many of them will not be is-a. In my view, subtyping expresses
nothing. It is a relation which can be evaluated to true or false. Same as
an integer number, which also expresses nothing. We can use either to model
something that in our opinion has a similar structure / behavior / shape /
properties. I stop, where you begin.
I don't how to avoid "mixing" them. OOA/D abstracts from various
problem spaces. The role of OOPLs is to provide an implementation for
the OOA/D design that is closer to the hardware computational models.
To preserve correctness, I think that implementation must preserve the
OOA/D semantics.
I think it would be a wrong idea. The semantics is different, and proving
correctness becomes a nightmare because of that. This is why generated code
is much easier to prove correct, by construction.
It seems to me that failing to preserve is-a semantics in the type
systems would be much worse than choosing OOPL names like X.Y() for
OOA/D abstractions like Account.withdrawal().
It is not failing, it is expressing it in a different way. When you have
virtual memory management, do you really care about physical addresses?
But I can't help pointing out that nobody had much interest in type
theory in general and LSP in particular until OOA/D became prominent.
When the only abstractions one needed to play with were procedures, one
could make do with less sophisticated graph and set theory for 3GL
language design. B-) So I find it hard to believe that the type
mavens weren't strongly influenced by OOA/D abstraction semantics like is-a.
It could be true or just a coincidence. Clearly we have a difficult problem
of growing complexity at hand. Old tools and customs stop working. So
people are searching in all corners. My hope is in a great unity, which
would cooptate functional and relational guys.
LSP is only an
issue for polymorphic dispatch. In fact, of all the forms of
polymorphism available to OO development, LSP is only relevant to
inclusion polymorphism. And inclusion polymorphism does not exist
without and is-a semantics.
It does not, it has a potential to become. Is-a is abstracted as "is
substitutable for" and the latter is as "inherits this method from."
Another fundamental disagreement. "is-a" does not imply anything at all
about substitutability. Is-a is abstracted as "is a member of that
set". Nothing more.
I am constructivist, show me the set! (:-))
Substitutability only comes into play through polymorphic dispatch when
a member of a set is accessed during collaboration and then only if the
access is through a superclass. And inheritance is orthogonal to
subclassing; inheritance merely provides a suite of rules for resolving
the properties of a particular member of a root superclass. IOW,
inclusion polymorphism and inheritance are enabled by subclassing, but
they are quite different things than the is-a semantics.
This is our disagreement. I don't consider values, they are only postulated
to exist. Our only interest in them is how values are bound by methods
(arcs). If there exists a path, it is a subtype relation. I don't care
where that transition leads, there is one, that's all.
OK, if you mean a possibility to instantiate values of S as ones of T. Why
T* cannot be instantiated as T?
I mean that the [Strategy] is-a exists with or without the R1
relationship and is unaffected by whether R1 exists. But LSP is not
relevant unless the R1 relationship exists.
I would say LSP is relevant to any relationship.
Nor does it matter how one
implements the relationship (T vs T*).
(Only if the implementation is conform to LSP.)
The
if-a-tree-falls-in-the-woods-is-there-a-sound? argument about the
possibility of substitution doesn't matter. It is the existence of the
/relationship/ that makes LSP substitutability concrete, not its
implementation via pointers or any other mechanism.
That's OK, but it is already beyond types. I want (and I think Liskov did
too) to judge about types regardless to what they implement.
[...]
What I disagree with is that
pointer dispatch is the same as polymorphic dispatch. The pointer
dispatch is not /intrinsically/ polymorphic; any substitution is purely
in the value of the pointer. The pointer dispatch semantics are
completely and unambiguously describable without any mention of
polymorphic dispatch. But one cannot describe LSP substitutability
without talking about polymorphic dispatch and, in an OO context, is-a
relationships.
Hmm, I could have fat pointers and thin objects. This is actually what
always wished to see in modern OOPL. Technically it means that the type tag
is not stored in the object (that will have no type identity). It is in the
pointer. Note that semantically fat-pointer-to-thin-value is equivalent to
thin-pointer-to-fat-value. Both dispatch, both are dynamically polymorphic.
But it breaks your "is-a" fiction. BTW, having this mechanism, you will be
able to translate your OOA/D "is-a" much more uniformly and efficiently.
As an analogy consider that I can describe any complex behavior with
interacting state machines using asynchronous event-based
communications. Almost always the state machine actions will be
executed at some lower level by making synchronous procedure calls.
Does that make a synchronous procedure call inherently asynchronous?
No. Like a pointer, it is just an implementation artifact. In this
case that call is /inherently/ synchronous even though it implements an
asynchronous solution. So the synchronous procedure call has no more to
do with asynchronous behavior than a pointer has to do with polymorphic
dispatch.
Agree, but why do you think that this supports your point of view and not
mine?! (:-))
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.
Ah, that nGL again! (:-)) Exception processing is not necessary a model. It
could serve for "phase transition." You might be unable to have one model
working well in all cases, just because the solution space has a structure
of its own. You have to handle "bifurcations" by changing models. (Not
everything is a model. I am *not* a translationist, as you know! (:-))
Whether one explicitly models exception processing depends on the
problem space. If there are rules and policies around exceptions that
are unique to the problem in hand, one would have to model it explicitly
in the solution. OTOH, if it is some artifact of the computing space
with well defined and has standardized infrastructure, one would leave
it to OOD or OOP.
What I am saying here is that IF one explicitly models it at the OOA
level, then one would still have to abstract its responsibilities
separately from those of the target. That is, the exception would be
abstracted separately in some other object(s) than the target in your
example.
Yes, but this is a different case. I meant exceptions used as artefacts of
design. Dereference_Error models nothing, but a design weakness. But it is
OK, because there might be no better design.
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.
I don't see it as the problem. Both are just implementations, they could be
any. The problem is in what they model, in the problem space. Circle is not
substitutable for ellipse already there.
Really?
[Shape]
A
|
+------+-------+
| |
[Rectangle] [Square]
- majorSide - side
- minorSide
Try defining a constructor for [Shape] that any client can use. Or
[Rectangle]
+ majorSide
+ minorSide
+ area ()
A
|
+-------+--------+
| |
[Square] [Rhomboid]
- side
Presumably Square.area() uses Square.side for the computation. Where
does the value of Square.side come from? Even for this simple case all
the answers are ugly. For more complex situations it would get worse.
But the real problem is the redundancy. For all [Square] objects you
will also have to put the value of Square.side into both majorSide and
MinorSide attributes so that clients of [Rectangle] can get the right
stuff when they ask about sides.
I don't have your "is-a" problem, so Rectangle and Square can have
different representations. majorSide is a member interface. It is not a
member. Square can implement that interface in the in-mode (getter.) It
cannot implement it in the out-mode (setter.) So it becomes an incomplete
(partial) subtype of Rectangle. Technically, subsets remain, but they are
moved to methods. It might look a small difference, but it is important,
because using your language, differently to attributes methods need not to
be always instantiated. So, in any context where majorSide setter is not
called its absence represents no problem.
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
.
- Follow-Ups:
- Re: Question on LSP
- From: H. S. Lahman
- 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
- From: H. S. Lahman
- Re: Question on LSP
- From: Dmitry A. Kazakov
- Re: Question on LSP
- From: H. S. Lahman
- Re: Question on LSP
- Prev by Date: Re: MVC: Internationalize Controller?
- Next by Date: Re: MVC: Internationalize Controller?
- Previous by thread: Re: Question on LSP
- Next by thread: Re: Question on LSP
- Index(es):
Relevant Pages
|