[generics] Feedback on optional type keyword experiment

580 views
Skip to first unread message

Carla Pfaff

unread,
Jul 25, 2020, 2:26:37 PM7/25/20
to golang-nuts
I just discovered the experiment to make the "type" keyword optional in certain cases on the dev.go2go branch. The commit message says:

---
    Experiment: Make "type" keyword optional in generic type declarations when
    it is clear that we can't have an array type declaration. This is the case
    when we have one the following:
    
    - more than one type parameter
    - a type parameter with a constraint
    - a trailing comma in the type parameter list
--

If the "type" keyword is not necessary if a constraint is present, then why not make a constraint mandatory and get rid of the "type" keyword in type parameter lists altogether?

Before:

    func Filter[type Elem](...)
    func Map[Elem1, Elem2](...)
    func Max[Elem constraints.Ordered](...)

After:

    func Filter[Elem interface{}](...)
    func Map[Elem1, Elem2 interface{}](...)
    func Max[Elem constraints.Ordered](...)

"interface{}" may be a little bulky, especially it since it is usually used for the simple cases. But if there was a short type alias for "interface{}" like "any" it can look good:

    type any = interface{}

    func Filter[Elem any](...)
    func Map[Elem1, Elem2 any](...)
    func Max[Elem constraints.Ordered](...)

Carla Pfaff

unread,
Jul 25, 2020, 2:47:20 PM7/25/20
to golang-nuts
To expand on my post:
It would be very consistent with the structure of regular parameter lists. Just like every parameter in a regular parameter list must have a type (with the exception of multiple consecutive parameters having the same type), every type parameter in a type parameter list must have a constraint. 

Ian Lance Taylor

unread,
Jul 25, 2020, 4:22:24 PM7/25/20
to Carla Pfaff, golang-nuts
On Sat, Jul 25, 2020 at 11:47 AM 'Carla Pfaff' via golang-nuts
<golan...@googlegroups.com> wrote:
>
> To expand on my post:
> It would be very consistent with the structure of regular parameter lists. Just like every parameter in a regular parameter list must have a type (with the exception of multiple consecutive parameters having the same type), every type parameter in a type parameter list must have a constraint.

That is certainly true.

But it is also true, based on experiments writing generic code, that
the majority of type parameters have no constraints. That is
particularly true for type parameters of generic types. So while it
would be possible to require people to always explicitly write a
constraint, it seems painful to force people to always write something
that is almost never needed.

Note that in this way constraints on type parameters are different
from types of regular parameters. It makes no sense to speak of a
regular parameter with no type. It's entirely reasonable, even
common, to speak of a type parameter with no constraint.

Ian


> On Saturday, 25 July 2020 at 20:26:37 UTC+2 Carla Pfaff wrote:
>>
>> I just discovered the experiment to make the "type" keyword optional in certain cases on the dev.go2go branch. The commit message says:
>>
>> ---
>> Experiment: Make "type" keyword optional in generic type declarations when
>> it is clear that we can't have an array type declaration. This is the case
>> when we have one the following:
>>
>> - more than one type parameter
>> - a type parameter with a constraint
>> - a trailing comma in the type parameter list
>> --
>>
>> If the "type" keyword is not necessary if a constraint is present, then why not make a constraint mandatory and get rid of the "type" keyword in type parameter lists altogether?
>>
>> Before:
>>
>> func Filter[type Elem](...)
>> func Map[Elem1, Elem2](...)
>> func Max[Elem constraints.Ordered](...)
>>
>> After:
>>
>> func Filter[Elem interface{}](...)
>> func Map[Elem1, Elem2 interface{}](...)
>> func Max[Elem constraints.Ordered](...)
>>
>> "interface{}" may be a little bulky, especially it since it is usually used for the simple cases. But if there was a short type alias for "interface{}" like "any" it can look good:
>>
>> type any = interface{}
>>
>> func Filter[Elem any](...)
>> func Map[Elem1, Elem2 any](...)
>> func Max[Elem constraints.Ordered](...)
>>
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/d7a9fe08-73bb-487b-ba2a-6766560f3b03n%40googlegroups.com.

Carla Pfaff

unread,
Jul 25, 2020, 4:37:39 PM7/25/20
to golang-nuts
I know it's common to have no constraints, but "[Elem any]" is even one character shorter than "[type Elem]". I rewrote the function signatures from slices.go2 in this way, and it doesn't feel painful. This already works on the go2go playground: https://go2goplay.golang.org/p/IQV5LTAIuDr

Carla Pfaff

unread,
Jul 25, 2020, 4:57:46 PM7/25/20
to golang-nuts
There's already a precedent of a builtin type alias in Go with "type rune = int32" https://golang.org/pkg/builtin/#rune and "any" would make many regular parameter lists shorter as well.

Bakul Shah

unread,
Jul 25, 2020, 5:07:07 PM7/25/20
to Carla Pfaff, golang-nuts
I like it!

BTW, I don't understand the meaning of this comment in the commit log:

>> Experiment: Make "type" keyword optional in generic type declarations when 
>> it is clear that we can't have an array type declaration.

It is talking about defining generic arrays, where one parameter may be the number of dimensions?
Probably not but IMHO such an exercise should be carried out before settling on a generic design.


Carla Pfaff

unread,
Jul 25, 2020, 5:12:38 PM7/25/20
to golang-nuts
On Saturday, 25 July 2020 at 22:22:24 UTC+2 Ian Lance Taylor wrote:
Note that in this way constraints on type parameters are different
from types of regular parameters. It makes no sense to speak of a
regular parameter with no type.

In regular parameter lists interface{} has this role, same as in type parameter lists, and we do not omit it. I know interface{} is technically a type, but "no constraint" is technically a constraint too.

Denis Cheremisov

unread,
Jul 25, 2020, 5:46:59 PM7/25/20
to golang-nuts
I look at what Carla did write and it feels ... good. I don't know, it may be not for everyone, but for me [T any] looks cleaner than [type T]. Probably I see `[` and understand this is generic params, then `T` and I immediately understand this is how the generic type denoted. A final touch, I would seriously consider this idea.

суббота, 25 июля 2020 г. в 23:22:24 UTC+3, Ian Lance Taylor:

Denis Cheremisov

unread,
Jul 25, 2020, 5:47:17 PM7/25/20
to golang-nuts
Great catch! I would say I really like it!

суббота, 25 июля 2020 г. в 23:37:39 UTC+3, Carla Pfaff:

Denis Cheremisov

unread,
Jul 25, 2020, 6:38:34 PM7/25/20
to golang-nuts
Btw, it `any` suffix can be a part of grammar, I mean something like

GenericParam = Lit [',' Lit]* 'any' | Lit [',' Lit]* Ident

where any can be replaced with an actual any if there's one in a scope.

воскресенье, 26 июля 2020 г. в 00:47:17 UTC+3, Denis Cheremisov:

DrGo

unread,
Jul 25, 2020, 6:43:26 PM7/25/20
to golang-nuts
I too think that T any is more readable than the overloaded type in type T especially if it means that I won’t have to remember when it’s Ok to drop type and when it’s not

Carla Pfaff

unread,
Jul 25, 2020, 7:11:18 PM7/25/20
to golang-nuts
I don't see why it should be in the grammar. Just a regular type alias for interface{} in the builtin scope, a regular predeclared identifier. It wouldn't break anyone's code. If someone already has an 'any' type or variable in their package their version shadows the builtin one, and they can still use interface{} as a generic type constraint. At least that's how it works with other builtin type aliases like 'rune': https://play.golang.org/p/KRX3fIBV9qW

Denis Cheremisov

unread,
Jul 25, 2020, 9:13:30 PM7/25/20
to golang-nuts
I actually mean something different. The bad with any in builtins is there will be questions "why you use interface{}" if there's builtin any?", etc. I mean these will be different AST nodes, there will be

type GenericAny struct {
    Name *ast.Lit
}

and

type Generic struct {
    Name *ast.Lit
    Type *ast.Ident
}

the type system then will see if there's type any in a scope and will replace it with a type info node for that type, otherwise, interface{} will be used. A bit ugly and I am anything but sure if they will be really happy with that. Still a variant.
воскресенье, 26 июля 2020 г. в 02:11:18 UTC+3, Carla Pfaff:

Carla Pfaff

unread,
Jul 26, 2020, 1:06:16 AM7/26/20
to golang-nuts
On Sunday, 26 July 2020 at 03:13:30 UTC+2 Denis Cheremisov wrote:
The bad with any in builtins is there will be questions "why you use interface{}" if there's builtin any?", etc.

If Go has generics I expect that people will use "interface{}"/"any" a lot less outside of type parameter lists than today. Maybe gofmt could rewrite "interface{}" to "any", so there won't even be such a question for new code.

Carla Pfaff

unread,
Jul 26, 2020, 1:55:12 AM7/26/20
to golang-nuts
On Sunday, 26 July 2020 at 07:06:16 UTC+2 Carla Pfaff wrote:
Maybe gofmt could rewrite "interface{}" to "any", so there won't even be such a question for new code.

When I think about it, that's probably not possible for gofmt to do in a safe way. 

Nuno Cruces

unread,
Jul 28, 2020, 12:18:57 PM7/28/20
to golang-nuts
Please, don't make type optional. IMO, removing it altogether with this proposal (type any = interface {}) is probably great. Making type mandatory (as originally proposed) is fine. Making it optional is much worse than both those options. As much as possible, there should be one way to do it.
Reply all
Reply to author
Forward
0 new messages