Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision |
rfc:generics [2016/03/24 17:26] – Mispelt rfc orolyn | rfc:generics [2016/04/25 14:58] – note about generic constructors mindplay |
---|
| |
In the second example, the ''ValueType'' is incorrect, which results in a ''TypeError''. | In the second example, the ''ValueType'' is incorrect, which results in a ''TypeError''. |
| |
| === Nested Type Arguments === |
| |
| Generic classes may be instantiated and generic functions/methods may be called with nested type arguments. |
| |
| <code php> |
| class Container<ContentType> |
| { |
| private $content; |
| |
| public function getContent(): ContentType |
| { |
| return $this->content; |
| } |
| |
| public function setContent(ContentType $content): void |
| { |
| $this->content = $content; |
| } |
| } |
| |
| $container = new Container<Entry<int,string>>(); |
| |
| $container->setContent(new Entry<int,string>(1, 'test')); |
| var_dump($container->getContent() instanceof Entry<int,string>); // => (bool) true |
| |
| $container->setContent(new Entry<int,int>(1, 1)); // throws a TypeError |
| </code> |
| |
| In this example, the ''ContentType'' has retained the nested type arguments within ''Entry<KeyType, ValueType>''. The responsibility of type checking arguments to ''Entry'' still belong to the ''Entry'' class, yet the type hierarchy is maintained all the way up to the root definition ''Container<Entry<int,string>>''. |
| |
| In the second example, the ''ValueType'' is incorrect just as before, which again results in a ''TypeError''. |
| |
=== Upper Bounds === | === Upper Bounds === |
Any valid PHP type-hint may be used as an upper bound, including simple types like ''int'', ''float'', ''bool'', ''string'' and ''object''. (Omission of an upper bound effectively means ''mixed'' in general PHP terms, though we are not proposing the ability to explicitly type-hint as ''mixed'', which isn't supported by PHP.) | Any valid PHP type-hint may be used as an upper bound, including simple types like ''int'', ''float'', ''bool'', ''string'' and ''object''. (Omission of an upper bound effectively means ''mixed'' in general PHP terms, though we are not proposing the ability to explicitly type-hint as ''mixed'', which isn't supported by PHP.) |
| |
Note that the choice of the keyword ''is'' to indicate upper bounds is based on the rejection of perhaps more obvious alternatives - repurposing the ''extends'' or ''implements'' keywords would be misleading, since they would work precisely the same way; worse, permitting both keywords would render consumer code invalid if an upper bound type provided by a library is refactored between class and interface. Repurposing ''instanceof'' would also be misleading, since the upper bound is checking the type-hint, not an instance. | Note that the choice of the keyword ''is'' to indicate upper bounds is based on the rejection of perhaps more obvious alternatives - repurposing the ''extends'' or ''implements'' keywords would be misleading, since they would work precisely the same way; worse, permitting both keywords would render consumer code invalid if an upper bound type provided by a library is refactored between class and interface. Repurposing ''instanceof'' would also be misleading, since the upper bound is checking the type-hint, not an instance. Furthermore, we don't want this to collide with possible future mixed scalar types, such as ''number'' or ''scalar'', neither of which make sense in conjunction with either ''extends'' or ''implements''. (If a reserved ''is'' keyword is undesirable for other reasons, a simple '':'' is likely a better alternative than overloading the meaning of an existing keyword.) |
| |
== Bounds Checking == | == Bounds Checking == |
class Box<T> | class Box<T> |
{ | { |
use Box<T>; | use Container<T>; |
} | } |
| |
| |
The same applies when overriding constructors and static methods. | The same applies when overriding constructors and static methods. |
| |
| ==== Generic Constructors ==== |
| |
| Constructors may accept arbitrary type-arguments, just like any other method, e.g.: |
| |
| <code php> |
| class Hello<T1> |
| { |
| public function __construct<T1,T2>() |
| { |
| // ... |
| } |
| } |
| </code> |
| |
| In other words, the constructor may accept more type-arguments than those affecting the type. |
| |
==== Generic Closures ==== | ==== Generic Closures ==== |