This technical note is excerpted from the text of a proposal submitted by ISE to the Nonprofit International Consortium for Eiffel (NICE). It describes a set of extensions to Eiffel.
This is a working document, precise for the most part but informal in places, and is currently under discussion.
The original form of this document was entitled Tuples, routine objects and iterators and covered important applications of tuples. These applications now have a detailed discussion of their own. Make sure to read that discussion once you have learned about tuples.
Because the note followed earlier discussions within the language committee of NICE, it lacks the customary "introduction" and "rationale" parts explaining the purpose of the proposed extensions. The rationale and applications should, however, quickly become clear to any reader familiar with Eiffel.
The mechanism described below is available in ISE Eiffel 4.3, with a few limitations detailed below.
1. Tuple types
A new Kernel Library class is introduced: TUPLE.
Alone among all classes, class TUPLE has a variable number of generic parameters. TUPLE, TUPLE [X], TUPLE [X, Y], TUPLE [X, Y, Z] and so on are all valid types, assuming valid types X, Y, Z and so on.
[CONF1] For n >= 0 TUPLE [U1, U2, ..., Un, Un+1] conforms to TUPLE [U1, U2, ..., Un]
In particular all tuple types conform to TUPLE, with no parameter.
[CONF2] For n >= 0 If *every* one of the types T1, T2, ..., Tn conforms to a type T, then TUPLE [T1, T2, ..., Tn] conforms to ARRAY [T].
Definition: a "tuple type" is any type based on class TUPLE, i.e. any type of the form TUPLE [T1, T2, ..., Tn] for any n (including 0, for which there is no generic parameter).
The domain of f contains the interval 1..n (in other words, f is defined for any i such that 1 <= i <= n).
For 1 <= i <= n, f (i) is a member of Ti.
With this definition, TUPLEn is indeed a subset of TUPLEn+1, and in particular TUPLE0, the empty set, is a subset of TUPLEn for any n.)
Semantics: an instance of TUPLE [T1, T2, ..., Tn] is a tuple whose first element is an instance of T1, the second element being an instance of T2 etc. (The precise definition is the mathematical one given in note 1.) Note that there can be more than n elements to the tuple: for example a tuple with first element 5 and second element "FOO" is an instance of all of the following tuple types: TUPLE; TUPLE [INTEGER]; TUPLE [INTEGER, STRING].
C [G -> TUPLE]
and then use the generic derivations
C [TUPLE [X]] C [TUPLE [X, Y]]and so on. This also makes it possible to have the effect of some fixed parameters and some variable ones, as in
C [G, H, I -> TUPLE]
so we have all the necessary flexibility.)
2. Tuple expressionsLet e1, e2, ..., en be expressions of respective types T1, T2, ..., Tn. Then the expression
[e1, e2, ..., en]
denotes an instance of TUPLE [T1, T2, ..., Tn], whose first element is e1, the second element being e2 etc.
Tuple expressions can be nested: whereas
[1, 2, 3]
is a tuple with three elements (representing an instance of TUPLE [INTEGER, INTEGER, INTEGER]),
[1, [2, 3]]
is a tuple with two elements, the second one itself a tuple; the overall expression represents an instance of TUPLE [INTEGER, TUPLE [INTEGER, INTEGER].
As a special case of tuple expression syntax, the delimiters [ and ] are replaced by parentheses for the tuple representing the actual argument list of a routine call (see section 4).
3. TUPLE features
The exact specification of class TUPLE will be described in an addition to ELKS. The principal features are:
count (number of significant elements)
item (i), with the obvious precondition: the i-th element, of type ANY (since the value of i is not known at compile time); also first, second, third, fourth and fifth, of the appropriate types.
put (x, i), with the obvious precondition: replace i-th element with x. If argument x is not of the appropriate type Ti there is no effect.
is_equal: redefined to consider only the first n elements, where n is the smaller length.
Other features under consideration include:
stripped (i): a tuple of type TUPLE [T1, T2, Ti-1, Ti+1, ..., Tn], derived from the current one by removing the i-th component, again with the obvious precondition.
wedged (x, i): a tuple with one more element, inserted at position i.
infix "+": tuple concatenation
infix "++": element concatenation; t ++ x is the same thing as t.wedged (x, t.count + 1).
In addition, there may be in class GENERAL the following three features:
acceptable_tuple (t: TUPLE): BOOLEAN -- Is t convertible into an object of the current -- type? associated_tuple: TUPLE -- Tuple made of all of this object's field ensure acceptable_tuple (Result) make_from_tuple (t: TUPLE) -- Reset from t. require acceptable_tuple (t) ensure equal (associated_tuple, t)
4. What have we gained?
First we have solved the only case in the Eiffel language in which an expression has no precisely defined type: polymorphic manifest arrays. We don't have manifest arrays any more, but manifest tuples, with a precisely defined type. No incompatibility is introduced thanks to rule CONF2. The original syntax for manifest arrays, Result := <<e1, e2, ..., en>>, will continue to be supported.
Second, we can define functions that return multiple results. This is a quite significant increase in expressive power. No common language has that. (You have to go to Lisp and functional languages.) Just define TUPLE [...] as the result type; in the function, you will write things like
Result := [e1, e2, ..., en]
Also, from a theoretical viewpoint, feature calls are simpler and more homogeneous: every feature takes exactly one tuple as argument and returns exactly one tuple as a result. (Either of these tuples may be empty: the first for a feature with no argument, the second for a procedure.) The syntax for a call becomes
with Arguments defined as
where the Tuple_expression uses the form given in section 2 but with the outermost [ and ] delimiters replaced by parentheses to conform to usual practice. So the call
f (a, b, c)
which we continue to think of as having three arguments a, b and c, formally has only one tuple argument [a, b, c]. This is of course not to be confused with a call of the form
g ([a, b, c])
which has one argument (a tuple with three elements) in both the ordinary and the formal sense.
5. Active, iterators, numerical applications, introspection
For a set of important applications of tuples see the book chapter on delayed calls and iterators which also covers aspects of numerical software and related topics following from the tuple mechanism.
6. Temporary limitations
The implementation of tuples in ISE Eiffel 4.3 has the following limitations:
Conformance of ARRAY types to TUPLE types is not yet fully supported.
Class TUPLE does not have features such as first and second. You must use item and, in most cases, an assignment attempt.