[RFC:generics]

php.internals

Rasmus Schultz

10 years ago
Hello internals, I'd like to introduce an RFC proposing the addition of generic types and functions: https://wiki.php.net/rfc/generics Ben Scholzen started this RFC as a quick draft with a few code samples in August last year, and I have since then worked with Dominic and Ben towards a more complete, detailed RFC. There are a few holes still, which is why it hasn't moved from Draft to Under Discussion yet, but we feel that it's complete enough that we can start a discussion about this feature and try to iron out the remaining details. The RFC was previously "unofficially" announced on reddit - this thread generated some good questions and may answer some of the most immediate questions: https://www.reddit.com/r/PHP/comments/3zx8qs/php_rfcgenerics_update_03_please_comment/ One of the most common criticisms we've heard, is that the syntax would be hard to implement, a few have said "impossible" - but we feel that, if generics are introduced, it's important that the syntax and features be as familiar as possible to developers who are experienced with other mainstream web industry languages, such as C# and Java. To that end, Dominic Grostate has worked through most of the tokenizer/parser issues - save for one very exotic edge case, his fork demonstrates that the proposed syntax can be parsed: https://github.com/orolyn/php-src/commits/generics Note that this fork is by no means an implementation of generics - it is proof of concept as far as being able to parse the syntax. We're hoping to find someone, with more experience working on the php codebase, who is willing to collaborate on further implementation - and we do also have a partial test-suite, defining the big picture expectations for most of the proposed language features: https://github.com/orolyn/php-src/tree/generics-tests/Zend/tests/generics We look forward to your comments, questions and (I'm sure) criticisms of this proposal! Thank You, Regards, Rasmus Schultz

Josh Di Fabio

10 years ago
On Mon, Apr 18, 2016 at 6:20 AM, Rasmus Schultz <rasmus@mindplay.dk> wrote:
> Hello internals, > > I'd like to introduce an RFC proposing the addition of generic types > and functions: > > https://wiki.php.net/rfc/generics > > Ben Scholzen started this RFC as a quick draft with a few code samples > in August last year, and I have since then worked with Dominic and > Ben towards a more complete, detailed RFC. > > There are a few holes still, which is why it hasn't moved from Draft > to Under Discussion yet, but we feel that it's complete enough that > we can start a discussion about this feature and try to iron out > the remaining details. > > The RFC was previously "unofficially" announced on reddit - this > thread generated some good questions and may answer some of the > most immediate questions: > > https://www.reddit.com/r/PHP/comments/3zx8qs/php_rfcgenerics_update_03_please_comment/ > > One of the most common criticisms we've heard, is that the syntax > would be hard to implement, a few have said "impossible" - but we feel > that, if generics are introduced, it's important that the syntax and > features be as familiar as possible to developers who are experienced > with other mainstream web industry languages, such as C# and Java. > > To that end, Dominic Grostate has worked through most of the tokenizer/parser > issues - save for one very exotic edge case, his fork demonstrates that the > proposed syntax can be parsed: > > https://github.com/orolyn/php-src/commits/generics > > Note that this fork is by no means an implementation of generics - it is proof > of concept as far as being able to parse the syntax. > > We're hoping to find someone, with more experience working on the php codebase, > who is willing to collaborate on further implementation - and we do also have > a partial test-suite, defining the big picture expectations for most of the > proposed language features: > > https://github.com/orolyn/php-src/tree/generics-tests/Zend/tests/generics > > We look forward to your comments, questions and (I'm sure) criticisms of > this proposal! > > Thank You, > > Regards, > Rasmus Schultz > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php >
Nice work. I think you there's a typo in one of your examples: write(new Entry<int, int>(1, 2)); // throws a TypeError Presumably this should be <int, string> or something similar?

Josh Di Fabio

