xp-framework/rfc — Issue #193: Generics optimization
Author: thekid
Created: 2011-10-17 16:05:02+00:00
State: closed
Labels: framework, implemented

Scope of Change
====
Generics will be optimized.

Rationale
====
* Improve performance
* Enable reflection for generics
* Enable reflective creation of generics
* Support primitives a generic arguments

Functionality
====
Currently, generics are implemented as follows:

* A: A __generic instance member is required inside the declaration.
It will hold an array of the component types.
* B: The methods working with generics are required to take care of
the type checks.
* C: The create() core functionality takes care of instantiating the
generics, populating the __generic member with the given types'
names.

Example (abbreviated):

```php
__generic[0]) { // B
throw new IllegalArgumentException('...');
}
// ...
}
}

$v= create('new Vector()'); // C
?>
```

This has the following downsides:
* The declaration is quite verbose and introduces a bunch of boilerplate
code for the manual component type verification.
* At runtime, two generics, e.g. a vector of strings and one integers,
are "instanceof"-compatible
* There is no way to type-hint a generic, verifying a vector's component
type is string would mean manually accessing its __generic member.

Plan
----
A generic instance should be created at runtime named with unique name
created of the base and component types. A class has two names, one that
is reported by `XPClass::getName()` (F) and one used literally (L):

```php
()');

// Creates a class named:
// F: "util.collections.HashTable`2[lang.types.String,lang.Generic]"
// L: "HashTable··String¸Generic"
$ht= create('new HashTable()');

// Creates a class named:
// F: "util.collections.Stack`1[string]"
// L: "Stack··þstring"
$st= create('new Stack()');
?>
```

The same generation process happens for all generic interfaces these
classes implement and the generic base classes they extend.

The middle dot (·, Alt-Gr + "." in Cygwin) is used in the XP Framework
for generated classes and in fully qualified names (see xp-framework/rfc #37). The
cedil sign (¸, Alt-Gr + "´" in Cygwin) is used to separate the components.

Declaration
----
To declare a generic class using the XP framework, we will resort to
annotations:

```php
'K, V')))]
class HashTable extends Object implements Map {

#[@generic(params= 'K, V')]
public function put($key, $value) { ... }

#[@generic(params= 'K')]
public function get($key) { ... }

#[@generic(return= 'V[]')]
public function values() { ... }

public function toString() { ... }
}
?>
```

In XP language, this needn't be done as it syntactically supports generics:

```php
implements Map {

public void put(K $key, V $value) { ... }

public V get(K $key) { ... }

public V[] values() { ... }

public string toString() { ... }
}
?>
```

Instantiation
----
To instantiate generics, the `create()` core functionality needs
to be used. The inner workings are as follows:

1) Parse string specifying type into class and parameters
2) Compose unique name
3) If this class exists, instantiate and return
4) For all interfaces, perform generation
5) Generate class extending lang.Object
6) For all methods generate delegation
7) Instantiate and return

What we will end up with is the following:

```php
delegate= new HashTable();
}

public function put(String $key, Object $value) {
$this->delegate->put($key, $value);
}

// ...
}
?>
```

Reflection
----
Whether a type is a generic instance should be determinable at runtime:

```php
lang.XPClass
// ]
$class= create('new Vector()')->getClass();
if ($class->isGeneric()) {
Console::writeLine('Arguments: ', $class->genericArguments());
}
?>
```

Reflection on generic definitions should also be possible:

```php
"T"
// ]
$class= XPClass::forName('util.collections.Vector');
if ($class->isGenericDefinition()) {
Console::writeLine('Components: ', $class->genericComponents());
}
?>
```

Also, reflective creation of generic types should be possible:

```php
newGenericType(array(XPClass::forName('lang.types.String')));

// ...and then use newInstance() methods
$vector= $generic->newInstance();
?>
```

Discovering the definition type:

```php

$class= create('new Vector()')->getClass();
if ($class->isGeneric()) {
Console::writeLine('Definition: ', $class->genericDefinition());
}
?>
```

Type restrictions
----
The generic types can now be used in parameter type hints, although
somewhat ugly:

```php

```

Security considerations
====
n/a

Speed impact
====
Faster.

Dependencies
====
xp-framework/rfc #197

Related documents
====
* http://www.artima.com/intv/generics2.html - Generics in C#, Java, and C++
* xp-framework/rfc #106 - original generics RFC
* http://xp-framework.net/rfc/contrib/rfc0193.diff - Implementing patch
(applies in xp5_8 branch only)