marcap@doyle.cs.concordia.ca (PAWLOWSKY marc) (02/20/90)
ASSUMPTIONS: The definition for INTEGER is int.e (It inherits from comparable). The compiler handles basic types (INT, STRING, REAL, .. ) specially THE EXAMPLE ARRAYS that can be sorted. THE PROBLEM ec can not handle constraints on basic types. DISCUSSION Creating a constrained generic type is very basic to OOP and Eiffel in particular. However the basic types for 2.2 can not be passed as constrained parameters. This limitation is most annoying. Since to bypass it artificial types become necessary, making the situation more complex than necessary. For example the class ARRAY_COMPAR class ARRAY_COMPAR[T -> COMPARABLE] export repeat ARRAY, is_sorted, quick_sort, merge inherit ARRAY[T] rename Create as array_create can not be used with a basic type. Trying to do so results in the error message Eiffel compilation manager (version 2.2 level A) Pass 3 on class test_array_compar "test_array_compar", 15: Basic type may not be used as actual generic type corresponding to a constrained formal generic parameter es: error in pass3 I do not think the compiler should treat basic types any different from other types when being passed. If the resulting code is more inefficent than so be it. Otherwise a class is necessary for each basic type, as well as another class for non-basic types. I do not believe this is in the "spirit" of Eiffels concepts on reusability. Marc Pawlowsky Graduate Student Concordia University
bertrand@eiffel.UUCP (Bertrand Meyer) (02/20/90)
In <1864@clyde.concordia.ca>, marcap@doyle.cs.concordia.ca (Marc Pawlowsky) voices concerns about basic types and their use as parents in inheritance. I essentially agree with his observations. To reconstruct the sequence of events: - In the original language design, as reflected in ``Object-Oriented Software Construction'', four types (INTEGER, REAL, BOOLEAN, CHARACTER) were treated specially, i.e. outside of the object-oriented context. The reason was twofold: a concern for performance; and a feeling that ``everyone knows about integers and booleans anyway'' and that using the OO framework to handle them was overkill. - After a while we recognized that it was in fact unpleasant to have this ``magical'' status for basic types, and that (thanks to expanded types, infix/prefix operators and constrained genericity, among others) it was indeed possible to have a fully consistent type system, elegantly covering basic types as well as user-defined types, without necessarily sacrificing implementation performance. As a result, the basic types are treated as ``quasi-normal'' in the release available since last summer (2.2). Internally, however, they are still handled specially so as to guarantee a high level of efficiency (3 + 4 is theoretically a routine call, but few Eiffel users would want it to be implemented that way!). In fact, this part is one of the trickiest in our implementation as we try to reconcile elegance of concept with efficiency of implementation. Furthermore, there are still many carryovers from the original implementation. For example (as pointed out by Norman Shelley and others) having a function ``abs'' (absolute value) for integers and a different one, ``rabs'', for real numbers, is anathema to the object-oriented approach. I am not particularly proud of that one (which, fortunately, will be easy to correct; it just escaped our attention). As we continue improving and generalizing the implementation, we will strive to achieve the degree of generality desired by Mr. Pawlowsky and other writers (and Eiffel users such as ourselves). Although we would like INTEGER et al. to be conceptually treated exactly like any other class-based expanded types, we cannot promise that ALL restrictions will be lifted soon. We want Eiffel to remain implementable with a very small performance overhead over something like C, and some tradeoffs need to be made for this goal to remain realistic. -- -- Bertrand Meyer bertrand@eiffel.com
weiner@novavax.UUCP (Bob Weiner) (02/21/90)
> As a result, the basic types are treated as ``quasi-normal'' in the > release available since last summer (2.2). Internally, however, they are > still handled specially so as to guarantee a high level of efficiency > (3 + 4 is theoretically a routine call, but few Eiffel users would want it > to be implemented that way!). In fact, this part is one of the trickiest in I do not agree with this statement since I believe that one cannot inherit from the basic types in order to create a new class which constrains the type's invariant further. (I must admit that I have tried to inherit from INT rather than INTEGER, and so forth, since there is no class interface corresponding to INTEGER.) Rather than sprinkle pre- and post-conditions around routines that say: require param > 0 and other such things, it makes sense to create classes for POS_INT, NON_NEG_INT and so forth and then type the formal parameters of the routines. The current implementation does not support this basic idea and hence event the term 'quasi-normal' seems too strong to me. I do hope that Eiffel V3.0 will correct this limitation. Even better, I would enjoy finding out that I am mistaken in my view. -- Bob Weiner, Motorola, Inc., USENET: ...!gatech!uflorida!novavax!weiner (407) 364-2087
bertrand@eiffel.UUCP (Bertrand Meyer) (02/23/90)
From <1799@novavax.UUCP> by weiner@novavax.UUCP (Bob Weiner): > Rather than sprinkle pre- and post-conditions around routines that say: > > require > param > 0 > > and other such things, it makes sense to create classes for POS_INT, > NON_NEG_INT and so forth and then type the formal parameters of the > routines. > > I do hope that Eiffel V3.0 will correct this limitation. Even better, I > would enjoy finding out that I am mistaken in my view. I agree that it should be possible for programmers to define such classes by inheriting from INT and adding the proper invariants. This is an implementation problem and I have had good hope that we (or others) will be able to solve it. Assuming this is the case, however, I am not so sure that these classes should be added to the Kernel Library. This is because I have some doubts about their practical applicability. (This should be taken literally: at this point I am neither for or against their inclusion in version 3, just doubtful.) The problem is that POS_INT, NON_NEG_INT etc. are not *closed* for the arithmetic operations. For example, with p1, p2: POS_INT; n1, n2: NEG_INT there is no guarantee that p1 - p2 will be a POS_INT or that n1 - n2 will be a NEG_INT. The best information we can deduce (the ``and'' in the lattice of types) is just INT. Similarly, if we define interval types of the form class INTERVAL export repeat INT, low, high inherit INT feature low, high: INTEGER; Create (a, b: INTEGER) is -- Set interval bounds to `a' and `b'. do low := a; high := b end; -- Create invariant value >= low; value <= high end -- class INTERVAL they will not help us very much since for n of type INTERVAL we have no static way of determining whether n + 1 is still compatible. In all these cases we will have to resort to assertions anyway. All this is not surprising. We should not hope that a static type system will magically solve problems that are fundamentally dynamic in nature. The problem is not essentially different from the situation with interval types in Pascal, as analyzed by A. Nico Habermann (``Critical Comments on the Programming Language Pascal'', Acta Informatica, 3, 1973, pages 47-57). The above is not a contention that Mr. Weiner is ``mistaken in his view''. Simply, I am not convinced that the suggested classes will solve more problems than they raise. -- Bertrand Meyer bertrand@eiffel.com
tynor@prism.gatech.EDU (Steve Tynor) (02/23/90)
In article <254@eiffel.UUCP> bertrand@eiffel.UUCP (Bertrand Meyer) writes: >From <1799@novavax.UUCP> by weiner@novavax.UUCP (Bob Weiner): > >> Rather than sprinkle pre- and post-conditions around routines that say: >> >> require >> param > 0 >> >> and other such things, it makes sense to create classes for POS_INT, >> NON_NEG_INT and so forth and then type the formal parameters of the >> routines. ... > In all these cases we will have to resort to assertions anyway. ... It's really a case of where we have to assert. Surely much better in a class than in each of its uses since the constraint is a property of the class. Perhaps, for efficiency's sake, it would be acceptable to dissallow multiple inheritance and feature (re)defintion for descendants of basic types. Thus: class INTERVAL_1_10 export repeat INTEGER inherit INTEGER invariant Current >= 1 and Current <= 10; end Sure, this restricts us to static interval bounds, but then this is all most programming languages provide. And it's better than what we have now. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= inherit STD_DISCLAIMER; Steve Tynor Georgia Tech Research Institute Artificial Intelligence Branch tynor@prism.gatech.edu
rowley@bath.cs.ucla.edu (Michael T Rowley) (02/23/90)
In article <254@eiffel.UUCP>, bertrand@eiffel.UUCP (Bertrand Meyer) writes: > [Intervals] will not help us very much since for n of type INTERVAL we > have no static way of determining whether n + 1 is still > compatible. > > In all these cases we will have to resort to assertions anyway. > > All this is not surprising. We should not hope that a > static type system will magically solve problems that are > fundamentally dynamic in nature. > > The problem is not essentially different from the situation with > interval types in Pascal, as analyzed by A. Nico Habermann > (``Critical Comments on the Programming Language Pascal'', > Acta Informatica, 3, 1973, pages 47-57). > I have to disagree with statement that these problems are dynamic in nature. Significant research has been done with "strengthened" types to make it possible to catch range errors at compile time. The main reference I have is Paul Eggert's 1981 Ph.D. dissertation, which is available as a technical report from UCLA. Since then, he has gone to Twinsun, where they are developing "C-cured" which uses strengthened types. I am not an expert on the subject, but it involves having the compiler know about subranges, and making sure that all assignments are to conforming expressions (expressions that result in the same or smaller range as the lvalue). This changes the way some code is written, for example "n = n + 1" is never allowed. But the comparisons I have seen between code written without vs. with strenthened types convinced me that the restrictions do not add to many lines to the code. The original version was from an Introductory programming textbook, and the conversion brought to light 3 logic errors from the published original. Both the original and the converted version had 250-300 lines of code (depending on indenting style). More recent papers could probably be obtained by contacting Paul Eggert at Eggert@twinsun.com. - MTR P.S. I have nothing to do with the C-cured project. I saw a talk given by him, and think that some of the concepts could benefit eiffel.