Generics

One of the issue of .NET is the lack of generics support. Our first implementation of generics was based on generics as they were implemented in version 4.2 and prior of the ISE Eiffel compiler. Now, we need to find a way to represent the generic information for a given class. When this is done we can implement generic conformance.

Keeping type information

To keep the type information, we need to add a new attribute to every Eiffel objects. This attribute can be null in which case it is not a generic type, or not null in which case it is either a TUPLE or a generic class. The type of this attribute is an EIFFEL_DERIVATION.

We create a new type called EIFFEL_DERIVATION in which there is:

To create an instance of EIFFEL_DERIVATION, we need to know more about CLASS_TYPE. Here is the hierarchy:

class
	TYPE>
feature
	class_name: SYSTEM_STRING
	type_name: SYSTEM_STRING
			-- Corresponding to `generator' and `generating_type' in
			-- class ANY.
end

class
	CLASS_TYPE
inherit
	TYPE
feature
	type: RUNTIME_TYPE_HANDLER
			-- .NET Run-time type information.
end

class
	GENERIC_TYPE
inherit
	CLASS_TYPE
feature
	type_array: NATIVE_ARRAY [TYPE]
			-- Information about generic parameters of current generic type.
			-- Count of array is `nb_generics'.

	nb_generics: INTEGER
			-- Number of generic parameters in Current.

end

The CLASS_TYPE stores the run-time information about current Eiffel type with no generic parameters information. A GENERIC_TYPE stores the information about a generic type as seen during compilation. When an object of a certain type is instantiated we will evaluate the GENERIC_TYPE object in the context of the creation.

class
	FORMAL_TYPE
inherit
	TYPE
feature
	position: INTEGER
			-- Generic parameter position.
end

class
	ANCHORED_TYPE
inherit
	TYPE
end

FORMAL_TYPE and ANCHORED_TYPE are just place holder to tell the run-time how to compute certain type.

Generating the type information

The best way to describe it is to do a small example. In our case, we will try to create a LINKED_LIST [HASH_TABLE [INTEGER, STRING]]. In order to create this type, we are going to create an instance of TYPE that fully describes this type.

example:
LINKED_LIST [HASH_TABLE [INTEGER, STRING]] corresponds to the LINKED_LIST_ANY type definition in .NET. Since it is generic we are going to create an instance of GENERIC_TYPE with the following content:

type = create {CLASS_TYPE}.make (runtime_type_handle ("LINKED_LIST_ANY"))
nb_generics = 1
type_array = [a GENERIC_TYPE instance of HASH_TABLE [INTEGER, STRING] described below]

Here is the second GENERIC_TYPE instance for HASH_TABLE:

type = create {CLASS_TYPE}.make (runtime_type_handle ("HASH_TABLE_INTEGER_ANY"))
nb_generics = 2
type_array = [create {BASIC_TYPE}.make (runtime_type_handle ("Int32")),
                create {CLASS_TYPE}.make (runtime_type_handle  ("STRING"))]

This approach of representing types is directly taken from our representation in the C code generation, however much simplified thanks to the use of classes. Given this array, we are going to compute an associated EIFFEL_DERIVATION object that we will store after having created the a new instance of the class LINKED_LIST [HASH_TABLE [INTEGER, STRING]].

In this particular case, the EIFFEL_DERIVATION instance should have a content very similar to the one described above for just describing the type as there is no unknown part in the GENERIC_TYPE object. In case GENERIC_TYPE contains a formal generic parameter, then the formal generic parameter will need to be evaluated before the creation of the new object and after its evaluation the EIFFEL_DERIVATION object is created with the correct content.

Special case of SPECIAL/.NET arrays

On of the trickiest thing is to have generic information on the .NET array types, since they are generic containers and therefore we cannot add some extra information since their layout is controlled by the .NET runtime. So we will introduce a type SPECIAL_XX where XX is one of the possible generic derivation:

This type will contain the reference to the current .NET array and the reference to its EIFFEL_DERIVATION counterpart. So everywhere we have a SPECIAL type we will generate the SPECIAL_XX type instead. The performance lost is only in memory size.

Generic conformance

[Not completed yet]
Given all the above information, plus some more information about inheritance tree, we will be able to compute the conformance between two eiffel types.