Current implementation of multi constraint formals
Warning: Warning: Article under development
Contents
Introduction
The first implementation of multi constraints is done and this article describes its current implementation status.
Let's take this example
MULTI[G -> {H, COMPARABLE rename is_equal as is_equal_cmp end}, H -> {NUMERIC rename default_create as default_create_num end, G}]
A type satisfying the constraint of G has the following properties:
- It conforms to whatever H is and therefore
- to
NUMERIC
and - by recursion to itself (G)
- to
- It conforms to its second constraint which is
COMPARABLE
.
A type satisfying the constraint of H has the following properties:
- It conforms to
NUMERIC
. - It conforms to G and therefore
- by recursion to itself (H) and
- to
COMPARABLE
.
As G and H both have to conform to each other the only possibility to satisfy this is that G and H must be the same in the generic derivation. It does not make much sense to program something like that but it is part of the current implementation.
Feature calls
Let's have a look at the following feature written in class MULTI:
feature g: G f: BOOLEAN -- Sample feature do create g -- 1 Result := g.is_equal(g) -- 2 end
The following rules have to hold for each call on a multi constraint formal:
- Every feature which is called has exactly one class which is used as the static type for the call.
This is a major difference to the ECMA standard which allows a call to features which are available through different classes as long as it is the same feature. A definition of what the same feature means can be found here.
In order to achieve that goal if a feature occurs with the same name in different classes one uses a rename clause and renames that feature. If there are name clashes between features and one does not want to call that feature a renaming is not needed.
As we perform calls to default_create
(line 1 of f
) and is_equal
(line 2 of f
, which are both features from ANY
and each occurs as the same feature once in COMPARABLE
and once in NUMERIC
. We do this despite the fact that it is actually the same feature. The reason for this can be found in the new semantics of the dynamic binding described in the standard. You may also want to have a look at the following article which discusses the issue.
Renaming on formals
The current implementation rejects a rename clause which is applied to a formal. The following code is therefore currently rejected as H is a formal and we don't allow a renaming on it.
class MULTI[G -> {H rename is_equal as is_equal_prime end, ANY}, H -> ANY]
The rules implemented are chosen so that they are the most restrictive. This is to ensure that written code is likely to compile in the future where the rules might be more relaxed.
Implementation details
The central classes to the current implementation are:
-
TYPE_SET_A
-
EXTENDED_TYPE_A
-
RENAMING_A
-
CONSTRAINING_TYPE_AS
- and some changes to
CLASS_C
The main tasks which have to be performed are:
- Type checking in particular type conformance.
- Feature lookup
Both tasks are provided by TYPE_SET_A
.
TYPE_SET_A
Conformance
The feature conform_to
inherited from TYPE_A
can be used to check whether a type set conforms to another type which is possibly a type set as well.
- A type set conforms to another type if at least one type in the type
set conforms to the type.
- Another type conforms to a type set if it conforms to all types in the type set.
- A type set ts1 conforms to a type set ts2 if for each type t in ts2 there is at least one type in ts1 which conforms to t.
If every type is regarded as a type set with one element one can simply always use the last rule.
Feature lookup
There are various features which provide this functionality. Their differences are mostly in the amount of information they provide. Of course the computation gets more expensive if the feature returns more information. Currently the API is pretty much targeted to what the compiler needs. There's a bunch of features of the family e_feature_state_*/feature_i_state_* which are used when most likely only one feature occurs. As soon as you need more information the features of the family info_about_feature_* can help you to get all information about a certain feature for a given type set.
Associated class
This feature is no longer available and therefore exported to NONE. This is simply because there is no single associated class but many.
You can use the feature associated_classes instead and get a list of all associated classes.
However, the features applicable to the type set is not the same set as the features provided by each element of the associated_classes. This is because one loses the renaming (class RENAMING_A
) which is stored inside the TYPE_SET_A
in each EXTENDED_TYPE_A
instance. This is why there are some places in the code where going from a CLASS_C
instance to one of type LIST [CLASS_C]
is not enough.
EXTENDED_TYPE_A
The EXTENDED_TYPE_A
class basically encapsulates a TYPE_A
object and a RENAMING_A
object.
{EXTENDED_TYPE_A}.type</a> or <e>{EXTENDED_TYPE_A}.actual_type</a> if your code makes assignment attempts, it is pretty much the same as with the family of the "like" types. ===RENAMING_A=== This is the class which provides features to handle the renaming which is applied to the features of the constraint type. It's current implementation is based on a hash table and therefore only one way is efficient. You can find out whether a specific feature is renamed by calling <e>is_feature_renamed. There's also a predefined feature
renamed
which takes an integer argument and returns another one. The integer returned is either
- unchanged, if the feature is not renamed
- some other positive integer if the feature is renamed under the renaming
- -1 if the feature was renamed into something else (therefore it is not accessible)
However, this is only relative to the renaming and is not in the context of a specific class. It means that if the feature f does not occur in the class you don't get an error (-1), as RENAMING_A
does not consult a context class for its operations.
CLASS_C
A major change here affects the feature constraint (i: INTEGER): TYPE_A
.
It is used to get the constraint of the formal at position i. A new precondition has been added which states that it is only ok to call that feature if the formal has only one constraint. This is also the reason why currently it is not allowed to apply a renaming to a single constraint.
For the multi constraint case the feature constraints (i: INTEGER): TYPE_SET_A
should be used instead. It returns a TYPE_SET_A instance which can possibly contain other formals.