comp.lang.ada
 help / color / mirror / Atom feed
* Re: OO puzzle
  1999-12-22  0:00 OO puzzle Ehud Lamm
  1999-12-22  0:00 ` Tucker Taft
@ 1999-12-22  0:00 ` Ted Dennison
  1999-12-23  0:00   ` Ehud Lamm
  1999-12-22  0:00 ` Jeff Carter
  2 siblings, 1 reply; 21+ messages in thread
From: Ted Dennison @ 1999-12-22  0:00 UTC (permalink / raw)


In article
<Pine.A41.3.96-heb-2.07.991222103646.28794B-100000@pluto.mscc.huji.ac.il
>,
  Ehud Lamm <mslamm@mscc.huji.ac.il> wrote:

> This example is again from the Eiffel book.
>
> 1. Truck_Driver IS-A Driver (one hierrachy)
>
> 2. Motor_Vehicle (and all its kids)  support the operation
> register_Driver(d:driver) the paramter is of type driver above.
>
>    Car IS-A Motor_Vechicle
>    Truck IS-A Motor_Vehicle
>      Truck wants to override register_driver(d:truck_driver) becuase
> only truck drivers should be allowed here.
>
> Can yuo do this in Ada? Try, and show your error messages! How can you
> do something to achive the same result, in Ada?

Well, I'll assume in Ada you would be talking about a routine that
takes in driver'class and also has a "motor_vehicle" parameter on which
it dispatches, and it does *not* dispatch on the driver. One possibility
would be to have truck's version of register_driver internally check
that the driver is in truck_driver'class:

if d not in truck_driver'class then
   raise Constraint_Error;
end if;

Another would be to disallow calls to the original register altogether
(via "abstract" perhaps?) and to make a new one that only takes in
truck_driver'class. That looses the dynamic dispatch from
Motor_Vehicle'class, though.

--
T.E.D.


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-22  0:00 OO puzzle Ehud Lamm
  1999-12-22  0:00 ` Tucker Taft
  1999-12-22  0:00 ` Ted Dennison
@ 1999-12-22  0:00 ` Jeff Carter
  2 siblings, 0 replies; 21+ messages in thread
From: Jeff Carter @ 1999-12-22  0:00 UTC (permalink / raw)


In article <Pine.A41.3.96-heb-2.07.991222103646.28794B-
100000@pluto.mscc.huji.ac.il>,
  Ehud Lamm <mslamm@mscc.huji.ac.il> wrote:
...
> Can you do this in Ada? How?
...
> Can you do this in Ada ...
...
> Can yuo do this in Ada? Try, and show your error messages! How can
you do
> something to achive the same result, in Ada?
...
> Can you do this in Ada? How?
...

The answer to these repeated questions:

Yes. Use composition, not type extension/dispatching.
--
Jeff Carter
"Now go away or I shall taunt you a second time."
-- Monty Python and the Holy Grail


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-22  0:00 OO puzzle Ehud Lamm
@ 1999-12-22  0:00 ` Tucker Taft
  1999-12-23  0:00   ` Ehud Lamm
  1999-12-22  0:00 ` Ted Dennison
  1999-12-22  0:00 ` Jeff Carter
  2 siblings, 1 reply; 21+ messages in thread
From: Tucker Taft @ 1999-12-22  0:00 UTC (permalink / raw)


Ehud Lamm wrote:
> 
> The recent threads about languages for OO development, made me think the
> following may interest readers here.
> ...
> Basically this means that is you have a function
>    Stack.Push(Node)
> 
> and you inherit to create Stack_Array than you can also change the
> argument Node to something that inherits from Node:
>   Stack_Array.Push(Node_Array)
> 
> Can you do this in Ada (think of what we saw above about comparable)? So
> what is the Ada solution in this case? Can you do this in Java (is Java
> "covariant")?

Ada is automatically "covariant" in all of the "controlling" operands
(and result) of a primitive operation.  Java is not covariant in its 
operands (other than the implicit "this" operand, of course).

Ada does not support covariance for operands of an unrelated type.
This has a number of nasty "system validity" issues that Eiffel presumes
will be caught by the linker.

When you want to do something like this in Ada, the best thing to do is 
define a generic and either use a formal derived type, or use
a formal private type with specified operations (this is the
most flexible approach).

> ---------------------------------------------------------------------
> 
> Now how does this affect design?
> This example is again from the Eiffel book.
> 
> 1. Truck_Driver IS-A Driver (one hierrachy)
> 
> 2. Motor_Vehicle (and all its kids)  support the operation
> register_Driver(d:driver) the paramter is of type driver above.
> 
>    Car IS-A Motor_Vechicle
>    Truck IS-A Motor_Vehicle
>      Truck wants to override register_driver(d:truck_driver) becuase only
> truck drivers should be allowed here.

This implies that you will have to deal with the system validity
issues, if someone tries to register a non-truck driver of a vehicle, and
the vehicle turns out to be truck.  In most cases, this would imply
a run-time check, or a "pessimistic" link-time check.

> Can yuo do this in Ada? Try, and show your error messages! How can you do
> something to achive the same result, in Ada?

The simplest solution is to create a new operation (perhaps with
a new name like "register_truck_driver").  The existing register_driver
operation could be overridden with one that performs the appropriate
conversion to truck_driver (which will automatically do the relevant
run-time check) and then calls the register_truck_driver operation.
Either one could be called from outside the abstraction,
but the "register_truck_driver" version would have no chance of
run-time-check failure, and instead would enforce the check at compile-time.



> 
> I qoute:
> "Examples of this kind, with two prallel inheritance hierarchies, are a
> constant occurrence in the development of systems and their class
> hierarchies. Many appear in the Data Strcuture Library" (the Eiffel
> library of trees etc.) "For example, to describe a doubly linked list,
> TWO_WAY_LIST inherits from LINKED_LIST; to describe two-way chained linked
> cells, BI_LINAKBLE inherits from LINKABLE. The list classes have
> procedures for manipulating list celss, such as put_linkable_left, which
> quite naturally take arguments of type LINKABLE imn LINKED_LIST and
> BI_LINKABLE in TWO_WAY_LIST"
> 
> A bit complicated hierrachies, but this is simple comapred to what you may
> find in real life applications!
> 
> Can you do this in Ada? How?

See above.  Trying to do this "automatically" with parameter covariance
is in some ways sweeping the issue under the rug.  Additional
run-time checks may be inevitable, meaning that the operations should
perhaps not be given identical names.  As mentioned above, using
generics or adding new operations are two approaches.  Given
any particular problem, the solution would probably be obvious.

Given a general statement such as "this language has this feature, 
what is the equivalent in that language" can be a waste of energy.
Each language gives you a toolkit.  The toolkits are generally not
identical.  To pick one tool from a toolkit and try to construct
an equivalent tool using tools from another toolkit may be pointless.
The real question is how effectively and safely can each toolkit,
given the tools it contains, solve the problems of interest.  So the
key is to focus on the problems of interest, not on replicating
particular tools.
 
> ...
> So what do you guys suggest as the proper Ada way in these cases?

See above.
> 
> Ehud Lamm mslamm@mscc.huji.ac.il
> http://purl.oclc.org/NET/ehudlamm <== My home on the web
> Check it out and subscribe to the E-List- for interesting essays and more!

-- 
-Tucker Taft   stt@averstar.com   http://www.averstar.com/~stt/
Technical Director, Distributed IT Solutions  (www.averstar.com/tools)
AverStar (formerly Intermetrics, Inc.)   Burlington, MA  USA




^ permalink raw reply	[flat|nested] 21+ messages in thread

* OO puzzle
@ 1999-12-22  0:00 Ehud Lamm
  1999-12-22  0:00 ` Tucker Taft
                   ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: Ehud Lamm @ 1999-12-22  0:00 UTC (permalink / raw)


The recent threads about languages for OO development, made me think the
following may interest readers here.
 


I am now quouting a bit from the book "Eiffel the language", so I am
describing Eiffel and not Ada, consider how these language differ, and try
to think why. This will lead to an answer to the design question ahead:

" (P1) A Class may override the export policies of its parents; it may for
example make secret its version of a feature which the parent exported"
Can you do this in Ada? How? What does it mean to the "IS-A" meaning of
ihnheritance?

" (P2) The routine redifinition may replace the type of a formal argument
by a type conforming to the original (covariant argument policy)"
This meains that when you inherit (think of comparable above) you can
replace the argument with any type that is inherited from it. But for this
to make sense, we are talking of more than one type - because you are
doing this change, as part of inheriting the routine. 
Basically this means that is you have a function 
   Stack.Push(Node)

and you inherit to create Stack_Array than you can also change the
argument Node to something that inherits from Node:
  Stack_Array.Push(Node_Array)

Can you do this in Ada (think of what we saw above about comparable)? So
what is the Ada solution in this case? Can you do this in Java (is Java
"covariant")? 

---------------------------------------------------------------------

Now how does this affect design?
This example is again from the Eiffel book.

1. Truck_Driver IS-A Driver (one hierrachy)

2. Motor_Vehicle (and all its kids)  support the operation
register_Driver(d:driver) the paramter is of type driver above.

   Car IS-A Motor_Vechicle 
   Truck IS-A Motor_Vehicle
     Truck wants to override register_driver(d:truck_driver) becuase only
truck drivers should be allowed here.

Can yuo do this in Ada? Try, and show your error messages! How can you do
something to achive the same result, in Ada? 

I qoute:
"Examples of this kind, with two prallel inheritance hierarchies, are a
constant occurrence in the development of systems and their class
hierarchies. Many appear in the Data Strcuture Library" (the Eiffel
library of trees etc.) "For example, to describe a doubly linked list,
TWO_WAY_LIST inherits from LINKED_LIST; to describe two-way chained linked
cells, BI_LINAKBLE inherits from LINKABLE. The list classes have
procedures for manipulating list celss, such as put_linkable_left, which
quite naturally take arguments of type LINKABLE imn LINKED_LIST and
BI_LINKABLE in TWO_WAY_LIST"

A bit complicated hierrachies, but this is simple comapred to what you may
find in real life applications!

Can you do this in Ada? How? 


Well this is quite a lot, and not easy to understand, but I hope you will
find it interesting. If you have questions/ideas I'd be happy to hear. 
You may find this page interesting:
http://www.eiffel.com/doc/manuals/technology/typing/intro.html


So what do you guys suggest as the proper Ada way in these cases?

Ehud Lamm mslamm@mscc.huji.ac.il
http://purl.oclc.org/NET/ehudlamm <== My home on the web 
Check it out and subscribe to the E-List- for interesting essays and more!






^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-23  0:00   ` Ehud Lamm
  1999-12-23  0:00     ` Ted Dennison
@ 1999-12-23  0:00     ` Robert A Duff
  1999-12-25  0:00       ` Ehud Lamm
  1 sibling, 1 reply; 21+ messages in thread