10 years ago
On Mon, Apr 18, 2016 at 10:47 AM, Josh Di Fabio <joshdifabio@gmail.com> wrote:
> On Mon, Apr 18, 2016 at 6:20 AM, Rasmus Schultz <rasmus@mindplay.dk> wrote: >> Hello internals, >> >> I'd like to introduce an RFC proposing the addition of generic types >> and functions: >> >> https://wiki.php.net/rfc/generics >> >> Ben Scholzen started this RFC as a quick draft with a few code samples >> in August last year, and I have since then worked with Dominic and >> Ben towards a more complete, detailed RFC. >> >> There are a few holes still, which is why it hasn't moved from Draft >> to Under Discussion yet, but we feel that it's complete enough that >> we can start a discussion about this feature and try to iron out >> the remaining details. >> >> The RFC was previously "unofficially" announced on reddit - this >> thread generated some good questions and may answer some of the >> most immediate questions: >> >> https://www.reddit.com/r/PHP/comments/3zx8qs/php_rfcgenerics_update_03_please_comment/ >> >> One of the most common criticisms we've heard, is that the syntax >> would be hard to implement, a few have said "impossible" - but we feel >> that, if generics are introduced, it's important that the syntax and >> features be as familiar as possible to developers who are experienced >> with other mainstream web industry languages, such as C# and Java. >> >> To that end, Dominic Grostate has worked through most of the tokenizer/parser >> issues - save for one very exotic edge case, his fork demonstrates that the >> proposed syntax can be parsed: >> >> https://github.com/orolyn/php-src/commits/generics >> >> Note that this fork is by no means an implementation of generics - it is proof >> of concept as far as being able to parse the syntax. >> >> We're hoping to find someone, with more experience working on the php codebase, >> who is willing to collaborate on further implementation - and we do also have >> a partial test-suite, defining the big picture expectations for most of the >> proposed language features: >> >> https://github.com/orolyn/php-src/tree/generics-tests/Zend/tests/generics >> >> We look forward to your comments, questions and (I'm sure) criticisms of >> this proposal! >> >> Thank You, >> >> Regards, >> Rasmus Schultz >> >> -- >> PHP Internals - PHP Runtime Development Mailing List >> To unsubscribe, visit: http://www.php.net/unsub.php >> > > Nice work. > > I think you there's a typo in one of your examples: > > write(new Entry<int, int>(1, 2)); // throws a TypeError > > Presumably this should be <int, string> or something similar?
Ignore me, I didn't read the example properly.

Dominic Grostate

10 years ago
We would really like some feedback on this. We know it is a massive feature, but we have put in quite a lot of research in both the language implications and implementation challenges. Please ask any questions you have. Thanks. On 18 Apr 2016 11:24 a.m., "Josh Di Fabio" <joshdifabio@gmail.com> wrote:

Mathieu Rochette

10 years ago
On 04/19/2016 06:28 PM, Dominic Grostate wrote:
> We would really like some feedback on this. We know it is a massive > feature, but we have put in quite a lot of research in both the language > implications and implementation challenges. Please ask any questions you > have.
thank you all for your work on this. That's a very interesting feature ! I guess it is possible but I have not seen it explicitly, can I do this: class StringKeyEntry<T> extends Entry<string,T> {} In "Traits" there is mistake; class Box<T> { use Box<T>; } should be class Box<T> { use Container<T>; } about the upper bounds, have you consider another way of describing the constraints, eg: class Box<T> where T is Boxable { // ... } this would allow multiple constraints, eg: class Collection<T> where T is Traversable, T is Countable { // ... } and, maybe, union type class Collection<T> where T is one of (\first\lib\Collection, \seconf\lib\Arrayable) { // ... } can generic types be nested ? eg: class Stuff<A, B is Something<A, string>> { // ... } considering the related enhancements, I guess this rfc is already big and both are useful enough to be proposed on their own. regards,
> > Thanks. > On 18 Apr 2016 11:24 a.m., "Josh Di Fabio" <joshdifabio@gmail.com> wrote: > >> On Mon, Apr 18, 2016 at 10:47 AM, Josh Di Fabio <joshdifabio@gmail.com> >> wrote: >>> On Mon, Apr 18, 2016 at 6:20 AM, Rasmus Schultz <rasmus@mindplay.dk> >> wrote: >>>> Hello internals, >>>> >>>> I'd like to introduce an RFC proposing the addition of generic types >>>> and functions: >>>> >>>> https://wiki.php.net/rfc/generics >>>> >>>> Ben Scholzen started this RFC as a quick draft with a few code samples >>>> in August last year, and I have since then worked with Dominic and >>>> Ben towards a more complete, detailed RFC. >>>> >>>> There are a few holes still, which is why it hasn't moved from Draft >>>> to Under Discussion yet, but we feel that it's complete enough that >>>> we can start a discussion about this feature and try to iron out >>>> the remaining details. >>>> >>>> The RFC was previously "unofficially" announced on reddit - this >>>> thread generated some good questions and may answer some of the >>>> most immediate questions: >>>> >>>> >> https://www.reddit.com/r/PHP/comments/3zx8qs/php_rfcgenerics_update_03_please_comment/ >>>> One of the most common criticisms we've heard, is that the syntax >>>> would be hard to implement, a few have said "impossible" - but we feel >>>> that, if generics are introduced, it's important that the syntax and >>>> features be as familiar as possible to developers who are experienced >>>> with other mainstream web industry languages, such as C# and Java. >>>> >>>> To that end, Dominic Grostate has worked through most of the >> tokenizer/parser >>>> issues - save for one very exotic edge case, his fork demonstrates that >> the >>>> proposed syntax can be parsed: >>>> >>>> https://github.com/orolyn/php-src/commits/generics >>>> >>>> Note that this fork is by no means an implementation of generics - it >> is proof >>>> of concept as far as being able to parse the syntax. >>>> >>>> We're hoping to find someone, with more experience working on the php >> codebase, >>>> who is willing to collaborate on further implementation - and we do >> also have >>>> a partial test-suite, defining the big picture expectations for most of >> the >>>> proposed language features: >>>> >>>> >> https://github.com/orolyn/php-src/tree/generics-tests/Zend/tests/generics >>>> We look forward to your comments, questions and (I'm sure) criticisms of >>>> this proposal! >>>> >>>> Thank You, >>>> >>>> Regards, >>>> Rasmus Schultz >>>> >>>> -- >>>> PHP Internals - PHP Runtime Development Mailing List >>>> To unsubscribe, visit: http://www.php.net/unsub.php >>>> >>> Nice work. >>> >>> I think you there's a typo in one of your examples: >>> >>> write(new Entry<int, int>(1, 2)); // throws a TypeError >>> >>> Presumably this should be <int, string> or something similar? >> Ignore me, I didn't read the example properly. >>
-- Mathieu Rochette

Sara Golemon

10 years ago
On Tue, Apr 19, 2016 at 1:16 PM, Mathieu Rochette <mathieu@texthtml.net> wrote:
> about the upper bounds, have you consider another way of describing the > constraints, eg: > > class Box<T> where T is Boxable > > this would allow multiple constraints, eg: > > class Collection<T> where T is Traversable, T is Countable >
IMO, this sort of problem should be solved by combining this feature with union types, so you could have something like: class Collection<T as (Traversable | Countable)> {... And merely inherit the logic rules from that feature rather than inventing yet another one.
> can generic types be nested ? > > class Stuff<A, B is Something<A, string>> >
I can't imagine why not... For my part, I love the concept overall. Generics are an important part of moving PHP towards comprehensive type-safety. But then, you know how I feel about Hack. :) -Sara

Stas Malyshev

10 years ago
Hi!
> class Collection<T as (Traversable | Countable)> {...
I am sorry if this sounds harsh, but I really hope we won't have something like this in PHP. Java templates are complex and weird enough, adding another layer on top of that to allow type expressions IMHO is really taking it too far.
-- Stas Malyshev smalyshev@gmail.com

Sara Golemon

10 years ago
On Tue, Apr 19, 2016 at 4:13 PM, Stanislav Malyshev <smalyshev@gmail.com> wrote:
>> class Collection<T as (Traversable | Countable)> {... > > I am sorry if this sounds harsh, but I really hope we won't have > something like this in PHP. Java templates are complex and weird enough, > adding another layer on top of that to allow type expressions IMHO is > really taking it too far. >
Nah, I've yet to actually have use for anything so specific yet either, but in the context of Mathieu was asking for, it seemed like a good moment to direct the concept back to something more consistent, at least. -Sara

Guilherme Blanco

10 years ago
Hi, Here are a couple of comments towards Generics support to PHP. 1- Even though mentioned, I'd still use "extends" or "implements" instead of "is" (which would be a new pseudo-reserved keyword) to enforce data type consistency and prevent developers to potentially referring to one thing while consider another. 2- I'd avoid blindly inferring generic type using constructor without notifying the user about this being a generic class. I'd still prefer a diamond operator <> to be used. This would be specially valid if we ever decide to merge typed properties too. Example: class Foo { private Bar<string> bar; public function __construct() { $this->bar = new Bar<>("Hello World"); // Can be omitted because of typed properties already defined it } } 3- I didn't see any description related to nested generic type definition. I hope it is supported. Example: $pair = new Tuple<string, Map<string, Foo>>(); 4- Another thing not mentioned in the RFC is if constructor also support generic typing, like this: class Foo<A> { public function __construct<B>(B $b) {} } $foo = new Foo<string>(1); 5- Java provides an enforcement that you can specify multiple bounds. Imagine a class that contains a generic that that must extend class A, but also implement interfaces B and C. We'd enter in a language recognition problem if we take the same approach as class declaration as definition, such as: class Foo<T extends A implements B, C> In order to properly solve this, Java takes the approach of &, and require the class to be first and interfaces later, like this: class Foo<T extends A & B & C>. As I already mentioned in comment #1, we should stick to extends and implements, but adopt & as multiple interface implementation, like this: class Foo<T extends A implements B & C> {} 6- This could be an independent RFC, but ideally we should support generic typed arrays using the [] syntax, like this: function sortElements<E extends Element>(E[] $elements) : E[]; 7- Typed returns are also not mentioned in RFC: function newEntity<E implements Entity>($id) : E; $user = newEntity<User>(UUID::v4()); 8- RFC only handles upper bound generic types, but no support is mentioned about lower bound generic types. An upper bound generic type is when it restricts the unknown type to that type or one of its inherited types. In RFC this is specified by the "is" keyword and I suggested to still segregate it to "extends" as highlighted in comment #1. A lower bound generic type is when it restrict the unknown type to that type or any of the is parent types. I'd suggest to use "parent", "parents", "parentof" or "super". Example: class A {} class B extends A {} class C extends A {} class D extends B {} class Foo<T parent B> {} // T can be an instance of A or B but never C or D. 9- Although not clearly clarified in RFC, I saw some inference over unbounded wildcard types. However, nothing is mentioned about wildcard upper bound and wildcard lower bounds. A few examples: // Unbounded wildcard type function sort(List $list) : void; // ... how Java (here, PHPized) does it: function sort(List<?> list) : void; // Wildcard upper bound in Java (PHPized) function sortElements(List<? extends Element> $list) : void; // Wildcard lower bound in Java (PHPized) function addAll(List<? super Integer> $list) : void; There're problems of using the unbounded wildcard generic type, but I think you may have to dig through Java language specification to better understand what I'm saying. You can poke me privately and I can point out documentation that exposes its limitations/constraints. 10- Reflection plays a very important piece in this support and IMHO it must be documented with proposed API for verification. A link to a gist is not enough to fully understand what is proposed, so I'm abstaining from reviewing it until it gets properly mapped out in RFC. I hope I gave enough insight of what I consider that needs to be expanded in RFC, expanded in the proposal, highlighted better, etc. Still, this RFC is the best attempt I've seen towards improving the reusability of data structures in PHP. Nice work! =) Regards, On Tue, Apr 19, 2016 at 9:17 PM, Sara Golemon <pollita@php.net> wrote:
> On Tue, Apr 19, 2016 at 4:13 PM, Stanislav Malyshev <smalyshev@gmail.com> > wrote: > >> class Collection<T as (Traversable | Countable)> {... > > > > I am sorry if this sounds harsh, but I really hope we won't have > > something like this in PHP. Java templates are complex and weird enough, > > adding another layer on top of that to allow type expressions IMHO is > > really taking it too far. > > > Nah, I've yet to actually have use for anything so specific yet > either, but in the context of Mathieu was asking for, it seemed like a > good moment to direct the concept back to something more consistent, > at least. > > -Sara > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
-- Guilherme Blanco Lead Architect at E-Block

Sara Golemon

10 years ago
On Tue, Apr 19, 2016 at 7:54 PM, guilhermeblanco@gmail.com <guilhermeblanco@gmail.com> wrote:
> 1- Even though mentioned, I'd still use "extends" or "implements" instead of > "is" (which would be a new pseudo-reserved keyword) to enforce data type > consistency and prevent developers to potentially referring to one thing > while consider another. >
FWIW, This is why Hack chose "as", which is already a special keyword and is much more concise than extends/implements. -Sara

Rowan Collins

10 years ago
guilhermeblanco@gmail.com wrote on 20/04/2016 03:54:
> 1- Even though mentioned, I'd still use "extends" or "implements" instead > of "is" (which would be a new pseudo-reserved keyword) to enforce data type > consistency and prevent developers to potentially referring to one thing > while consider another.
Perhaps "instanceof" would make more sense here? "class FileProcessor<T extends FileHandle>" seems to exclude instantiating FileProcessor<FileHandle>, because "FileHandle extends FileHandle" doesn't make any sense. You could read "class Box<T instanceof Boxable>" as an assertion that the class passes the constraint, as in "public function __construct(T $t) { assert($t instanceof Boxable); }" Regards,
-- Rowan Collins [IMSoP]

Jesse Schalken

10 years ago
On Wed, Apr 20, 2016 at 8:22 AM, Sara Golemon <pollita@php.net> wrote:
> On Tue, Apr 19, 2016 at 1:16 PM, Mathieu Rochette <mathieu@texthtml.net> > wrote: > > about the upper bounds, have you consider another way of describing the > > constraints, eg: > > > > class Box<T> where T is Boxable > > > > this would allow multiple constraints, eg: > > > > class Collection<T> where T is Traversable, T is Countable > > > IMO, this sort of problem should be solved by combining this feature > with union types, so you could have something like: > > class Collection<T as (Traversable | Countable)> {... > > And merely inherit the logic rules from that feature rather than > inventing yet another one. > >
I think the "where T is Traversable, T is Countable" syntax was intended to represent the intersection (i.e. a "Countable Traversable"), not the union. So you would need an intersection syntax class Collection<T as Traversable & Countable> {...

Sara Golemon

10 years ago
On Tue, Apr 19, 2016 at 7:56 PM, Jesse Schalken <me@jesseschalken.com> wrote:
>> class Collection<T as (Traversable | Countable)> {... > > I think the "where T is Traversable, T is Countable" syntax was intended to > represent the intersection (i.e. a "Countable Traversable"), not the union. > > So you would need an intersection syntax > > class Collection<T as Traversable & Countable> {... >
And that's precisely my point for why reusing the suggested syntax for union types makes sense. You can to specify either intersection or union (or potentially a complex combination of the two (A | (B & C))), rather than being limited to intersections only. -Sara

Jesse Schalken

10 years ago
I agree. On Wed, Apr 20, 2016 at 2:01 PM, Sara Golemon <pollita@php.net> wrote:

Mathieu Rochette

10 years ago
On 20/04/2016 00:22, Sara Golemon wrote:
> On Tue, Apr 19, 2016 at 1:16 PM, Mathieu Rochette <mathieu@texthtml.net> wrote: >> about the upper bounds, have you consider another way of describing the >> constraints, eg: >> >> class Box<T> where T is Boxable >> >> this would allow multiple constraints, eg: >> >> class Collection<T> where T is Traversable, T is Countable >> > IMO, this sort of problem should be solved by combining this feature > with union types, so you could have something like: > > class Collection<T as (Traversable | Countable)> {... > > And merely inherit the logic rules from that feature rather than > inventing yet another one.
obviously if the union type rfc passes we don't need another way of expressing this. that was only in the case it does not, I think having a way to have at least types intersection is useful here (and I didn't event think about <T is A & B>)
> >> can generic types be nested ? >> >> class Stuff<A, B is Something<A, string>> >> > I can't imagine why not...
just to be clear, it's not just nested generic. the A type have to be same in both "subtypes"

Dominic Grostate

10 years ago
I've made an amendment to the RFC to clarify on the Nested Types, which is indeed supposed to be part of the feature. Rasmus may want to reword it if it isn't very clear. Regarding union and intersections for upper (and maybe lower) bounds. Would it be appropriate to exclude these from type parameters until their respective RFCs are approved? As including them in generics but not in standard type hints may create an inconsistency. In short, perhaps a generics implementation should incorporate unions (and any future type constraints) as existing features only. This would help RFC Generics to focus on: Type aliasing, Introspection and Reflection. On 20 Apr 2016 9:05 a.m., "Mathieu Rochette" <mathieu@rochette.cc> wrote:

Quim Calpe

10 years ago
On Wed, Apr 20, 2016 at 11:10 AM, Dominic Grostate < codekestrel@googlemail.com> wrote:
> I've made an amendment to the RFC to clarify on the Nested Types, which is > indeed supposed to be part of the feature. Rasmus may want to reword it if > it isn't very clear. > > Regarding union and intersections for upper (and maybe lower) bounds. > Would it be appropriate to exclude these from type parameters until their > respective RFCs are approved? As including them in generics but not in > standard type hints may create an inconsistency. > > In short, perhaps a generics implementation should incorporate unions (and > any future type constraints) as existing features only. This would help > RFC Generics to focus on: Type aliasing, Introspection and Reflection. >
That would be a wise move, there are currently some RFCs with similar areas of contention

Guilherme Blanco

10 years ago
I don't know if mid-thread answering may lead to top-posting, but if it does, I'm sorry... =\ Answer inline: On Wed, Apr 20, 2016 at 5:10 AM, Dominic Grostate < codekestrel@googlemail.com> wrote:
> I've made an amendment to the RFC to clarify on the Nested Types, which is > indeed supposed to be part of the feature. Rasmus may want to reword it if > it isn't very clear. > > Regarding union and intersections for upper (and maybe lower) bounds. > Would it be appropriate to exclude these from type parameters until their > respective RFCs are approved? As including them in generics but not in > standard type hints may create an inconsistency. > > In short, perhaps a generics implementation should incorporate unions (and > any future type constraints) as existing features only. This would help > RFC Generics to focus on: Type aliasing, Introspection and Reflection. >
Unions and Intersections are required anyway, and I don't see how you can implement generics without supporting them. Let's say I'm implementing a cache library that segregate the interface of BulkOperations from the basic operations named CacheDriver. In a given class, I might want to only accept CacheDrivers that also support BulkOperations. How would I achieve that? The same happens to upper bounds that someone asked for an example privately. If I want to hire/move a person to a department that is registered in the system, but is not a 3rd party company person, how would you achieve that considering the following class structure? class Person {} class Employee extends Person {} class AssociateEmployee extends Employee {} class Manager extends Employee {} Considering your function: function assignToDepartment<T>(T $person) : bool; Generic type "T" in the function prototype needs to accept Person (new hire), Employee and Manager (transfer), but not AssociateEmployee. Considering upper bounds support only, your best bet is "T extends Person", but that would accept AssociateEmployee to be provided, which contradicts the business rule. Accepting anything lower in the hierarchy prevents new hires. That's when lower bounds comes into play. If you define as "T super Manager", all Person, Employee and Manager gets accepted, but not the AssociatedEmployee, matching properly the business rule. Also, someone else asked about type inference over my comment #4 in this example: class Foo<A> { public function __construct<B>(B $b) {} } $foo = new Foo<string>(1); The question asked is if that "string" was an inference over A or B. The correct answer is A, because generic type B is inferred from the parameter (integer) provided. That is exactly why class generic type definition should never be inferred from the constructor arguments, because you make it impossible to support both constructor generic types AND class generic type definitions at the same time.
> On 20 Apr 2016 9:05 a.m., "Mathieu Rochette" <mathieu@rochette.cc> wrote: > > > > > > > On 20/04/2016 00:22, Sara Golemon wrote: > > > >> On Tue, Apr 19, 2016 at 1:16 PM, Mathieu Rochette <mathieu@texthtml.net > > > >> wrote: > >> > >>> about the upper bounds, have you consider another way of describing the > >>> constraints, eg: > >>> > >>> class Box<T> where T is Boxable > >>> > >>> this would allow multiple constraints, eg: > >>> > >>> class Collection<T> where T is Traversable, T is Countable > >>> > >>> IMO, this sort of problem should be solved by combining this feature > >> with union types, so you could have something like: > >> > >> class Collection<T as (Traversable | Countable)> {... > >> > >> And merely inherit the logic rules from that feature rather than > >> inventing yet another one. > >> > > obviously if the union type rfc passes we don't need another way of > > expressing this. > > that was only in the case it does not, I think having a way to have at > > least types intersection > > is useful here (and I didn't event think about <T is A & B>) > > > >> > >> can generic types be nested ? > >>> > >>> class Stuff<A, B is Something<A, string>> > >>> > >>> I can't imagine why not... > >> > > just to be clear, it's not just nested generic. the A type have to be > same > > in both "subtypes" > > > >> > >> For my part, I love the concept overall. Generics are an important > >> part of moving PHP towards comprehensive type-safety. But then, you > >> know how I feel about Hack. :) > >> > >> -Sara > >> > >> > > >
-- Guilherme Blanco Lead Architect at E-Block

Rowan Collins

10 years ago
guilhermeblanco@gmail.com wrote on 20/04/2016 15:44:
> In a given class, I might want to only accept CacheDrivers that also > support BulkOperations. How would I achieve that?
Apologies if this has been refuted elsewhere, but AFAIK you can implement any intersection constraint, albeit slightly more verbosely, by creating a new type: - You can create a new interface that expresses an intersection of two other interfaces: interface BulkOperationCacheDriver extends CacheDriver, BulkOperation {} - Similarly, the intersection of a class and an interface can be created as an abstract class: abstact class BulkRedisCacheDriver extends RedisCacheDriver implements BulkOperation {} Since you can create those without modifying the underlying classes, you could specify generic constraints for any given intersection. A union constraint ("it can be either this or this") cannot currently be implemented, but the use cases are somewhat more questionable anyway. Regards,
-- Rowan Collins [IMSoP]

Dominic Grostate

10 years ago
I agree on both points (technically). It would allow you to apply that restriction. I only advise against it to reduce the impact the initial implementation would have on the codebase, provided it is preferable to implement it in phases. As for inference. Rasmus and I have argued over that a fair bit, as I was in favour of using 'new Entry<>' or just 'new Entry' to be a parameterised type with no type constraints (any value). On 20 Apr 2016 3:44 p.m., "guilhermeblanco@gmail.com" < guilhermeblanco@gmail.com> wrote:

Dennis Birkholz

10 years ago
Hi all, Am 20.04.2016 um 16:44 schrieb guilhermeblanco@gmail.com:
> If I want to hire/move a person to a department that is registered in the > system, but is not a 3rd party company person, how would you achieve that > considering the following class structure? > > class Person {} > class Employee extends Person {} > class AssociateEmployee extends Employee {} > class Manager extends Employee {} > > Considering your function: > > function assignToDepartment<T>(T $person) : bool; > > Generic type "T" in the function prototype needs to accept Person (new > hire), Employee and Manager (transfer), but not AssociateEmployee. > Considering upper bounds support only, your best bet is "T extends Person", > but that would accept AssociateEmployee to be provided, which contradicts > the business rule. Accepting anything lower in the hierarchy prevents new > hires. > That's when lower bounds comes into play. If you define as "T super Manager", > all Person, Employee and Manager gets accepted, but not the > AssociatedEmployee, matching properly the business rule.
I have to strongly disagree with the last sentence here: "T super Manager" only fulfills your business rule by accident. If you add a "TeamLeader extends Employee" class, your complete example falls apart and shows that it is a very bad idea to introduce a "T super X" requirement. You really want "T implements Person except AssociateEmployee" so that you can use them like you would use bitmasks. I think that fundamentally contradicts how interfaces and inheritance work. The type in the generic should specify which contract (Base class/interface) you require at least inside the generic class/function. Everything else is really strange to me. What about interfaces? If Manager or Employee implement Serializable, will all other classes that implement Serializable also be allowed here? Please let's not implement "T super X" kind of generics for use cases that really need something different. Thanks, Dennis

Robert Stoll

10 years ago
Hi Rasmus
> Hello internals, > > I'd like to introduce an RFC proposing the addition of generic types and functions: > > https://wiki.php.net/rfc/generics > > Ben Scholzen started this RFC as a quick draft with a few code samples in August last year, and I have since then worked > with Dominic and Ben towards a more complete, detailed RFC. > > There are a few holes still, which is why it hasn't moved from Draft to Under Discussion yet, but we feel that it's complete > enough that we can start a discussion about this feature and try to iron out the remaining details. > > The RFC was previously "unofficially" announced on reddit - this thread generated some good questions and may answer > some of the most immediate questions: > > https://www.reddit.com/r/PHP/comments/3zx8qs/php_rfcgenerics_update_03_please_comment/ > > One of the most common criticisms we've heard, is that the syntax would be hard to implement, a few have said > "impossible" - but we feel that, if generics are introduced, it's important that the syntax and features be as familiar as > possible to developers who are experienced with other mainstream web industry languages, such as C# and Java. > > To that end, Dominic Grostate has worked through most of the tokenizer/parser issues - save for one very exotic edge > case, his fork demonstrates that the proposed syntax can be parsed: > > https://github.com/orolyn/php-src/commits/generics > > Note that this fork is by no means an implementation of generics - it is proof of concept as far as being able to parse the > syntax. > > We're hoping to find someone, with more experience working on the php codebase, who is willing to collaborate on > further implementation - and we do also have a partial test-suite, defining the big picture expectations for most of the > proposed language features: > > https://github.com/orolyn/php-src/tree/generics-tests/Zend/tests/generics > > We look forward to your comments, questions and (I'm sure) criticisms of this proposal! > > Thank You, > > Regards, > Rasmus Schultz > > -- > PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Some questions about bounds checking: - Example A: why don't you pass T (instead of Computer) to MachineBuilder? Just for the example or is it not possible with your approach? - What about lower bounds? In you examples about type checking you write:
> var_dump($hat_box instanceof Box); // => (bool) true
Will you support "raw types" similar as in Java, if so why? you wrote:
> TODO: decide whether or not bounded polymorphism should be supported.
I am a bit confused, isn't parametric polymorphism combined with upper bounds already bounded polymorphism?