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.2 required=5.0 tests=BAYES_00,INVALID_MSGID, 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: Detecting type mismatch at compile time (was Re: Real OO) Date: 1996/04/04 Message-ID: #1/1 X-Deja-AN: 145705271 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-04T00:00:00+00:00 List-Id: Robert I. Eachus) wrote: :In article <65lDeVZF3RB@herold.franken.de> jhd@herold.franken.de (Joachim Durchholz) writes: : > My (somewhat dogmatic) belief is that a program shouldn't fail : > with a typing error at run-time. Types are a mechanism introduced : > to allow the compiler to catch errors. This is a pure opinion, : > based on nothing more than the void in my head ;) - but I think I : > could justify it, though with much handwaving. Agree. I suppose the Eiffel approach would be for the client to pretest compatibility before making the call (as you could in Ada) and preserve the integrity of the target with a precondition requiring the dynamic types (feature 'dynamic_type' of class INTERNAL) of Current and the parameter are compatible. This protection is stronger than Ada's because the point of failure is BEFORE the body of the routine is executed rather than WHILE it is executed. : But the case being discussed above is exactly the one that can't be :detected until run-time. For example, I can have a fruit class: Equivalent Eiffel interspersed (omitting semicolons because they are optional): : type Fruit is abstract tagged null record; class FRUIT ... end :-- and some member subclasses: : : type Apple is new Fruit with private; : type Orange is new Fruit with private; class APPLE inherit FRUIT ... end class ORANGE inherit FRUIT ... end :-- a type that designates any Fruit: : : type Fruit_Pointer is access Fruit'Class; Don't need this due to Eiffel's default reference semantics. :-- now I make an array of Fruit_Pointers: : : type Fruit_Arrangement is array (Integer range <>) of Fruit_Pointer; class FRUIT_ARRANGEMENT inherit ARRAY [FRUIT] ... end :-- and an instance of Fruit_Arrangement: : : FA: Fruit_Arrangement(1..10); fa: FRUIT_ARRANGEMENT Don't need to constrain size of arrangement. If it is implemented as an array, the size may be changed dynamically (with a performance penalty; obviously, if the arrangement is changing often, you would use something other than an array). : Now at execution time I put some apples and some oranges in my :fruit arrangement, then do: : : S := FA(x) + FA(y); s.add_fruit (fa@x, fa@y) (Of course, to faithfully model the situation, you would first remove fruit from one arrangement before adding them to another). : It is only at run-time that I know whether I am trying to add :apples and oranges. In the corresponding case, where the type of the :operands can be determined at compile time, the error would be :diagnosed at compile time. (Unless, of course, the programmer had :explicitly defined an operation to add apples to oranges. ;-) Likewise with Eiffel. : Maybe that smiley is misplaced. There is a technique in Ada 95 for :cases where you do want to support heterogeneous operations. The :fully general case often requires declaring several primitive :operations for each of the "visible" operations, but the others can be :private, and in some cases never need to be overridden. In the much :more common case where the result type is always the same we could :define: : : function "+"(L,R: Fruit'Class) return Fruit_Arrangement; : function "+"(L: Fruit_Arrangement; R: Fruit'Class) return : Fruit_Arrangement; : function "+"(L: Fruit'Class; R: Fruit_Arrangement) return : Fruit_Arrangement; : function "+"(L,R: Fruit_Arrangement) return Fruit_Arrangement; : : The body of the first plus is obviously: : : function "+"(L,R: Fruit'Class) return Fruit_Arrangement is : begin : return : Fruit_Arrangement'(1 => new Fruit'Class(L), 2 => new Fruit'Class(R)); : end "+"; add_fruit (f: FRUIT) is ... end add_arrangement (a: FRUIT_ARRANGEMENT) is ... end make (f1, f2: FRUIT) is ... end : : Robert I. Eachus Don.