This site contains older material on Eiffel. For the main Eiffel page, see http://www.eiffel.com.

NICE Language Committee: ms-m_arr

From Michael Schweitzer
Date: Sat, 16 Apr 94 15:07:14 +0200
To: bertrand@eiffel.com
Subject: MS-M_ARR
Cc: tynor@atlanta.twr.com
Content-Length: 5651
X-Lines: 177
Status: RO

-----------------------------------------------------------
Key    : MS-M_ARR
Title  : Questions about manifest arrays
-----------------------------------------------------------

I have several questions about manifest arrays. These questions
are motivated by implementation problems.

Question 1:

As far as I can see, there is no rule which makes instructions
of the following form illegal:

        e := (<<1, 'X', "Hello">>).item (i)

(assuming that 'i' is of type INTEGER). In other words,
a manifest array is syntactically an expression and can
therefore be used as the target of a call. However, in this
example it is impossible to determine the type of 'item (i)'
since it is impossible (in general) to determine the value
of 'i' (the manifest array itself has no specific type).

Question 2:

Is the following instruction legal?

        a := <<1, 'X', "Hello">>        -- where 'a' is of type ANY?


Implementation problem:

If an instance of a generic class does not carry (somehow)
all the information about it's type (i.e. including the
actual generics) then dynamic conformance checking cannot be
implemented correctly. For example, if O1 is of type
ARRAY [T1] and O2 of type ARRAY [T2] and both O1 and
O2 only know that they are ARRAYs, then an assignment
attempt of the form

            O1 ?= O2

will always succeed. This is, of course, not correct.

Therefore, in our new implementation, objects of generic
type 'know' all their actual generics. This, however poses
a new problem: When the compiler encounters a manifest
array, it must produce code which will create an ARRAY. But
it is now impossible to create just an array: the actual
generic must also be supplied. In the above examples this
is impossible (what should the actual generic type be?).

As a consequence, I had to restrict the use of manifest arrays
to four cases:

    1) As source of an assignment, where the target has
       type ARRAY [T] for some type T, i.e.

                a := <<...>>    -- 'a' of type ARRAY [T].

    2) As source of an assignment attempt, where the target has
       type ARRAY [T] for some type T, i.e.

                a ?= <<...>>    -- 'a' of type ARRAY [T].

    3) As actual argument in a routine call, where the
       formal argument is of type ARRAY [T] for some
       type T, i.e.

                r (<<...>>)

    4) As an element of another manifest array, which
       (recursively) satisfies one of 1), 2), 3) or 4).

All other possible uses of manifest arrays are rejected
by the compiler. In cases 1) - 4), it is possible to
determine a creation type: simply use the type of the
target (ARRAY [T]).

I have the feeling that this is more or less what Bertrand
had in mind (?).

Consequences:

Let X, Y, U, V be classes, where both U and V inherit from
X and Y (see example in ETL) and assume we have the
following declarations and instructions:

        x_arr : ARRAY [X]
        y_arr : ARRAY [Y]
        u     : U
        v     : V

        x_arr := <>       -- (1)
        y_arr := <>       -- (2)

Both (1) and (2) are valid. The array created in case (1)
(in our new impl.) will be of type ARRAY [X], in case (2)
it will be of type ARRAY [Y]. As far as I can see this
does not violate any language rules. Now look at the
following code fragment (same declarations as above):

        x_arr := <>       -- (1)
        y_arr ?= x_arr          -- (2)
        y_arr ?= <>       -- (3)

Again, the type of the array created in (1) will be
ARRAY [X]. The assignment attempt in (2) will fail (i.e.
y_arr will be Void), since the dynamic type of x_arr
is ARRAY [X] which does not conform to ARRAY [Y]. However,
the assignment attempt in (3) will succeed, since the
type of the array is determined from the target (y_arr).

This seems strange but I don't see a way to avoid it.

Summary:
=======

Our new compiler implements the following rules and
semantics for manifest arrays:

    a) Their use is restricted to cases 1) - 4) as
       explained above.

    b) An instruction of the form (including argument passing)

            a := <>

       where 'a' is of type ARRAY [T] has the following
       semantics (assuming the types of the 'ei' conform
       to type T):

       1) Create an object of type ARRAY [T] with lower
          index bound 1 and upper index bound n.

       2) Evaluate expressions e1, .., en and put their
          values at indices 1, ..., n in the array.

       3) Attach a reference to this array to 'a'. DONE.

       (NOTE: 2) is of course skipped if n = 0).

    c) An instruction of the form

            a ?= <>

       where 'a' is of type ARRAY [T] has the following
       semantics:

       1) If the type of at least one of the 'ei' does
          not conform to 'T', then

          Evaluate expressions e1, ..., en and throw
          away their results.

          Attach 'Void' to 'a'. DONE.

       2) Otherwise the types of the 'ei' all conform
          to 'T'. Follow the steps in b) (1 - 3).

One further remark is necessary for the case of nested
manifest arrays. In an instruction of the form

            a := <>

where a is of type ARRAY [ARRAY [T]] and one of the 'ei'
is itself a manifest array, the type of the array created
for 'ei' will be ARRAY [T]. That is, the rules are
applied recursively.
-----------------------------------------------------------
NOTE: The creation semantics which are used here are over-
      simplified. For a more detailed discussion see
      "MS-creation".
-----------------------------------------------------------

Best regards,
    Michael