You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I suppose this would be a little bit like way that the language handles untyped constants, in that the type of the function would be inferred based on how the function call expression is used. But there would be a big difference, which is that untyped constants have a default type, but here the "default type" would be a compiler error.
I'm concerned that the rules for when the type is inferred would be unclear to the person reading the program. People already get confused about untyped constants.
In any case putting this on hold for later consideration after we have more experience with generics.
While this is on hold, I'd like to give my two cents on this one:
I don't want type inference to get too smart, and IMO nobody should wish for this. When we'll start having big projects using generics, or complex libraries with functions having a certain number of type parameters, differing in subtle ways, interacting with each other etc... it'll become more and more difficult to read generic code, up to the point where (and that is already the case in a number of languages) it'll be necessary to know a tremendous part of the codebase to know what types you're actually dealing with, their constraints and such. So I left a thumb down, not because I think this is bad in itself, I just feel like it goes against Go's philosophy.
On the call side, because the current type inference is only limited based on function arguments, we can infer g from the return type of f:
g(f[int]()) // OK
But not the vise versa:
g[int](f()) // ERROR: cannot infer T
This seems OK initially since it applies the philosophy of "there is only one way of doing something". However, whenever we trying to do something with ..., it feels so much wierd (am I the only person?):
One must write the first style rather than the second. Was there a particular example (similar to other known limitations caused by particular examples) to prevent this during the design cycle of 1.18's generics?
@DeedleFake For now I think we may want to constrain this to a limited set of "assignments". Once we add sending results to a channel, we (probably) also need to add setting a map element or providing a map key. Then the question is what about indexing (do we infer an int?), etc. In the cases of channels and maps we have clearly defined types and so it makes sense to include those, but let's do this in a separate round, ounce we are happy with this in the first place.
The primary issue with this proposal is that in general, type-inference is not easily localized anymore to a single ("flat") assignment/function call. Consider:
funcf[Pany](xP) P { returnx }
varxfloat64=f(f(f(0)))
The return type P of the outermost call of f is inferred from the assignment, i.e., P is float. That informs f's argument type, which in turn determines the result type and argument type of the middle f call, and then the innermost f call. The type of 0 will then be inferred to be float64.
In general, this nesting can be arbitrarily deep, with many different generic functions at various instantiation levels. While type inference should be able to infer types in cases like these, our current type checkers are not organized in a way that makes such an approach easily feasible: type checking essentially happens recursively, bottom-up. To make this more general inference work, expressions will need to be type-checked "as a whole" which likely will require significant re-engineering of the type checker.
Is this issue really "solved"? My understanding was that #58650 does not implement this; it just makes this easier to implement.
Also, a small modification of the code from the top of this issue does not compile in the playground, not even with the version set to "Go dev branch". https://go.dev/play/p/ry-w07CKoct?v=gotip
Activity
ianlancetaylor commentedon Dec 21, 2021
I suppose this would be a little bit like way that the language handles untyped constants, in that the type of the function would be inferred based on how the function call expression is used. But there would be a big difference, which is that untyped constants have a default type, but here the "default type" would be a compiler error.
I'm concerned that the rules for when the type is inferred would be unclear to the person reading the program. People already get confused about untyped constants.
In any case putting this on hold for later consideration after we have more experience with generics.
leaxoy commentedon Dec 24, 2021
And generic parameter should can be infer lazily.
For example:
can write as:
ianlancetaylor commentedon Dec 24, 2021
@leaxoy That seems very different to me, and should be a separate issue, not this one. Thanks.
mlevieux commentedon Jan 3, 2022
While this is on hold, I'd like to give my two cents on this one:
I don't want type inference to get too smart, and IMO nobody should wish for this. When we'll start having big projects using generics, or complex libraries with functions having a certain number of type parameters, differing in subtle ways, interacting with each other etc... it'll become more and more difficult to read generic code, up to the point where (and that is already the case in a number of languages) it'll be necessary to know a tremendous part of the codebase to know what types you're actually dealing with, their constraints and such. So I left a thumb down, not because I think this is bad in itself, I just feel like it goes against Go's philosophy.
changkun commentedon Apr 17, 2022
For the following
g
andf
:On the call side, because the current type inference is only limited based on function arguments, we can infer
g
from the return type off
:But not the vise versa:
This seems OK initially since it applies the philosophy of "there is only one way of doing something". However, whenever we trying to do something with
...
, it feels so much wierd (am I the only person?):One must write the first style rather than the second. Was there a particular example (similar to other known limitations caused by particular examples) to prevent this during the design cycle of 1.18's generics?
14 remaining items
fzipp commentedon Mar 31, 2023
I guess that should be
z, v := g[int]
.griesemer commentedon Mar 31, 2023
@DeedleFake For now I think we may want to constrain this to a limited set of "assignments". Once we add sending results to a channel, we (probably) also need to add setting a map element or providing a map key. Then the question is what about indexing (do we infer an
int
?), etc. In the cases of channels and maps we have clearly defined types and so it makes sense to include those, but let's do this in a separate round, ounce we are happy with this in the first place.griesemer commentedon May 16, 2023
The primary issue with this proposal is that in general, type-inference is not easily localized anymore to a single ("flat") assignment/function call. Consider:
The return type
P
of the outermost call off
is inferred from the assignment, i.e.,P
is float. That informsf
's argument type, which in turn determines the result type and argument type of the middlef
call, and then the innermostf
call. The type of0
will then be inferred to befloat64
.In general, this nesting can be arbitrarily deep, with many different generic functions at various instantiation levels. While type inference should be able to infer types in cases like these, our current type checkers are not organized in a way that makes such an approach easily feasible: type checking essentially happens recursively, bottom-up. To make this more general inference work, expressions will need to be type-checked "as a whole" which likely will require significant re-engineering of the type checker.
Putting back on proposal-hold for now.
LeGamerDc commentedon Jan 14, 2024
[#58650] solved the problem, should close now
zigo101 commentedon Jan 14, 2024
Solved?
pat42smith commentedon Jan 14, 2024
Is this issue really "solved"? My understanding was that #58650 does not implement this; it just makes this easier to implement.
Also, a small modification of the code from the top of this issue does not compile in the playground, not even with the version set to "Go dev branch". https://go.dev/play/p/ry-w07CKoct?v=gotip
griesemer commentedon Jan 16, 2024
This issue is not solved. See this comment for details. Leaving on hold.
kkqy commentedon Jun 7, 2024
I meet the same problem.
I use this pattern to pass variable options.