From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.3 required=5.0 tests=BAYES_00, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: fac41,c52c30d32b866eae X-Google-Attributes: gidfac41,public X-Google-Thread: 103376,2ea02452876a15e1 X-Google-Attributes: gid103376,public X-Google-Thread: 1108a1,c52c30d32b866eae X-Google-Attributes: gid1108a1,public From: donh@syd.csa.com.au (Don Harrison) Subject: Re: Real OO Date: 1996/04/23 Message-ID: X-Deja-AN: 150941421 sender: news@assip.csasyd.oz references: organization: CSC Australia reply-to: donh@syd.csa.com.au newsgroups: comp.lang.eiffel,comp.lang.ada,comp.object Date: 1996-04-23T00:00:00+00:00 List-Id: Jon S Anthony writes: :In article donh@syd.csa.com.au (Don Harrison) writes: : :> :> Yes, Eiffel's frozen routines alone are not the equivalent of Ada's classwide :> :> operations. The Eiffel analogue is a combination of: :> :> :> :> a) frozen routines, which make a routine classwide for Current, and :> :> b) parameters, all of which are classwide by default, and :> :> c) results of functions, which are classwide by default. :> :> :> :> This provides the same generality and flexibility of Ada's classwide :> :> operations. :> : :> :I don't see how. :> :> I think the examples which I listed speak for themselves. Do you dispute that : :No, here I'm talking about the points I made in this paragraph, :not the table stuff you gave. Okay. :> : For one thing clients can't define such things :> :without introducing gratuitous/extraneous classes (I would say this is :> :one of the more important uses). :> :> Not sure what you mean here. Classes T and U are not extraneous and no more :> classes need to be defined. : :Simply this: Classwide operations can be defined anywhere by anyone. :They do not have to be defined along with the primitive types in :their packages. In OO software, you would want to define them with their types (except that in Eiffel, you assign the operation to a particular type - whichever is most appropriate). Otherwise, you would end up with spaghetti, IMO. : So, suppose I have my T and U types (and classes) :as you gave in your table. Long after the types/classes have been :defined I am writing a client and decide that I need a new operation :which is general to these types and a new one that I've just defined, :S. It has signature, : :procedure Op (a: T'Class; b,c: U'Class; d: S'Class); : :In Ada, I can define this in my specific application as I see fit. : :Now, in Eiffel you need something like, : :in Class T in U in S :frozen Op ( frozen Op( frozen Op( : b:U,c:U,d:S) a:T,c:U,d:S) a:T,c:U,b:U) Except that you would only need one of them - not three. Note that in any one of these, each formal parameter is effectively classwide, including Current. So, you only need one of these, as you would in Ada. :But this would mean changing the class definitions for all three :classes. : Even with some clairvoyance you'd have trouble as you :couldn't know about S when T and U were defined. So, one possible :out would be to subclass them all and put the new frozen features :in these new "extraneous" classes and use them instead. Hopefully, these comments are no longer relevant. :> : For another, you need some :> :clairvoyance when designing a class in determining the set of features :> :to freeze in order to use them in these sorts of combinations :> :elsewhere. :> :> This is no different from Ada. : :See the discussion above for why this is not true. Ditto. [In here, we agreed on something, even if it was only to diasagree :-)] :> I guess the Eiffel equivalent to :> Ada's multiple controlling operands is something like (assuming the same :> definitions): :> :> function k (a: T; b: T) return T is k (b: like Current): like Current is :> begin require :> ... Current.conforms_to (b) :> end do :> ... :> ensure :> Current.conforms_to (Result) :> end :> :> A little more long-winded but notice the semantics is probably really closer :> to what you want because the test on the dynamic type of Result is made after :> the routine body: it's nonsense to make assertions about the Result until it : :This is true in the Ada case as well. The body is statically checked to :ensure that the result is T, of course, but during a runtime dispatch :the actual result is checked to ensure its dynamic type conforms to :its context. So, Ada loses nothing here. Okay. :> I hope you will agree by now that Eiffel and Ada are as flexible as each other :> in terms of the mechanisms they offer. : :I'm not sure about that. Maybe part of the issue is that "flexible" :is not the appropriate term for this discussion... Not sure what are you still unsure about. :>...[multiple controlling params again...] :> Mostly facetious. But I do find it slightly ridiculous to say that there are :> multiple controlling operands if it only works if they happen to have the same :> dynamic type. : :I wouldn't say ridiculous as there are some nice aspects you get even :at this level. How about, less flexible ;-) Okay. :> (No, I'm not saying that it should be possible for them to be :> different). : :Actually, I'm not so sure about this. I understand why this limitation :was made, but certainly CLOS and Dylan folk would say this _should_ be :possible. And they have a point too. Is this what is meant by multiple dispatching? :> The fact that you get an exception if the types differ is not as :> plain as in the Eiffel paradigm, IMO. : :OK, but I don't see this. Only because it is explicitly stated. Nothing to get too excited over, though. :> You are referring to catcalls: calls which fail because a descendant class : :The important point is that these can't be checked at compile time :(well, at least not in Eiffel 3), but that the rules require the :checks be made _before_ accepting the _system_ for execution. When I :say less flexible here, I just mean that _less_ cases can get through :to runtime. This _can_ be a _good_ thing. : : :>a) a type has been redefined to a non-conformant type, or :>b) a routine has been made inaccessible due to a change in it's export status. :> :>At first sight, it seems silly to permit such things if they can :>cause problems with polymorphism but there is a worthy motivation for :>providing such flexibility: :> :>allowing reuse of legacy code that does not exactly fit your requirements. :^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ : :I don't quite follow this. It does not seem to have much of anything :to do with the problem of system validity checks. I suppose you can :claim that overiding export policies and making covariant routine :signatures (I think you mean conforming, not non-conforming) is :is necessary to the emphasized goal, but I don't see it. Yes, I was wrong. It should be conforming signatures, as you say. (I was trying to avoid looking it up). A good example illustrating both a) and b) is in ETL, 22.6 - Notes on the type policy. Suppose you have: class DRIVER ... end class CAR_DRIVER inherit DRIVER ... end class TRUCK_DRIVER inherit DRIVER ... end and class VEHICLE feature register_driver (d: DRIVER) is ... renew_rego_by_mail is ... ... end class CAR inherit VEHICLE ... feature register_driver (d: CAR_DRIVER) is ... ... end class TRUCK inherit VEHICLE export {NONE} renew_rego_by_mail -- trucks must be inspected ... feature register_driver (d: TRUCK_DRIVER) is ... renew_rego_by_inspection is ... ... end Example of a) ------------- If, in a client, you have: d: DRIVER cd: CAR_DRIVER v: VEHICLE t: TRUCK ... d := cd v := t v.register_driver (d) -- catcall: class valid but not system valid Example of b) ------------- In the same client: v.renew_rego_by_mail -- catcall: class valid but not system valid : This goal is :trivial to achieve in Ada, do in large part to separation of :specifications (interfaces) and implementations (yeah, that old :argument). Add to this separation of interface and implementation :inheritance, and these problems disappear. Can you explain how these avoid the problem? :> the good reason of allowing reuse of legacy code) and this can cause runtime :> errors. If Ada were just as permissive, it would be a problem for Ada too. :> In Ada, you can't reuse such code that almost meets your needs; you have to :> rewrite it which could be a formidable task. : :But this is _trivial_ to achieve in Ada without resorting to system validity :checks. I don't know why you make such an odd claim. Probably because it is more of a deduction rather than actually knowing the reason whether or why it isn't a problem in Ada. However, making such deductions is not wise, I admit :-). :> The intended purpose of system-level validity checks is to identify :> and exclude at compile time the stuff that would cause runtime :> errors. : :This is just plain wrong. System validity checks don't happen at :compile time, but rather at binding/link time ("long" after the source :has been compiled). Okay, I should have said 'statically' rather than 'at compile time'. >From ETL, 18.10 - Creation validity (system level): "System-level validity, as all other validity properties, is a *static* requirement". :> for runtime. (Yes, I know that few, if any, Eiffel vendors implement :> it). Don't know what you mean here. : :I mean simply that invalid Eiffel systems are knowingly accepted by :these implementations. Correct. :> : And the reason it is a problem :> :is that Eiffel source does not have as much semantic information in it :> :in this area. :> :> What might that be? : :Specifically, the distinction and use of the difference between class :and type. The funny thing is, all this brouhaha about system validity :concerns this distinction and an attempt to try to separate them :again. No. This is not why. It's due to the distinction between static and dynamic types. : Meyer's "dynamic type set" is pretty much an Ada class and his :"dynamic class set" is pretty much a class-wide type. No. There is not really an equivalent concept in Ada because it does not support generic tagged types (as far as I'm aware) or anchored types. The dynamic type set is the set of all possible dynamic types whereas the dynamic class set is the set of all classes these are derived from. A generic class in the dynamic class set becomes numerous types in the dynamic type set. :> :was a rather good discussion of this stuff about a year ago. Maybe I :> :can dig that up. :> :> Please do. : :I will try to look it up. If Robb Nebbe is reading, maybe he has a ready :and complete "transcript". He was a major participant. : :/Jon : :-- :Jon Anthony :Organon Motives, Inc. :1 Williston Road, Suite 4 :Belmont, MA 02178 : :617.484.3383 :jsa@organon.com : Don.