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/19 Message-ID: X-Deja-AN: 148321996 sender: news@assip.csasyd.oz references: organization: CSC Australia reply-to: donh@syd.csa.com.au newsgroups: comp.lang.ada,comp.lang.eiffel,comp.object Date: 1996-04-19T00:00:00+00:00 List-Id: Robert I. Eachus writes: :In article donh@syd.csa.com.au (Don Harrison) writes: : : > Yes, it may be that an Ada programmer might choose static binding because : > they know the entity happens to be of a specific type. This is fine if it : > is known that the type is absolutely set in concrete. : : > However, we need to consider why it is known. Normally, it will be : > known because the (transitive) source of the value it last : > received was itself a statically bound call. That is, one designed : > to handle a specific abstraction, rather than a family of : > abstractions; it is not designed for reuse. If the routine : > servicing the call is designed for reuse, then it returns an : > indeterminate dynamic type which demands dynamic binding when we : > use the returned entity as an actual parameter to the operation we : > are designing. : : You worry about a real, but not very major problem. The Ada :mechanism is simple, elegant, and results in very reusable code. But :it can give you a blinding headache if you try to understand the :simple rules that apply to the abstraction and the simple rules that :apply to the implementation at the same time. What I'm basically saying about Eiffel is that it's use would tend to maximise reusability and flexibility in developed software due to the defaults of the language: a) reusability - the default is that a routine is extendable (not frozen) b) flexibilty - the default is that entities are polymorphic, so will maximise (theoretical) dynamic binding when used as actual parameters. This equates to flexibility, IMO. I acknowledge you can do exactly the same things in Ada but believe an Ada programmer would typically use static binding more often than an Eiffel programmer and would tend to use classwide operations more than an Eiffel programmer. If both of these were true, it would be true to say that the resulting Eiffel software would be more reusable and more flexible. The issue of redispatching is a different one, I think. Without addressing what you have said in detail, I would like to comment that I think it is incorrect to allow dispatching to an ancestor routine of an object as in your example: [...] : type Foo is tagged ....; : : function Bar(F: in Foo) return Boolean; : : procedure Barf(F: in out Foo); : : procedure Barf(F: in out Foo) is : begin : if Bar(F) then... : end Barf; : ... : : type Foobar is new Foo with ...; : : function Bar(F: in Foobar) return Boolean; : ... : : X: Foobar; : Y: Foo'Class := X; : ... : : Barf(Y); : : So far so good. But in the (dispatching) call to Barf of Y, the :call to Bar is directed to Bar for Foo not Bar for Foobar. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ : Is this a :problem? Not really. Without thinking too hard about it, I think this could cause problems. IMO, binding should always be to the routine defined for the class corresponding to the object (unless the operation is classwide, of course). The object has specific characteristics which may need special attention that the ancestor routine will not provide An analogy of the problem might be: It's fine to use a chainsaw to cut down a tree, but you'll have problems if you try to use it for timber craftwork instead of a fretsaw. You may argue that the ancestor routine may redispatch to the correct routine but an ancestor should have no knowledge of it's descendants. This is the chicken before the egg. Eiffel always dispatches to the operation designed for the object. [deleted for brevity] : More often you run into cases where the explicit redispatch is the :right approach, but it usually occurs where no original dispatch is :required, so there is no "extra" overhead: : : procedure Put(Obj: in Object_Type'Class) is : begin Put(Default_File, Obj); end Put; : pragma Inline(Put); : : procedure Put(F: in File, Obj: in Object_Type) is... You would do this in Eiffel with a combination of frozen and normal features. [...] :-- : : Robert I. Eachus : :with Standard_Disclaimer; :use Standard_Disclaimer; :function Message (Text: in Clever_Ideas) return Better_Ideas is... Don.