* OO puzzle @ 1999-12-22 0:00 Ehud Lamm 1999-12-22 0:00 ` Ted Dennison ` (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-22 0:00 OO puzzle Ehud Lamm @ 1999-12-22 0:00 ` Ted Dennison 1999-12-23 0:00 ` Ehud Lamm 1999-12-22 0:00 ` Jeff Carter 1999-12-22 0:00 ` Tucker Taft 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 ` 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 ` 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 ` 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 ` 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-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-22 0:00 OO puzzle Ehud Lamm 1999-12-22 0:00 ` Ted Dennison @ 1999-12-22 0:00 ` Jeff Carter 1999-12-22 0:00 ` Tucker Taft 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 ` Ted Dennison 1999-12-22 0:00 ` Jeff Carter @ 1999-12-22 0:00 ` Tucker Taft 1999-12-23 0:00 ` Ehud Lamm 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
* 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-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-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-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 ` 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-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 ` 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 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
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox