# Generic classes and methods RFC

- Thread: https://externals.io/message/87960
- Original archive: https://news-web.php.net/php.internals/87960
- Started by Ben Scholzen 'DASPRiD' on 2015-08-31T20:31:38+00:00
- Messages: 25
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #87960 — Ben Scholzen 'DASPRiD' — 2015-08-31T20:31:38+00:00

URL: https://externals.io/message/87960#87960

Hello,

I've written up an RFC for supporting generic classes and methods in 
PHP, and I'd love to hear your thoughts about it.

https://wiki.php.net/rfc/generics

Cheers,
-- 
Ben Scholzen 'DASPRiD'
Community Review Team Member | mail@dasprids.de
Zend Framework               | http://www.dasprids.de

---

## #87983 — pajousek@gmail.com — 2015-09-01T08:54:54+00:00

URL: https://externals.io/message/87960#87983 · In reply to: #87960

On Mon, Aug 31, 2015 at 10:31 PM, Ben Scholzen 'DASPRiD'
<mail@dasprids.de> wrote:
> Hello,
>
> I've written up an RFC for supporting generic classes and methods in PHP,
> and I'd love to hear your thoughts about it.
>
> https://wiki.php.net/rfc/generics
>
> Cheers,
> --
> Ben Scholzen 'DASPRiD'
> Community Review Team Member | mail@dasprids.de
> Zend Framework               | http://www.dasprids.de
>
> --
> 
> 
>

Hello,

I would love to see generics in PHP, but I have a few questions for your RFC.

class Bazz<Foo : \Bar>

Why did you use this syntax for forcing extending/implementation? I
know this is the syntax C# uses, but it doesn't fit PHP. I think it
should be "extends" or "implements", because in PHP : has a different
meaning.

Also, how do you specify multiple constraints?

Do you have any idea how it would work internally and if there was
some performance hit while using generics, and if it would also slow
down existing apps that don't use generics?

I hope this RFC will have positive comments, and someone who is
capable of writing C will help you out with it so there's a patch for
people to review - because I'm not sure if this RFC can get anywhere
without a patch. :(

Regards
Pavel Kouril

---

## #88059 — John LeSueur — 2015-09-05T19:48:51+00:00

URL: https://externals.io/message/87960#88059 · In reply to: #87983

> On Mon, Aug 31, 2015 at 10:31 PM, Ben Scholzen 'DASPRiD'
> <mail@dasprids.de> wrote:
> > […]
>
> Hello,
>
> I would love to see generics in PHP, but I have a few questions for your
> RFC.
>
> class Bazz<Foo : \Bar>
>
> Why did you use this syntax for forcing extending/implementation? I
> know this is the syntax C# uses, but it doesn't fit PHP. I think it
> should be "extends" or "implements", because in PHP : has a different
> meaning.
>
> Also, how do you specify multiple constraints?
>
> Do you have any idea how it would work internally and if there was
> some performance hit while using generics, and if it would also slow
> down existing apps that don't use generics?
>
> I hope this RFC will have positive comments, and someone who is
> capable of writing C will help you out with it so there's a patch for
> people to review - because I'm not sure if this RFC can get anywhere
> without a patch. :(
>
> Regards
> Pavel Kouril
>
> --
> 
> 
>
>
Hi Ben,

Now that I have substantive questions, including the list :)

In the following:

class SomeList<Bar> {
    public static function fromArray<Baz>(array $a): SomeList<Baz> {
        $list = new SomeList<Baz>();
        $list2 = new SomeList<Bar>();
        return $list;
    }
}

$list = SomeList<int>::fromArray([1, 2]);

When fromArray() executes, what type is $list2? or is that an error? If
it's an error, what advantage is there to having distinct generic types on
the class vs. the method? How do I specify the two generic types I want to
use?

Another thing I'd like to make sure I understand, how does this interact
with strict types (and non-strict)?

new Entry<int, string>(1, 2);//I assume it should type-juggle

declare(strict_types = 1);
new Entry<int, string>(1, 2);//I assume it should throw error

I'm interested to see if PHP can get generics going. I hope hashing out
some more details might garner more interest.


Thanks,
John

---

## #88062 — Andrea Faulds — 2015-09-06T16:20:40+00:00

URL: https://externals.io/message/87960#88062 · In reply to: #87960

Hi Ben!

Ben Scholzen 'DASPRiD' wrote:
> Hello,
>
> I've written up an RFC for supporting generic classes and methods in
> PHP, and I'd love to hear your thoughts about it.
>
> https://wiki.php.net/rfc/generics
>
> Cheers,

Generics are a feature I'd love to see in PHP. I think this RFC could do 
with a little elaboration, though.

Something that's particularly important to me is if it be possible to 
have default values for type parameters? For example, could I make a 
class like this?

     <?php
     // note the =, a default value (like function parameters)
     class List<T=mixed>
     {
         private $array = [];

         // ...

         public function append(T $value) {
             $this->array[] = $value;
         }
     }

     $integerList = new List<int>; // only accepts integers
     $list = new List; // accepts any value

Here, 'mixed' means any type, like in the PHP manual or in Hack. We 
don't currently have a 'mixed' typehint since we don't need it (you can 
simply omit a typehint for a parameter or return type), but it would be 
useful here.

I'd like it if this was possible, because then you could make existing 
classes use generics without breaking compatibility. It's also more 
beginner-friendly: people who don't know about generics don't have to 
use them, if the class author has made this possible. This is in keeping 
with the "PHP way" where we don't require people to use type hints if 
they don't want them.

On a different note, I'm not sure I like the  `class Baz<Foo : \Bar>` 
syntax. For functions parameters, we put the type name before the 
variable name, e.g. `function foo(int $bar)`. So, could we do the same 
here, i.e. `class <\Bar Foo>`, for consistency?

Though that looks a little strange to me. It's two bare identifiers next 
to eachother (`\Bar Foo`), unlike function parameters where the second 
one has a dollar prefix (`\Bar $foo`). Perhaps type variables, like 
regular variables, should have some sort of sigil in PHP? This would 
make it more obvious that something is a type variable and not a class 
name. To take an example from your RFC, consider the following code snippet:

     class Entry<KeyType, ValueType>
     {
         // ...

         public function __construct(KeyType $key, ValueType $value)
         {
             // ...
         }

         // ...
     }

If we hadn't seen the class declaration at the top which makes `KeyType` 
and `ValueType` be type parameters, we might not realise they weren't 
ordinary classes or interfaces when we looked at `__construct`. The 
-Type suffix you've used helps a little, but that's a convention, and 
isn't guaranteed to be used. Also, in some existing projects, there 
might be classes with that suffix.

What if we use some sort of sigil here to make it clear? Say we used %:

class Entry<%KeyType, %ValueType>
{
     // ...

     public function __construct(%KeyType $key, %ValueType $value)
     {
         // ...
     }

     // ...
}

Now, without having to look at the class declaration, we can tell that 
`KeyType` isn't a class name, because it has % in front of it.

Anyway, all that being said: the big challenge with generics is really 
getting someone to do the nitty-gritty of implementing it. It's great 
that you've got an RFC written for this, but unless someone is willing 
to implement it, I fear it may go to waste. But you writing an RFC might 
inspire someone. There is hope!

Hope my thoughts are somewhat helpful.

--
Andrea Faulds
http://ajf.me/

---

## #88082 — Ben Scholzen — 2015-09-07T09:46:54+00:00

URL: https://externals.io/message/87960#88082 · In reply to: #87983

Hi,
> I would love to see generics in PHP, but I have a few questions for your RFC.
>
> class Bazz<Foo : \Bar>
>
> Why did you use this syntax for forcing extending/implementation? I
> know this is the syntax C# uses, but it doesn't fit PHP. I think it
> should be "extends" or "implements", because in PHP : has a different
> meaning.

I've used a different syntax before (namely "extends" and "implements"), 
but someone pointed out, that a keyword-less version would make more 
sense, so I updated it appropriately. If someone has a better 
suggestion, I'm happy to include it in the RFC.

> Also, how do you specify multiple constraints?

I didn't plan on covering multiple constraints here, as we don't handle 
them at all in PHP yet. Although I've read that someone wanted to have 
Union-types in PHP, which could be used here as well I suppose.

> Do you have any idea how it would work internally and if there was
> some performance hit while using generics, and if it would also slow
> down existing apps that don't use generics?

I don't have enough insights in the PHP guts to make a good suggestion 
about this, but I'd assume that it should not have a negative 
performance effect on code which doesn't use generics.

> I hope this RFC will have positive comments, and someone who is
> capable of writing C will help you out with it so there's a patch for
> people to review - because I'm not sure if this RFC can get anywhere
> without a patch. :(
>
> Regards
> Pavel Kouril
>


-- 
Ben Scholzen
http://www.dasprids.de

---

## #88083 — Ben Scholzen — 2015-09-07T09:52:56+00:00

URL: https://externals.io/message/87960#88083 · In reply to: #88059

Hi,


> Hi Ben,
>
> Now that I have substantive questions, including the list :)
>
> In the following:
>
> class SomeList<Bar> {
>      public static function fromArray<Baz>(array $a): SomeList<Baz> {
>          $list = new SomeList<Baz>();
>          $list2 = new SomeList<Bar>();
>          return $list;
>      }
> }
>
> $list = SomeList<int>::fromArray([1, 2]);
>
> When fromArray() executes, what type is $list2? or is that an error? If
> it's an error, what advantage is there to having distinct generic types
> on the class vs. the method? How do I specify the two generic types I
> want to use?

The $list2 line would definitely be an error, since the <Bar> hint is 
not known in the static context. The advantage is simply that you can 
pass a type through the a static method to create an object with a 
specific type for you.

> Another thing I'd like to make sure I understand, how does this interact
> with strict types (and non-strict)?
>
> new Entry<int, string>(1, 2);//I assume it should type-juggle
>
> declare(strict_types = 1);
> new Entry<int, string>(1, 2);//I assume it should throw error

I didn't think too much about this, but I guess you are right that for 
scalar types, the strict_type declaration should apply in the user context.

> I'm interested to see if PHP can get generics going. I hope hashing out
> some more details might garner more interest.
>
>
> Thanks,
> John


-- 
Ben Scholzen
http://www.dasprids.de

---

## #88086 — Ben Scholzen — 2015-09-07T10:37:06+00:00

URL: https://externals.io/message/87960#88086

Hello,

> Hi Ben!
>
> Generics are a feature I'd love to see in PHP. I think this RFC could do
> with a little elaboration, though.
>
> Something that's particularly important to me is if it be possible to
> have default values for type parameters? For example, could I make a
> class like this?
>
>      <?php
>      // note the =, a default value (like function parameters)
>      class List<T=mixed>
>      {
>          private $array = [];
>
>          // ...
>
>          public function append(T $value) {
>              $this->array[] = $value;
>          }
>      }
>
>      $integerList = new List<int>; // only accepts integers
>      $list = new List; // accepts any value
>
> Here, 'mixed' means any type, like in the PHP manual or in Hack. We
> don't currently have a 'mixed' typehint since we don't need it (you can
> simply omit a typehint for a parameter or return type), but it would be
> useful here.
>
> I'd like it if this was possible, because then you could make existing
> classes use generics without breaking compatibility. It's also more
> beginner-friendly: people who don't know about generics don't have to
> use them, if the class author has made this possible. This is in keeping
> with the "PHP way" where we don't require people to use type hints if
> they don't want them.

I'm not sure if we would need any other default than "mixed". Personally 
I think that you should be able to instantiate any generic class which 
does not enforce specific types on the hints without any types, which 
automatically turns it into a mixed-type generic. That should cover this 
use-case pretty easily.

> On a different note, I'm not sure I like the  `class Baz<Foo : \Bar>`
> syntax. For functions parameters, we put the type name before the
> variable name, e.g. `function foo(int $bar)`. So, could we do the same
> here, i.e. `class <\Bar Foo>`, for consistency?

As written in an earlier mail, the colon came up from another email, I'm 
happy to change it if there's a better suggestion.

> Though that looks a little strange to me. It's two bare identifiers next
> to eachother (`\Bar Foo`), unlike function parameters where the second
> one has a dollar prefix (`\Bar $foo`). Perhaps type variables, like
> regular variables, should have some sort of sigil in PHP? This would
> make it more obvious that something is a type variable and not a class
> name. To take an example from your RFC, consider the following code snippet:
>
>      class Entry<KeyType, ValueType>
>      {
>          // ...
>
>          public function __construct(KeyType $key, ValueType $value)
>          {
>              // ...
>          }
>
>          // ...
>      }
>
> If we hadn't seen the class declaration at the top which makes `KeyType`
> and `ValueType` be type parameters, we might not realise they weren't
> ordinary classes or interfaces when we looked at `__construct`. The
> -Type suffix you've used helps a little, but that's a convention, and
> isn't guaranteed to be used. Also, in some existing projects, there
> might be classes with that suffix.
>
> What if we use some sort of sigil here to make it clear? Say we used %:
>
> class Entry<%KeyType, %ValueType>
> {
>      // ...
>
>      public function __construct(%KeyType $key, %ValueType $value)
>      {
>          // ...
>      }
>
>      // ...
> }
>
> Now, without having to look at the class declaration, we can tell that
> `KeyType` isn't a class name, because it has % in front of it.

I like that idea, as it makes the code easier to understand. I'm 
wondering what other people's thoughts about that is.

> Anyway, all that being said: the big challenge with generics is really
> getting someone to do the nitty-gritty of implementing it. It's great
> that you've got an RFC written for this, but unless someone is willing
> to implement it, I fear it may go to waste. But you writing an RFC might
> inspire someone. There is hope!

I hope so as well!

> Hope my thoughts are somewhat helpful.
>
> --
> Andrea Faulds
> http://ajf.me/

-- 
Ben Scholzen
http://www.dasprids.de

---

## #88107 — George Bond — 2015-09-07T19:02:26+00:00

URL: https://externals.io/message/87960#88107 · In reply to: #88086

> Hello,
>
> Hi Ben!
> > […]
>
> I'm not sure if we would need any other default than "mixed". Personally I
> think that you should be able to instantiate any generic class which does
> not enforce specific types on the hints without any types, which
> automatically turns it into a mixed-type generic. That should cover this
> use-case pretty easily.
>
> On a different note, I'm not sure I like the  `class Baz<Foo : \Bar>`
> > […]
>
> As written in an earlier mail, the colon came up from another email, I'm
> happy to change it if there's a better suggestion.
>
>
> Though that looks a little strange to me. It's two bare identifiers next
> > […]
>
> I like that idea, as it makes the code easier to understand. I'm wondering
> what other people's thoughts about that is.
>
> Anyway, all that being said: the big challenge with generics is really
> > […]
>
> I hope so as well!
>
> Hope my thoughts are somewhat helpful.
> > […]
>
> --
> Ben Scholzen
> http://www.dasprids.de
>
>
I'm a fan of the C# syntax for generics ("where" keyword).  I think the
natural translation of that syntax to PHP would be:

class ListOfLoggers<T> extends Enumerable<T> implements ArrayAccess
    where T implements LoggerInterface
{
    ...
}

Ie you have "where <class>" and then a block in the same syntax as a normal
class extends/implements declaration.  The full structure would be:

class Foo<TFirst, TSecond> extends BaseClass<TFirst, AnotherClass>
implements IGenericInterface<TSecond>, IOtherInterface
    where TFirst extends OtherBaseClass implements IAnotherInterface
    where TSecond extends YetAnotherBaseClass implements
IYetAnotherInterface, IEvenMoreInterfaces
{
    ....
}

C# doesn't put a comma between where blocks, which usually catches me out.
It's open to bikeshedding whether it would be sensible to require one here
(after "implements IAnotherInterface"), and if so whether to allow a
trailing comma (after "IEvenMoreInterfaces").

Thoughts?

--G

---

## #88131 — Stephen Coakley — 2015-09-10T01:50:41+00:00

URL: https://externals.io/message/87960#88131 · In reply to: #88107

> 
>
> > […]

You could also just use the dollar sign for type variables. As in

     class Entry<$KeyType, $ValueType>
     {
         // ...
         public function __construct($KeyType $key, $ValueType $value)
         {
             // ...
         }
         // ...
     }

Not sure if that would be *more* confusing or *less* confusing. If there 
was such a thing as a "type" type, then, depending on how generics were 
implemented, the type variables could *literaly* be "type" variables. If 
that makes any sense at all.

You could also have the type variables resolve to type strings somehow. 
For example, the output of:

     class Box<$T>
     {
         public function __construct($T $value)
         {
             // ...
         }

         public function printType()
         {
             print "$T\n";
         }
     }

     $box = new Box<\My\Object>(new \My\Object());
     $box->printType();

would be "My\Object". Just another idea; one that feels very "PHP-like" 
to me anyway. Other opinions?

> > […]
> I'm a fan of the C# syntax for generics ("where" keyword).  I think the
> natural translation of that syntax to PHP would be:
>
> class ListOfLoggers<T> extends Enumerable<T> implements ArrayAccess
>      where T implements LoggerInterface
> {
>      ...
> }
>
> Ie you have "where <class>" and then a block in the same syntax as a normal
> class extends/implements declaration.  The full structure would be:
>
> class Foo<TFirst, TSecond> extends BaseClass<TFirst, AnotherClass>
> implements IGenericInterface<TSecond>, IOtherInterface
>      where TFirst extends OtherBaseClass implements IAnotherInterface
>      where TSecond extends YetAnotherBaseClass implements
> IYetAnotherInterface, IEvenMoreInterfaces
> {
>      ....
> }
>
> C# doesn't put a comma between where blocks, which usually catches me out.
> It's open to bikeshedding whether it would be sensible to require one here
> (after "implements IAnotherInterface"), and if so whether to allow a
> trailing comma (after "IEvenMoreInterfaces").
>
> Thoughts?
>
> --G
>

I like the "where" syntax as well. Most of PHP's "type operators" are 
words instead of glyphs, so it makes sense to keep the tradition for 
consistency. See the various syntaxes and keywords for using traits for 
comparison.

I think adding a comma between "where" expressions is a little 
redundant; I'd leave it out like in C#.

-- Stephen

---

## #88133 — Rowan Collins — 2015-09-10T12:18:08+00:00

URL: https://externals.io/message/87960#88133 · In reply to: #88062

Andrea Faulds wrote on 06/09/2015 17:20:
> If we hadn't seen the class declaration at the top which makes 
> `KeyType` and `ValueType` be type parameters, we might not realise 
> they weren't ordinary classes or interfaces when we looked at 
> `__construct`. The -Type suffix you've used helps a little, but that's 
> a convention, and isn't guaranteed to be used. Also, in some existing 
> projects, there might be classes with that suffix. 

As I understand it, the convention in a lot of languages is that type 
parameters are a single upper-case letter. I'm not sure if any enforce 
this restriction, though, and a sigil does seem more flexible and readable.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #88139 — Ben Scholzen — 2015-09-10T16:25:14+00:00

URL: https://externals.io/message/87960#88139 · In reply to: #88131

> I like the "where" syntax as well. Most of PHP's "type operators" are
> words instead of glyphs, so it makes sense to keep the tradition for
> consistency. See the various syntaxes and keywords for using traits for
> comparison.
>
> I think adding a comma between "where" expressions is a little
> redundant; I'd leave it out like in C#.
>
> -- Stephen
>

I like the "where" syntax as well, as it really fits into the PHP syntax 
way. I think I should update the RFC accordingly.
-- 
Ben Scholzen
http://www.dasprids.de

---

## #88151 — Dennis Birkholz — 2015-09-10T23:00:29+00:00

URL: https://externals.io/message/87960#88151 · In reply to: #87960

Hi Ben,

Am 31.08.2015 um 22:31 schrieb Ben Scholzen 'DASPRiD':
> I've written up an RFC for supporting generic classes and methods in
> PHP, and I'd love to hear your thoughts about it.
> 
> https://wiki.php.net/rfc/generics

I have some points where I think some clarification is required before
someone can start to implement it:

1. static methods:

class Foo<T> {
	public static function test() {
	}
}

how can I call the method:
a) Foo::test()
or
b) Foo<int>::test()

in case b), would the generic methods not be a duplication?

2. Generic methods

a) Can generic methods be inside classes that themselves are not generic?

class Foo<T1> {
	public static function test<T2>() {
		$a = new self<T1>();
	}
}

b) Is the generic parameter type of T1 set inside the static method or
only T2? And if T1 is available, why is T2 required? What is the
advantage of having T1 and T2?

3. Class names

a) Is it possible to have two classes with the same name (in the same
namespace) but one that requires type parameters and one that does not?

b) Is it possible to allow for a generic class to be constructed without
type parameters (e.g. with mixed as the default)?

4. Reflection

Can you get the type parameters used to construct an object at runtime? How?

5. Implementation

How do you propose to implement all this? In Java (at least in older
versions, may have changed), generics where a pure compile time
function. So the compiler checked that your code did not validate the
type but you could not access the type parameter information it at
runtime. That is not possible for PHP. So either we need classes that
can be parameterized inside the PHP core or we need "template" classes
that are compiled into concrete implementations using the type
parameters once they are used first. Have you thought about which
variant you prefer and why (or any other I did forget)? Is this even
possible without digging deep inside the language?

Thanks for your time.
Greets
Dennis

---

## #88150 — Ben Scholzen 'DASPRiD' — 2015-09-10T23:12:50+00:00

URL: https://externals.io/message/87960#88150 · In reply to: #88151

Hi Dennis,

thanks for your feedback, see my answers below:

> 1. static methods:
>
> class Foo<T> {
> 	public static function test() {
> 	}
> }
>
> how can I call the method:
> a) Foo::test()
> or
> b) Foo<int>::test()
>
> in case b), would the generic methods not be a duplication?

Case a) is correct here. A static method is not in the context of an 
instance, so it doesn't know about the class boxing by itself.

> 2. Generic methods
>
> a) Can generic methods be inside classes that themselves are not generic?

Sure, that's perfectly valid.

> class Foo<T1> {
> 	public static function test<T2>() {
> 		$a = new self<T1>();
> 	}
> }
>
> b) Is the generic parameter type of T1 set inside the static method or
> only T2? And if T1 is available, why is T2 required? What is the
> advantage of having T1 and T2?

T1 is not available in the static method, as said before, the static 
method is not part of an instance. Furthermore, line 3 should read like 
this:

$a = new self<T2>();

> 3. Class names
>
> a) Is it possible to have two classes with the same name (in the same
> namespace) but one that requires type parameters and one that does not?

That is in fact an implementation detail, but I'd tend to say no. That 
is similar to function overloading, which we don't have in PHP (sadly).

> b) Is it possible to allow for a generic class to be constructed without
> type parameters (e.g. with mixed as the default)?

As I wrote in an earlier email, that would totally possible. My idea 
there was, that, as long as the types don't have restrictions (to extend 
another class or implement an interface), it should be allowed to 
construct it without a type so that it accepts any parameters.

> 4. Reflection
>
> Can you get the type parameters used to construct an object at runtime? How?

That's in fact an implementation detail I can't say anything about, sorry.

> 5. Implementation
>
> How do you propose to implement all this? In Java (at least in older
> versions, may have changed), generics where a pure compile time
> function. So the compiler checked that your code did not validate the
> type but you could not access the type parameter information it at
> runtime. That is not possible for PHP. So either we need classes that
> can be parameterized inside the PHP core or we need "template" classes
> that are compiled into concrete implementations using the type
> parameters once they are used first. Have you thought about which
> variant you prefer and why (or any other I did forget)? Is this even
> possible without digging deep inside the language?

I haven't thought about a concrete implementation, simply because I'm 
not familiar enough with this part of the PHP core, and I'd leave it up 
to someone else to suggest the best way to implement it. But the idea of 
template classes sounds like a solution I'd probably chose if I didn't 
know better… which I don't :)

Again, thanks for your feedback!
-- 
Ben Scholzen 'DASPRiD'
Community Review Team Member | mail@dasprids.de
Zend Framework               | http://www.dasprids.de

---

## #88154 — Levi Morrison — 2015-09-11T15:27:51+00:00

URL: https://externals.io/message/87960#88154 · In reply to: #88150

On Thu, Sep 10, 2015 at 5:12 PM, Ben Scholzen 'DASPRiD'
<mail@dasprids.de> wrote:
> Hi Dennis,
>
> thanks for your feedback, see my answers below:
>
> > […]
>
>
> Case a) is correct here. A static method is not in the context of an
> instance, so it doesn't know about the class boxing by itself.

I think b would be correct. Can you explain this rationale a bit more?

---

## #88155 — Korvin Szanto — 2015-09-11T16:00:07+00:00

URL: https://externals.io/message/87960#88155 · In reply to: #88154

Levi,
It's my understanding that the "type variable" is a member of the instance
and not of the class. In at least java, generics are unavailable in static
context[1] though they can be specifically defined on the static method
itself[2].

[1]
http://stackoverflow.com/questions/936377/static-method-in-a-generic-class
[2] https://docs.oracle.com/javase/tutorial/extra/generics/methods.html



> On Thu, Sep 10, 2015 at 5:12 PM, Ben Scholzen 'DASPRiD'
> <mail@dasprids.de> wrote:
> > […]
>
> I think b would be correct. Can you explain this rationale a bit more?

---

## #88156 — Levi Morrison — 2015-09-11T16:08:21+00:00

URL: https://externals.io/message/87960#88156 · In reply to: #88155

> Levi,
> It's my understanding that the "type variable" is a member of the instance
> and not of the class. In at least java, generics are unavailable in static
> context[1] though they can be specifically defined on the static method
> itself[2].
>
> [1]
> http://stackoverflow.com/questions/936377/static-method-in-a-generic-class
> [2] https://docs.oracle.com/javase/tutorial/extra/generics/methods.html
>
> 
> > […]

This may be how it works in Java, but this is not Java. All behavior
must be outlined and justified, especially because not all languages
behave the same as Java with regards to generic-like behavior. Notably
C++ does not share this characteristic. If this generic ability is
confined only to classes/interfaces and only to instance methods that
is a large limitation. Even if that is what is decided there must be
rationale for choosing it to be that way.

---

## #88157 — Ben Scholzen — 2015-09-11T16:55:45+00:00

URL: https://externals.io/message/87960#88157 · In reply to: #88156

Well, with the example, there's a good reason to have them separated:

class Factory
{
   public static function createFoo<T extends \SomeClass>()
   {
     return new Foo<T>();
   }

   public static function createBar<T extends \SomeOtherClass>()
   {
     return new Bar<T>();
   }
}

class Foo<T extends \SomeClass> {}
class Bar<T extends \SomeOtherClass> {}

The factory instance does not know to need about <T>, this is purely a 
type for the method to be able to create another class, which requires 
that type. You couldn't put this definition on the Factory class.


> 
> > […]
>
> This may be how it works in Java, but this is not Java. All behavior
> must be outlined and justified, especially because not all languages
> behave the same as Java with regards to generic-like behavior. Notably
> C++ does not share this characteristic. If this generic ability is
> confined only to classes/interfaces and only to instance methods that
> is a large limitation. Even if that is what is decided there must be
> rationale for choosing it to be that way.
>


-- 
Ben Scholzen
http://www.dasprids.de

---

## #88159 — Levi Morrison — 2015-09-12T00:19:21+00:00

URL: https://externals.io/message/87960#88159 · In reply to: #88157

(Please stop top-posting!)


> Well, with the example, there's a good reason to have them separated:
>
> class Factory
> {
>   public static function createFoo<T extends \SomeClass>()
>   {
>     return new Foo<T>();
>   }
>
>   public static function createBar<T extends \SomeOtherClass>()
>   {
>     return new Bar<T>();
>   }
> }
>
> class Foo<T extends \SomeClass> {}
> class Bar<T extends \SomeOtherClass> {}
>
> The factory instance does not know to need about <T>, this is purely a type
> for the method to be able to create another class, which requires that type.
> You couldn't put this definition on the Factory class.

What would prohibit this?

    class Factory<T> {
        public static function makeFoo() {
           return new Foo<T>();
        }
    }

It's perhaps less generic than what you posted, but this demonstrates
that that a Factory *could* hold the definition on the class and not
the method.

To be honest, I don't know why you would bother doing this anyway. I
am a fan of realistic examples and Factories that make Foos of type T
is pretty unrealistic.

---

## #88160 — Ben Scholzen — 2015-09-12T05:55:22+00:00

URL: https://externals.io/message/87960#88160 · In reply to: #88159

> What would prohibit this?
>
>      class Factory<T> {
>          public static function makeFoo() {
>             return new Foo<T>();
>          }
>      }
>
> It's perhaps less generic than what you posted, but this demonstrates
> that that a Factory *could* hold the definition on the class and not
> the method.
>
> To be honest, I don't know why you would bother doing this anyway. I
> am a fan of realistic examples and Factories that make Foos of type T
> is pretty unrealistic.

Well, the counter-example would be that without generic methods, thus 
automatically applying the class instance types to static method, you 
would enforce that the user has to define them for static method calls 
which don't require a type at all (helper methods for instance).

-- 
Ben Scholzen
http://www.dasprids.de

---

## #88161 — Dennis Birkholz — 2015-09-12T10:03:12+00:00

URL: https://externals.io/message/87960#88161 · In reply to: #87960

Hi together,

1. If we require some keyword instead of the colon to limit which types
the type placeholders can have I would choose:
class Foo<T1 instanceof Bla, T2 instanceof Blubb> {}

The C#-like syntax "where T1 extends Bla implements Blubb" (proposed in
another thread) has two downsides:
a) It will not fit nicely with generic methods
b) "extends Bla" implies you can not use Bla itself but you actually
want a behavior that exactly matches "instanceof"

But I am not really happy with listing multiple classes/interfaces after
"instanceof" (the RFC does also not address this): separating it by
space seems odd, by comma will not work (you can not distinguish it from
type placeholders without an "instanceof" requirement) or you have to
use semicolon to separate the type placeholders and list multiple
"instanceof" requirements by comma.

2. I think mixing class and method generic specification together is
quite confusing:

class A {}
class B {}

class List<T : A> {
public static createFromElement<T : B>(T $element) {
return new OtherList<T>($element);
}
}

class OtherList<T extends B> { ... }

$list = List<A>::createFromElement(new A());

The example is not very meaningful but I think it sometimes may get very
hard to see why the static method does not accept an A if the class
does. If only non-generic classes could contain generic static methods
that would make it more obvious.

Maybe we should ignore generic methods for the moment and cleanly
specify how generic classes work, including the question if static
methods can be called with class::method() on generic classes and if the
type parameters can be used inside static methods if the call is
class<...>::method(). If someone is willing and able to implement this,
we will see whether generic methods are needed in real live at all.

Greets
Dennis

P.s.: sorry for top-replying again but my last thread got too specific
for this reply IMHO

---

## #88162 — Dennis Birkholz — 2015-09-12T10:24:46+00:00

URL: https://externals.io/message/87960#88162 · In reply to: #88161

Am 12.09.2015 um 12:03 schrieb Dennis Birkholz:
> Hi together,
> 
> 1. If we require some keyword instead of the colon to limit which types
> the type placeholders can have I would choose:
> class Foo<T1 instanceof Bla, T2 instanceof Blubb> {}

Just to save you some lookups in the Hack documentation:
1. Hack uses the "as" keyword:
class Foo<T1 as Bla> {}

2. It does not allow to require multiple types for T1:
"Currently, Hack only allows one constraint on a type or a method."

3. I found no example that Hack allows multiple type parameters like
class Foo<T1, T2> but also nothing that it is not possible

4. All type parameters must start with a capital T

5. Hack has generic methods

6. Hack has generic traits which we should also consider/specify how
they work exactly.

Greets
Dennis

---

## #88163 — Levi Morrison — 2015-09-12T13:51:53+00:00

URL: https://externals.io/message/87960#88163 · In reply to: #88162

> 4. All type parameters must start with a capital T

It's important to note that the HHVM runtime does not require this (or
at least it didn't when I last checked it out). It's only the Hack
type-checker that cares.

---

## #88164 — Andrea Faulds — 2015-09-12T14:57:44+00:00

URL: https://externals.io/message/87960#88164 · In reply to: #88154

Hey,

Levi Morrison wrote:
> On Thu, Sep 10, 2015 at 5:12 PM, Ben Scholzen 'DASPRiD'
> <mail@dasprids.de> wrote:
> > […]
>
> I think b would be correct. Can you explain this rationale a bit more?
>

I'm with Levi here, I think type parameters should matter for static 
methods. An example might be a list class:

     class List<T> {
         // ...
         public static function newFromConcat(List<T> $a, List<T> $b) {
             // creates a new list which is two lists concatenated
         }
         // ...
     }

In this context, the static method, which operates on instances of list, 
would benefit from type checking.

PHP's dynamic nature means that it wouldn't be the end of the world if 
static methods couldn't use the type parameter, though. You'd just lose 
proper type checking.

Thanks.

-- 
Andrea Faulds
http://ajf.me/

---

## #88165 — Andrea Faulds — 2015-09-12T15:00:18+00:00

URL: https://externals.io/message/87960#88165 · In reply to: #88162

Hi Dennis,

Dennis Birkholz wrote:
> Am 12.09.2015 um 12:03 schrieb Dennis Birkholz:
> > […]
>
> Just to save you some lookups in the Hack documentation:
> 1. Hack uses the "as" keyword:
> class Foo<T1 as Bla> {}

This seems like a poor syntax choice to me. Usually the word 'as' is 
used for aliases and such. If you hadn't told me its function here, I 
would probably have been very confused. 'T1' isn't an alias of Bla, 
right? It's some subclass.

Thanks.
-- 
Andrea Faulds
http://ajf.me/

---

## #88208 — Stig Bakken — 2015-09-15T09:30:48+00:00

URL: https://externals.io/message/87960#88208 · In reply to: #88164

>
>
> I'm with Levi here, I think type parameters should matter for static
methods. An example might be a list class:
>

Just because you want it, doesn't make it possible ;-)

The class type variables are specified when instantiating the class. Since
you don't do that for static methods, the runtime has no information about
which type was specified at the time the static method is called.

- Stig