From: Robert A Duff @ 1999-12-23  0:00 UTC (permalink / raw)


Ehud Lamm <mslamm@mscc.huji.ac.il> writes:

> But than you lose the ability to define the abstract interface (for
> Motor_Vehicle) and know that it is supported by all descendants.

But it seems to me that you are *not* requiring the descendants to
support that interface.  You are trying to let the descendants support a
different operation, also called "register", but with a different
contract (ie, trucks can't register airplane drivers, although the
parent type implied they could -- or whatever the example was).

It's an interesting language design issue, anyway.

- Bob




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-22  0:00 ` Tucker Taft
@ 1999-12-23  0:00   ` Ehud Lamm
  1999-12-23  0:00     ` Robert Dewar
  1999-12-29  0:00     ` Brian Rogoff
  0 siblings, 2 replies; 21+ messages in thread
From: Ehud Lamm @ 1999-12-23  0:00 UTC (permalink / raw)


In article <386102F6.56CEFA22@averstar.com>,
  Tucker Taft <stt@averstar.com> wrote:
> Ada does not support covariance for operands of an unrelated type.
> This has a number of nasty "system validity" issues that Eiffel
presumes
> will be caught by the linker.

This issue of system validity is discussed in the "Eiffel the language"
book, from which I took the examples. If any one is interested in
looking it up. This is indeed the heart of this issue.

>
> When you want to do something like this in Ada, the best thing to do
is
> define a generic and either use a formal derived type, or use
> a formal private type with specified operations (this is the
> most flexible approach).
>

Yes, my approach is to use generics as much as possible. Simply love
the concept.
But how would you use it in the Truch driver example below?


> >
> > 1. Truck_Driver IS-A Driver (one hierrachy)
> >
> > 2. Motor_Vehicle (and all its kids)  support the operation
> > register_Driver(d:driver) the paramter is of type driver above.
> >
> >    Car IS-A Motor_Vechicle
> >    Truck IS-A Motor_Vehicle
> >      Truck wants to override register_driver(d:truck_driver)
becuase only
> > truck drivers should be allowed here.
>
> This implies that you will have to deal with the system validity
> issues, if someone tries to register a non-truck driver of a vehicle,
and
> the vehicle turns out to be truck.  In most cases, this would imply
> a run-time check, or a "pessimistic" link-time check.

This issue of run-time/pre run-time checking is the crux of the matter.
I was under the impression that system validity issue are checked
before runtime. Of course otherwise the problem is much simpler, since
explicit conversions in the body of the inherited routine would give
you a constraint_error if the types do not match. Checking the 'class
is also possible to do explicitly.
I assume the importance of catching errors before runtime is evident.
Now can we do it nicely in this case?

> The simplest solution is to create a new operation (perhaps with
> a new name like "register_truck_driver").  The existing
register_driver
> operation could be overridden with one that performs the appropriate
> conversion to truck_driver (which will automatically do the relevant
> run-time check) and then calls the register_truck_driver operation.
> Either one could be called from outside the abstraction,
> but the "register_truck_driver" version would have no chance of
> run-time-check failure, and instead would enforce the check at
compile-time.
>

Right but someone using the abstract interface, may end up having a run-
time error. Just so we are claer on the implications here.
This is indeed sometimes an acceptable solution.

> >

> See above.  Trying to do this "automatically" with parameter
covariance
> is in some ways sweeping the issue under the rug.  Additional
> run-time checks may be inevitable, meaning that the operations should
> perhaps not be given identical names.  As mentioned above, using
> generics or adding new operations are two approaches.  Given
> any particular problem, the solution would probably be obvious.

I am not sure obvious to everybody! My students do not find it obvious
(and as a matter of fact neither do I all the time!)
I'd be happy if you could elaborate on the issue of the inevitability
of runtime checks. As far as I see, _in principle_ these issues can be
checked at compile time (unsless of course we are delaing with dynamic
binding). So is the issue the cost of the checking, or is there some
issue I am fogetting right now?


>
> Given a general statement such as "this language has this feature,
> what is the equivalent in that language" can be a waste of energy.


It seems people understood me as doing this. But this is exactly what I
do not like, and didn't try to do!
My attempt was to help clarify the different approaches. I am not
saying off hand "emulate." But I do think that it is not a simple
matter to arrive at the level of understanding you have... The examples
illustrate that something that looks like an acceptable design, is not
automatically codable. You have to understand the underlying
methodology, and have an intuition for the techniques.
I think this discussion is useful for this purpose (e.g, clarifying the
things that are compile time and run time).
Actually in most respects I prefer the Ada tagged type model to others,
since it seems clearer to me. But this is not the issue. The issue is
having a good enough understanding to compare and analyze. This, I
think, is not a waste of energy.


--
Ehud Lamm mslamm@mscc.huji.ac.il
http://purl.oclc.org/NET/ehudlamm
Check it out and subscribe to the E-List


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-22  0:00 ` Ted Dennison
@ 1999-12-23  0:00   ` Ehud Lamm
  1999-12-23  0:00     ` Ted Dennison
  1999-12-23  0:00     ` Robert A Duff
  0 siblings, 2 replies; 21+ messages in thread
From: Ehud Lamm @ 1999-12-23  0:00 UTC (permalink / raw)


In article <83qtap$pri$1@nnrp1.deja.com>,
  Ted Dennison <dennison@telepath.com> wrote:
> In article
> <Pine.A41.3.96-heb-2.07.991222103646.28794B-
100000@pluto.mscc.huji.ac.il
> Well, I'll assume in Ada you would be talking about a routine that
> takes in driver'class and also has a "motor_vehicle" parameter on
which
> it dispatches, and it does *not* dispatch on the driver. One
possibility
> would be to have truck's version of register_driver internally check
> that the driver is in truck_driver'class:
>
> if d not in truck_driver'class then
>    raise Constraint_Error;
> end if;
>

Right. But than we are dealing with a runtime check. See the discussion
per Tucker's post.

> Another would be to disallow calls to the original register altogether
> (via "abstract" perhaps?) and to make a new one that only takes in
> truck_driver'class. That looses the dynamic dispatch from
> Motor_Vehicle'class, though.

But than you lose the ability to define the abstract interface (for
Motor_Vehicle) and know that it is supported by all descendants.

Trade offs all arround...

--
Ehud Lamm mslamm@mscc.huji.ac.il
http://purl.oclc.org/NET/ehudlamm
Check it out and subscribe to the E-List


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-23  0:00   ` Ehud Lamm
@ 1999-12-23  0:00     ` Robert Dewar
  1999-12-23  0:00       ` Ehud Lamm
  1999-12-29  0:00     ` Brian Rogoff
  1 sibling, 1 reply; 21+ messages in thread
From: Robert Dewar @ 1999-12-23  0:00 UTC (permalink / raw)


In article <83sq9g$5ml$1@nnrp1.deja.com>,
  Ehud Lamm <mslamm@mscc.huji.ac.il> wrote:
> I assume the importance of catching errors before runtime is
> evident. Now can we do it nicely in this case?

Evident, but not quite so neatly trivial. Run-time errors are
of two kinds:

1. Statements that will always cause an error if executed. Such
errors are bound to get caught by simple coverage testing.

2. Statements where the error is data dependent and there is no
simple guarantee.

Obviously errors in these two classes are a completely different
kettle of fish.


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-23  0:00     ` Robert Dewar
@ 1999-12-23  0:00       ` Ehud Lamm
  1999-12-24  0:00         ` swhalen
  1999-12-25  0:00         ` Ehud Lamm
  0 siblings, 2 replies; 21+ messages in thread
From: Ehud Lamm @ 1999-12-23  0:00 UTC (permalink / raw)


In article <83t14p$9ps$1@nnrp1.deja.com>,
  Robert Dewar <robert_dewar@my-deja.com> wrote:
> In article <83sq9g$5ml$1@nnrp1.deja.com>,
>   Ehud Lamm <mslamm@mscc.huji.ac.il> wrote:
> > I assume the importance of catching errors before runtime is
> > evident. Now can we do it nicely in this case?
>
> Evident, but not quite so neatly trivial. Run-time errors are
> of two kinds:
>
> 1. Statements that will always cause an error if executed. Such
> errors are bound to get caught by simple coverage testing.
>
> 2. Statements where the error is data dependent and there is no
> simple guarantee.
>

This is true, of course. Indeed one of the basic elements of OOP is the
late binding, which allows you things like polymorphic datastructures.
The price you pay is of course that some things are only checkable in
runtime. So far so good.

But if we delve into this, following your post, we get to less firm
ground.
Suupose I have a routine that receives a class wide type. Inside I
expicitly convert and treat it as some specific type.
If I pass an actual paramter that is class-wide (access object'class)
than, obviously, the valdity of the conversion can only be checked at
run time.
However if I pass a specific, and incompatible type - we can imagine a
compiler flagging the conversion as raising an exception. whether we
design a language to do this checking, and disallow such calls is,
naturally, a deisgn choice. But as opposed to the first example - this
checking seems possible to do (at least in limited cases like this).

The issue we discussed was an example of paramter delcartions in
Eiffel, that if checked before runtime, provide more checking than is
achied by some Ada examples that ostensibly defer the check to runtime.

Your classifciation is correct, but in itself doesn't provide the
prescriptive answer of how to design a language in such a way as to
ensure as much can be done during compile time, as possible without
hurting expressablity to much. This question is naturally not a
question that can be answered shortly and with a defnitive answer.
Hence we see some differences even among mostly similiar languages.

The "system validty" issue in Eiffel, is such an issue, and comments
about it are welcome. The first question, though, is if it can be
checked before runtime. Tucker's response seems to imply that the
answer is no. [but also brings in the question of link time checks]

--
Ehud Lamm mslamm@mscc.huji.ac.il
http://purl.oclc.org/NET/ehudlamm
Check it out and subscribe to the E-List


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-23  0:00   ` Ehud Lamm
@ 1999-12-23  0:00     ` Ted Dennison
  1999-12-25  0:00       ` Ehud Lamm
  1999-12-23  0:00     ` Robert A Duff
  1 sibling, 1 reply; 21+ messages in thread
From: Ted Dennison @ 1999-12-23  0:00 UTC (permalink / raw)


In article <83sqht$5oi$1@nnrp1.deja.com>,
  Ehud Lamm <mslamm@mscc.huji.ac.il> wrote:
> In article <83qtap$pri$1@nnrp1.deja.com>,
>   Ted Dennison <dennison@telepath.com> wrote:
> > if d not in truck_driver'class then
> >    raise Constraint_Error;
> > end if;
> >
>
> Right. But than we are dealing with a runtime check. See the
> discussion per Tucker's post.

Well...yes. But even if the language directly supported MI, this would
have to be a runtime check in many situations. Situations where it
doesn't dynamicly dispatch might be determinable at compile time, but in
those situations you don't need straight inheritance either.

The real drawback in my mind is that the type constraint isn't visible
in the procedure's spec. You'd have to copiously comment it, but
comments aren't checked by the compiler.

--
T.E.D.


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-23  0:00       ` Ehud Lamm
@ 1999-12-24  0:00         ` swhalen
  1999-12-25  0:00           ` Ehud Lamm
  1999-12-25  0:00         ` Ehud Lamm
  1 sibling, 1 reply; 21+ messages in thread
From: swhalen @ 1999-12-24  0:00 UTC (permalink / raw)


Ehud Lamm <mslamm@mscc.huji.ac.il> wrote:
...
: Your classification is correct, but in itself doesn't provide the
: prescriptive answer of how to design a language in such a way as to
: ensure as much can be done during compile time, as possible without
: hurting expressablity to much. This question is naturally not a
: question that can be answered shortly and with a definitive answer.
: Hence we see some differences even among mostly similar languages.
...

I'm missing something here (which is not that unusual <g>).

I know Ada _much_ better than I know Eiffel, but my impression is
that Ada already _is_ designed

    "in such a way as to ensure as much can be done during compile
     time, as possible without hurting expressablity to much."

In many ways, that seems to me a good definition of one of the major
design goals (and successes) of Ada.

My impression of Eiffel is that from the start, it was intended that
having powerful OO constructs was a more important language design
constraint than early vs. late binding. I seem to remember that
Eiffel intended to have a larger and smarter run-time with many
class and conversion and compatibility issues deferred to run time
and not even be attempted at link time (to enhance OO "power" or
"clarity").

Aren't the differences you're highlighting inherent in the differing
design intents of the two languages? It seems to me that the
examples you give are right on the boundary of where Eiffel
intentionally went farther than Ada in order to enhance "OO clarity"
(and sacrificed link time error detection / efficiency).

Steve

-- 
{===--------------------------------------------------------------===}
                Steve Whalen     swhalen@netcom.com
{===--------------------------------------------------------------===}




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-23  0:00       ` Ehud Lamm
  1999-12-24  0:00         ` swhalen
@ 1999-12-25  0:00         ` Ehud Lamm
  1 sibling, 0 replies; 21+ messages in thread
From: Ehud Lamm @ 1999-12-25  0:00 UTC (permalink / raw)


In article <83t2vt$arh$1@nnrp1.deja.com>,
  Ehud Lamm <mslamm@mscc.huji.ac.il> wrote:
> Suupose I have a routine that receives a class wide type. Inside I
> expicitly convert and treat it as some specific type.
> If I pass an actual paramter that is class-wide (access object'class)
> than, obviously, the valdity of the conversion can only be checked at
> run time.
> However if I pass a specific, and incompatible type - we can imagine a
> compiler flagging the conversion as raising an exception. whether we
> design a language to do this checking, and disallow such calls is,
> naturally, a deisgn choice. But as opposed to the first example - this
> checking seems possible to do (at least in limited cases like this).
>

Just ot clarify myeself. This issue, is conneted with the issue
of "seperate compilation" Indeed the "system validity" of Eiffel is
exactly the checks that are not (class) local.



--
Ehud Lamm mslamm@mscc.huji.ac.il
http://purl.oclc.org/NET/ehudlamm
Check it out and subscribe to the E-List


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-24  0:00         ` swhalen
@ 1999-12-25  0:00           ` Ehud Lamm
  0 siblings, 0 replies; 21+ messages in thread
From: Ehud Lamm @ 1999-12-25  0:00 UTC (permalink / raw)


In article <83uk4d$mec$1@nntp6.atl.mindspring.net>,
  swhalen@netcom.com wrote:
>
> I'm missing something here (which is not that unusual <g>).
>
> I know Ada _much_ better than I know Eiffel, but my impression is
> that Ada already _is_ designed
>
>     "in such a way as to ensure as much can be done during compile
>      time, as possible without hurting expressablity to much."
>
> In many ways, that seems to me a good definition of one of the major
> design goals (and successes) of Ada.
>

Quite. But in this case we are talking about something very specific,
so the question is could this specific kind of checks be done before
runtime, and at what costs.

Compare this with generics. Ada(83) generics are designed so that
checking can be done seperately on the generic unit, and the
instantiation. This allow seperate compilation, and early detection of
errors. But it relies on the fact the generic paramaters compromise
very specific classes of types etc.

OO which by nature uses late binding etc. can make this issue harder.

One more reason why I am a fan of generics.

But still not an answer to the specific cases I outlined in the
original post. Can we ensure the truck_driver/driver distinction using
compile time checks?

--
Ehud Lamm mslamm@mscc.huji.ac.il
http://purl.oclc.org/NET/ehudlamm
Check it out and subscribe to the E-List


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-23  0:00     ` Ted Dennison
@ 1999-12-25  0:00       ` Ehud Lamm
  0 siblings, 0 replies; 21+ messages in thread
From: Ehud Lamm @ 1999-12-25  0:00 UTC (permalink / raw)


In article <83tb9t$g8e$1@nnrp1.deja.com>,
  Ted Dennison <dennison@telepath.com> wrote:
> In article <83sqht$5oi$1@nnrp1.deja.com>,
>   Ehud Lamm <mslamm@mscc.huji.ac.il> wrote:
> > In article <83qtap$pri$1@nnrp1.deja.com>,
> >   Ted Dennison <dennison@telepath.com> wrote:
> > > if d not in truck_driver'class then
> > >    raise Constraint_Error;
> > > end if;
> > >
> >
> > Right. But than we are dealing with a runtime check. See the
> > discussion per Tucker's post.
>
> Well...yes. But even if the language directly supported MI, this would
> have to be a runtime check in many situations. Situations where it
> doesn't dynamicly dispatch might be determinable at compile time, but
in
> those situations you don't need straight inheritance either.

I am not sure why you restrict the issue to MI. The hierarchy of
vehicles and drivers was SI. The difference is that you have covariance
on paramters that are not of the class being extended. Note that this
is clearly apperant - becuase of the "distinguished receiver."

>
> The real drawback in my mind is that the type constraint isn't visible
> in the procedure's spec. You'd have to copiously comment it, but
> comments aren't checked by the compiler.

Quite. This is an important issue, and relates to expresability.
--
Ehud Lamm mslamm@mscc.huji.ac.il
http://purl.oclc.org/NET/ehudlamm
Check it out and subscribe to the E-List


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-23  0:00     ` Robert A Duff
@ 1999-12-25  0:00       ` Ehud Lamm
  0 siblings, 0 replies; 21+ messages in thread
From: Ehud Lamm @ 1999-12-25  0:00 UTC (permalink / raw)


In article <wccr9gdaefw.fsf@world.std.com>,
  Robert A Duff <bobduff@world.std.com> wrote:
> Ehud Lamm <mslamm@mscc.huji.ac.il> writes:
>
> > But than you lose the ability to define the abstract interface (for
> > Motor_Vehicle) and know that it is supported by all descendants.
>
> But it seems to me that you are *not* requiring the descendants to
> support that interface.  You are trying to let the descendants
support a
> different operation, also called "register", but with a different
> contract (ie, trucks can't register airplane drivers, although the
> parent type implied they could -- or whatever the example was).
>

Yep. In essence it is like saying that suporting a covariant interface
is still an IS-A relationship.

I am not sure if I am comfortable with this notion, but it does have an
impact on design.

> It's an interesting language design issue, anyway.
>

I'll add one more quote from the Eiffel book:
"The above two properties (P1 and P2) often seem surprising at first.
Why make type checking more difficult, and introduce the distinction
between class-level and system-level validity by allowing classes to
choose export and  argument typing policies different from those of its
parents?
The answer is the this felxibilty is indispensable to the practice of
object-oriented design. without it designer would constantly have to
reshuffle inheritance hierarchies, and would have much difficulty
observing the constraints of a typed object-oriented language. P1 and
P2 serve to acknowledge the inescapable difficulty of reconciling the
golas of orderly classifiaction (as implemented through inheritance)
and safety (as implemented through typing) with the irruglarities and
instability of the real-world situtations which our software systems
attempt to model through their inheritance hierarchies."

The is the view of the designer of Eiffel.

----
Ehud Lamm mslamm@mscc.huji.ac.il
http://purl.oclc.org/NET/ehudlamm
Check it out and subscribe to the E-List


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-23  0:00   ` Ehud Lamm
  1999-12-23  0:00     ` Robert Dewar
@ 1999-12-29  0:00     ` Brian Rogoff
  1999-12-30  0:00       ` Jeffrey L Straszheim
  1 sibling, 1 reply; 21+ messages in thread
From: Brian Rogoff @ 1999-12-29  0:00 UTC (permalink / raw)


On Thu, 23 Dec 1999, Ehud Lamm wrote:
> This issue of system validity is discussed in the "Eiffel the language"
> book, from which I took the examples. If any one is interested in
> looking it up. This is indeed the heart of this issue.

Just to refresh my memory, do any real Eiffel compilers do system validity
checking, or deal with "polymorphic catcalls" as decribed recently by
Meyer, or do all compilers just punt on this issue? 

Even the theoretical checks require global analysis right? This doesn't
sit well with the goal of separate compilation. 

Parameter covariance seemed like a huge mistake of the Eiffel design to
me. Is it all fixed and working now?

-- Brian





^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-29  0:00     ` Brian Rogoff
@ 1999-12-30  0:00       ` Jeffrey L Straszheim
  1999-12-31  0:00         ` Brian Rogoff
  0 siblings, 1 reply; 21+ messages in thread
From: Jeffrey L Straszheim @ 1999-12-30  0:00 UTC (permalink / raw)


Brian Rogoff wrote:

> Just to refresh my memory, do any real Eiffel compilers do system validity
> checking, or deal with "polymorphic catcalls" as decribed recently by
> Meyer, or do all compilers just punt on this issue?

Well, to use your term, they all "punt".
 
> Even the theoretical checks require global analysis right? This doesn't
> sit well with the goal of separate compilation.

True, which is among the reasons it has never been implemented. The
more restrictive "catcall" proposal does allow separate compilation,
but it would render a rather large subset of currently working Eiffel
software invalid. Myself, I would find that intolerable.
 
> Parameter covariance seemed like a huge mistake of the Eiffel design to
> me. Is it all fixed and working now?

I have mixed feelings. I've used covariance, and it turns out that I
found it generally useful, even while the holes in the type system
bothered me on a basic level. I've suggested several times on the Eiffel
forums that sufficient run time testing would be satisfactory. You
see, most current Eiffel flavors now simply fly into hyperspace if
you end up making an illegal catcall during execution. I think a run-
time exception would be a fine compromise.

At a certain abstract level, Ada has a similar issue, in that I can
declare a subtype and, as it turns out, have no formal guarantee that
I won't violate its constraint. In both situations one could make
the effort to prove that a violation will not occur, but in neither
case does the language formally guarantee it.

-- Jeffrey Straszheim          
-- Systems Engineer, Programmer
-- http://www.shadow.net/~stimuli
-- stimuli AT shadow DOT net




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-30  0:00       ` Jeffrey L Straszheim
@ 1999-12-31  0:00         ` Brian Rogoff
  1999-12-31  0:00           ` Jeffrey L Straszheim
  0 siblings, 1 reply; 21+ messages in thread
From: Brian Rogoff @ 1999-12-31  0:00 UTC (permalink / raw)


On Thu, 30 Dec 1999, Jeffrey L Straszheim wrote:
> Brian Rogoff wrote:
>  
> > Parameter covariance seemed like a huge mistake of the Eiffel design to
> > me. Is it all fixed and working now?
> 
> I have mixed feelings. I've used covariance, and it turns out that I
> found it generally useful, even while the holes in the type system
> bothered me on a basic level. 

Kind of like "conservative" (inaccurate) garbage collectors. You know its 
wrong even though it seems to work most of the time.

I preferred Sather's approach, though I admit contravariance isn't
"useful" there were acceptable workarounds for covariance. 

> At a certain abstract level, Ada has a similar issue, in that I can
> declare a subtype and, as it turns out, have no formal guarantee that
> I won't violate its constraint. In both situations one could make
> the effort to prove that a violation will not occur, but in neither
> case does the language formally guarantee it.

This is really not the same, as Ada subtypes aren't like Eiffel
subclasses. Its more appropriate to compare Ada subtypes with 
array bounds checking and the like. 

It is interesting that in lots of modern languages with sophisticated type 
systems the type checking is very hard, sometimes even undecidable. C++ 
with its templates come to mind, but OCaml's module system also has such 
problems.  

-- Brian






^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-31  0:00         ` Brian Rogoff
@ 1999-12-31  0:00           ` Jeffrey L Straszheim
  2000-01-02  0:00             ` Brian Rogoff
  2000-01-03  0:00             ` Matthew Heaney
  0 siblings, 2 replies; 21+ messages in thread
From: Jeffrey L Straszheim @ 1999-12-31  0:00 UTC (permalink / raw)


Brian Rogoff wrote:

> On Thu, 30 Dec 1999, Jeffrey L Straszheim wrote:

> > I have mixed feelings. I've used covariance, and it turns out that I
> > found it generally useful, even while the holes in the type system
> > bothered me on a basic level.
 
> Kind of like "conservative" (inaccurate) garbage collectors. You know its
> wrong even though it seems to work most of the time.

Fair enough. However, with covariance -- at least if it is used
wisely, which means not used much -- I can be certain that my program
is, ultimately, correct and will not make an invalid catcall. With
an inaccurate GC, I can write a correct progam, but have it bomb
when deployed because of faults in the GC.
 
> I preferred Sather's approach, though I admit contravariance isn't
> "useful" there were acceptable workarounds for covariance.
 
> > At a certain abstract level, Ada has a similar issue, in that I can
> > declare a subtype and, as it turns out, have no formal guarantee that
> > I won't violate its constraint. In both situations one could make
> > the effort to prove that a violation will not occur, but in neither
> > case does the language formally guarantee it.
 
> This is really not the same, as Ada subtypes aren't like Eiffel
> subclasses. Its more appropriate to compare Ada subtypes with
> array bounds checking and the like.

Of course it's not the same: no two different things are ever the
same. The point is Ada allows me to do this:

In some package specification:

 function Some_Opaque_Library_Function (Param: Integer) return Integer;

In my code:

 The_Largest_Fred : constant := 135;
 subtype Fred is range 0 .. The_Largest_Fred;

 A_Variable       : Fred := 0;
 Another_Varialbe : Fred;

 begin

   Another_Variable := Some_Opaque_Library_Function (A_Variable);

...

Now, nothing guarantees that the constraint for subtype Fred won't
be violated here, causing a runtime fault. (BTW, this is the sort
of place where DBC really helps, but I won't belabor that point.)

Now, one can debate whether this is a (potential) type error. If
so, the debate becomes a semantic one and a waste of time, but
let me just say that by some definitions of type, this is indeed
considered a type error. Again, I'd prefer not to belabor the point.

So, here is my point: catcalls are one area where Eiffel lets
its programmers shoot themselves in the foot. There are a few others,
namely the subclassing rules for generics (yuck), but all in all
I've found these problems easy to avoid, more so than avoiding,
say, buffer problems in C. I'm just learning Ada now, so I have
limited experience with it, but I suspect that I won't have problems
with its "gotchas" either. At least it seems so at first glance.
 
> It is interesting that in lots of modern languages with sophisticated type
> systems the type checking is very hard, sometimes even undecidable. C++
> with its templates come to mind, but OCaml's module system also has such
> problems.

-- Jeffrey Straszheim          
-- Systems Engineer, Programmer
-- http://www.shadow.net/~stimuli
-- stimuli AT shadow DOT net




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-31  0:00           ` Jeffrey L Straszheim
@ 2000-01-02  0:00             ` Brian Rogoff
  2000-01-03  0:00             ` Matthew Heaney
  1 sibling, 0 replies; 21+ messages in thread
From: Brian Rogoff @ 2000-01-02  0:00 UTC (permalink / raw)


On Fri, 31 Dec 1999, Jeffrey L Straszheim wrote:
> Brian Rogoff wrote:
> > This is really not the same, as Ada subtypes aren't like Eiffel
> > subclasses. Its more appropriate to compare Ada subtypes with
> > array bounds checking and the like.
> 
> Of course it's not the same: no two different things are ever the
> same. 

Yes, so you should compare similar features in the two languages. The 
analogous problem in Eiffel is that you don't know that you'll get a 
precondition violation at run time. Range constraints are like a
degenerate form of precondition. It isn't useful to compare them to
Eiffel's broken covariance. 

> So, here is my point: catcalls are one area where Eiffel lets
> its programmers shoot themselves in the foot. There are a few others,
> namely the subclassing rules for generics (yuck), but all in all
> I've found these problems easy to avoid, more so than avoiding,
> say, buffer problems in C. I'm just learning Ada now, so I have
> limited experience with it, but I suspect that I won't have problems
> with its "gotchas" either. At least it seems so at first glance.

Ada has its share of "gotchas", but IME most are just annoying
restrictions telling me I can't do something, rather than silently 
watching me do something stupid.

-- Brian






^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: OO puzzle
  1999-12-31  0:00           ` Jeffrey L Straszheim
  2000-01-02  0:00             ` Brian Rogoff
@ 2000-01-03  0:00             ` Matthew Heaney
  1 sibling, 0 replies; 21+ messages in thread
From: Matthew Heaney @ 2000-01-03  0:00 UTC (permalink / raw)


In article <386CFDEB.946C3336@shadow.net> , Jeffrey L Straszheim 
<stimuli@shadow.net>  wrote:

> Of course it's not the same: no two different things are ever the
> same.

To use Peter Wegner's terminology, it's the difference between "type
semantics" and "template semantics."

What "type semantics" means is that for a (scalar) type, you constrain
the range of possible values.

What "template semantics" means is that for a (tagged type) class, you
constrain the set of possible types, and therefore constrain the set of
operations possible.

So you are comparing apples and oranges.  If you're going to grok the
Ada way of doing things, you have to think in terms of

1) scalar types with their constrained ranges
2) array types with their index constraints
3) discriminated records with their discriminant constraints

and

4) tagged types and class-wide programming


> The point is Ada allows me to do this:
>
> In some package specification:
>
>  function Some_Opaque_Library_Function (Param: Integer) return Integer;
>
> In my code:
>
>  The_Largest_Fred : constant := 135;
>  subtype Fred is range 0 .. The_Largest_Fred;
>
>  A_Variable       : Fred := 0;
>  Another_Varialbe : Fred;
>
>  begin
>
>    Another_Variable := Some_Opaque_Library_Function (A_Variable);
>
> ...
>
> Now, nothing guarantees that the constraint for subtype Fred won't
> be violated here, causing a runtime fault.

Of course, because you-the-client made an unjustified assumption about
the return value of the function, by assuming a smaller range than was
specified in the function profile.

If there's a run-time error, then it's your fault for assuming a
stronger postcondition than was guaranteed by the function
specification.


> (BTW, this is the sort
> of place where DBC really helps, but I won't belabor that point.)

Then use DBC.  Declare your library function as returning subtype with a
smaller range:

  subtype Fred is Integer range 0 .. 135;

  function Some_Opaque_Lib_Func (Param : Integer) return Fred;
...
  Variable : constant Fred := Some_Opaque_Lib_Func (P);

Now you really do have a guarantee that no run-time fault will occur
(assuming of course the function is error-free, and satisfies its
postcondition).


> Now, one can debate whether this is a (potential) type error. If
> so, the debate becomes a semantic one and a waste of time, but
> let me just say that by some definitions of type, this is indeed
> considered a type error. Again, I'd prefer not to belabor the point.

The only "definition of type" that you should care about on CLA is the
Ada definition.  In Ada, there is no type error in your example!

A "type error" --as defined by Ada-- would have been caught at compile
time.  For example:

  type Barney is new Integer;

  B : constant Barney := Some_Opaque_Lib_Func (P);

This assignment is illegal, and will be caught at compile time, because
Barney is a different type from Integer.

Your original example had a "constraint error," because you violated the
range constraint of the object (which had subtype Fred).  It is not a
type error.





^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2000-01-03  0:00 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-12-22  0:00 OO puzzle Ehud Lamm
1999-12-22  0:00 ` Tucker Taft
1999-12-23  0:00   ` Ehud Lamm
1999-12-23  0:00     ` Robert Dewar
1999-12-23  0:00       ` Ehud Lamm
1999-12-24  0:00         ` swhalen
1999-12-25  0:00           ` Ehud Lamm
1999-12-25  0:00         ` Ehud Lamm
1999-12-29  0:00     ` Brian Rogoff
1999-12-30  0:00       ` Jeffrey L Straszheim
1999-12-31  0:00         ` Brian Rogoff
1999-12-31  0:00           ` Jeffrey L Straszheim
2000-01-02  0:00             ` Brian Rogoff
2000-01-03  0:00             ` Matthew Heaney
1999-12-22  0:00 ` Ted Dennison
1999-12-23  0:00   ` Ehud Lamm
1999-12-23  0:00     ` Ted Dennison
1999-12-25  0:00       ` Ehud Lamm
1999-12-23  0:00     ` Robert A Duff
1999-12-25  0:00       ` Ehud Lamm
1999-12-22  0:00 ` Jeff Carter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox