Type parameters syntax... Can it be improved?

220 views
Skip to first unread message

atd...@gmail.com

unread,
Mar 23, 2021, 9:16:44 PM3/23/21
to golang-nuts
Quick question...

Why do we need brackets to define a parametered function, struct etc...?

Why not change Go kinds to accept either a type (would produce a regular, function, structs, etc) or a new type parameter object that would implement the constraints (would produce a generic function definition)

for instance,

type parameter T

// [...]  some way to add constraint to T

func Max(v T) T{...} 

What are the brackets for? Just an idea.

Ian Lance Taylor

unread,
Mar 23, 2021, 9:41:15 PM3/23/21
to atd...@gmail.com, golang-nuts
Each call to Max can use a different value for T. We can call
Max[int] and Max[string]. How would we do that with this notation?

A type parameter really is a parameter to the function. Making it
syntactically similar to other non-type parameters seems like a good
idea to me.

Ian

atd...@gmail.com

unread,
Mar 23, 2021, 10:18:40 PM3/23/21
to golang-nuts
Since, we also know the type of v, It would be infered from it.

There is no variance, no dependent type... Meaning that the type of a Go variable does not change. 
So the constraints do not change midway through the program, including type names/definitions.

It does however require to have something that resemble a type definition beforehand.
A type parameter definition.

Ian Lance Taylor

unread,
Mar 23, 2021, 10:22:51 PM3/23/21
to atd...@gmail.com, golang-nuts
On Tue, Mar 23, 2021 at 3:19 PM atd...@gmail.com <atd...@gmail.com> wrote:
>
> Since, we also know the type of v, It would be infered from it.
>
> There is no variance, no dependent type... Meaning that the type of a Go variable does not change.
> So the constraints do not change midway through the program, including type names/definitions.
>
> It does however require to have something that resemble a type definition beforehand.
> A type parameter definition.

In some cases it can be inferred. But what about cases where it
can't? And what if I want to write

// IntMin is a function with type func(int, int) int.
var IntMin = Min[int]

?

The constraints don't change midway through a program, but in your
example the meaning of T does change.

Ian


> On Tuesday, March 23, 2021 at 10:41:15 PM UTC+1 Ian Lance Taylor wrote:
>>
>> On Tue, Mar 23, 2021 at 2:17 PM atd...@gmail.com <atd...@gmail.com> wrote:
>> >
>> > Quick question...
>> >
>> > Why do we need brackets to define a parametered function, struct etc...?
>> >
>> > Why not change Go kinds to accept either a type (would produce a regular, function, structs, etc) or a new type parameter object that would implement the constraints (would produce a generic function definition)
>> >
>> > for instance,
>> >
>> > type parameter T
>> >
>> > // [...] some way to add constraint to T
>> >
>> > func Max(v T) T{...}
>> >
>> > What are the brackets for? Just an idea.
>>
>> Each call to Max can use a different value for T. We can call
>> Max[int] and Max[string]. How would we do that with this notation?
>>
>> A type parameter really is a parameter to the function. Making it
>> syntactically similar to other non-type parameters seems like a good
>> idea to me.
>>
>> Ian
>
> --
> 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/5713130f-20c7-4b70-ba8f-2e9be22cb9c9n%40googlegroups.com.

atd...@gmail.com

unread,
Mar 23, 2021, 11:23:12 PM3/23/21
to golang-nuts
Mmmh, :/ depends. What is the type of IntMin for the compiler in your example? The same as Min?

If not, it is basically defining a regular function out of a generic function definition.
So it is merely about constraining the type parameter further to be of specific type int.

A simple closure would be a sensible way to deal with it easily. In general, one would define a general closure function with new type parameters that have aditional constraints.

Trying to see type parameters more like concrete types and interface types, just with different constraints enforced at compile-time than those of types and interface types.
Could make brackets redundant.

atd...@gmail.com

unread,
Mar 24, 2021, 1:31:01 AM3/24/21
to golang-nuts
Nevermind, I forgot about function return values.

Difficult to infer them without specifying them, isn'it?

Sorry... should have thought better.

Markus Heukelom

unread,
Mar 24, 2021, 8:28:07 AM3/24/21
to golang-nuts
I agree here that there is a lot of repetition in the function definitions of let's say a generic math package:

types Numbers { type float32,float64,  }

func Abs[T Floats](a T) T {}
func Sin[T Floats](a T) T {}  
func Cos[T Floats](a T) T {}  

etc. (50 orso more?)

It feels a bit redundant and "noisy" to the eye. I think in practice, any good generic packages will only use maybe one or two type parameters constrainsts (interfaces), and likewise most types (functions) will use very similar if not the same type parameters lists.

So I tried to come up with a solution similar to yours by predefining T which could then be directly. But as Ian illustrated there's issues that are not naturally solved. So I agree that the current proposal is simpler (with the downside of being a bit "noisier" wrt such a proposal).

Another solution that comes to mind would be to allow to some sort of grouping structure:

generic [T Numbers] {
    func Abs(a T) T {}
    func Sin(a T) T {}  
    func Cos(a T) T {}  
}

This would give all types within the group the same type parameters list.  The grouping my also be useful for documentation. Obvious downside is the extra level of indentation on package level (although it nicely separates the generic types from concrete types, so maybe just getting used to). Another downside is the introduction of the "generic" keyword. 

-Markus

at diar

unread,
Mar 24, 2021, 10:34:06 AM3/24/21
to Markus Heukelom, golang-nuts
Yes, and... (just in case someone else comes across this thread wondering in the distant future) , 

func(v T) T is not too big a problem but func(v T) R

If the function body has cases, i.e. flow sensitive, that's where the brackets are mandatory to make the inference more straightforwardly decidable. 

Unfortunately, that's what happens if returns are created by unboxing an interface for instance. We introduce variance. 

It might be solvable/partially solvable via constraint-propagation / type-flow analysis or we can be wise and just constrain return values to be of a specific type but then brackets are needed.












--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/x3ZffZXHMyA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/b802e7fe-4f72-4804-8c23-ea55ac4a5de0n%40googlegroups.com.

Martin Leiser

unread,
Mar 25, 2021, 7:18:07 AM3/25/21
to golang-nuts
Ian Lance Taylor schrieb am Dienstag, 23. März 2021 um 23:22:51 UTC+1:
On Tue, Mar 23, 2021 at 3:19 PM atd...@gmail.com <atd...@gmail.com> wrote:
>
> Since, we also know the type of v, It would be infered from it.
>
> There is no variance, no dependent type... Meaning that the type of a Go variable does not change.
> So the constraints do not change midway through the program, including type names/definitions.
>
> It does however require to have something that resemble a type definition beforehand.
> A type parameter definition.

In some cases it can be inferred.

But even if it can be inferred it should be possible to annotate the type I do expect,
to improve local readiblity and compile time error message quality:
I assume that "x" is later used in a context requiring the type to be "int":
          x := Min(someFunc(foo), someFunc(bar))
Here i can use:
          var x int = Min(someFunc(foo), someFunc(bar)))
but using
         x := Min[int]( someFunc(foo), someFunc(bar)))
The three version yield different error message, if the called function "someFunc()" return a float instead of the expected int.

But what about cases where it
can't? And what if I want to write

// IntMin is a function with type func(int, int) int.
var IntMin = Min[int] 
?

The constraints don't change midway through a program, but in your
example the meaning of T does change.


hmmm... if all I need throughout my whole package is one binding e.g. to "int",
or to the type parameter "MyParameterType" my function use for themselves it may get teadious to
repeat the [MyParameter] all over the place.
Type inferences helps, but weakens the quality of error messages.
So please always allow for a explicit type parameter annotation even if inference is possible.
(And doing so in a more global location may improve simplicity a lot;-)

Martin

at diar

unread,
Mar 25, 2021, 1:50:20 PM3/25/21
to Martin Leiser, golang-nuts
Yes that too. To differentiate between MinFloat and MinInt for instance. 


:) 

You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/x3ZffZXHMyA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/ba6f07e2-f89f-4d59-9f10-e0e2fcea004en%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages