-
Notifications
You must be signed in to change notification settings - Fork 17.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: Go 2: add "var name auto" to handle some edge cases in type inference #46109
Comments
What is "first assignment", exactly?
Does |
One of the things we didn't get right with the design of Go is that that there are too many different ways to declare a variable. Adding another way is not the solution. |
The simple answer is x has the type of the lexically first assignment. It’s already an error if you use a short declaration and the return types of f and g are incompatible. The interesting question is what if they are assignable but different types like an interface and a concrete. But that already occurs with short declarations and the lexically first rule is simple to understand and implement. |
I figured this was a long shot proposal but #33167 has been nagging me for a while so I might as well get the potential solution out there. The simple solution to the too many declaration types problem is to remove |
Maybe simply |
Personally, I think enforcing re-declared variables represented with a non-pure identifier form is good enough to avoid many confusions. |
I do not like this. Especially in larger functions, there can be large gaps between variable declarations and when they are first used. This makes it extremely unclear what type a variable will hold. The type of a variable should always be able to be easily found where it is declared. |
For the var f auto
f = func(a, b int) int { return a + b } case, the type of
This is not very true. Otherwise, type deduction should not be supported. |
@go101 As I had said, I was talking about cases where the space between variable declaration and first assignment is larger. For instance, variables that need to be declared in scope of the whole function, but the first use of the variable is in a conditional inside of a nested for-loop:
Also - it is true that the type of a variable can always be easily found, Type deduction works by using the type of the assigned value. The type of the assigned value can always be easily found by looking upwards in the function. However, with |
Why would you concern this? After all, between the declaration and the first assignment, the variable is not used at all. |
As my example shows, in order to figure out the type of an
this involves searching downward for the assignment, then back upward to figure out the type of the expression. in my example, this is illustrated by searching for the first assignment of |
I should also point out - what do we do with |
I think here only the first point is valid. For the others also exist for current already supported typed deducted variables. And I think the first point is not serious in most cases.
The OP mentioned this above:
Personally, I think the auto declaration and its first assignments should share the same innermost containing code block. |
Something like this is a little tricky to think through, but I think banning it would be more trouble than it's worth:
Logically, it's not worse than just
In this case, I think the compiler should say that x has type int from the first assignment, so x = "two" is an illegal assignment of a string to an int. |
The discussion above points out various difficulties with this proposal. The emoji voting does not show support. Therefore, this is a likely decline. Leaving open for four weeks for final comments. |
No further comments. |
Would you consider yourself a novice, intermediate, or experienced Go programmer?
Experienced.
What other languages do you have experience with?
Python, JavaScript, scattered others.
Would this change make Go easier or harder to learn, and why?
Marginally harder but it's an advanced feature users should only rarely encounter.
Has this idea, or one like it, been proposed before?
Not AFAIK, but it has a parallel in C/C++.
Who does this proposal help, and why?
It prevents type repetition in some cases and fills an inconsistency in the type system in others.
What is the proposed change?
As a special case, if a variable is declared with type
auto
, it will take infer type from the subsequent first assignment, as per the rules of:=
.For example in this case,
f
will infer a type offunc(int, int) int
:This is particularly helpful in cases of recursive closures (see #33167), which currently must be written like this if they aren't at the top level:
This leads to an inconvenient repetition of the type information.
With
auto
, the first line would bevar fac auto
and the rest would be the same.Another case in which there is an inconvenient repetition is this:
Essentially, the programmer is faced with the unfortunate dilemma of either shadowing err or redeclaring v2. Unfortunately, in some cases, redeclaring v2 is impossible because the type of v2 is in another unexported package.
Please describe as precisely as possible the change to the language.
auto
would be a predeclared identifier (or possibly a keyword at the risk of breaking existing packages) that, if not otherwise overwritten in function local scope, the compiler would interpret as an instruction to infer the type from a subsequent first assignment. Accessing an unassigned auto variable would be a compiler error. Like:=
short declarations,auto
would only be legal inside of a function/method, because first assignment is not well defined at the package level.What would change in the language spec?
Assuming it is added a magic declared identifier, the grammar for the language could remain the same. There would be a new section between "Short variable declarations" and "Function declarations" explaining that
var x auto
inside of a function has rules similar to:=
Please also describe the change informally, as in a class teaching Go.
Sometimes you want to use
:=
for its type inference but only create new variables for some of the types. For those scenarios, you can use the magic typeauto
withvar
like:Is this change backward compatible?
I believe so if implemented as a magic predeclared identifier.
Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit.
Show example code before and after the change.
See above.
What is the cost of this proposal? (Every language change has a cost).
How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected?
I think that tools that don't do type analysis like gofmt and goimports could be left as is.
What is the compile time cost?
Negligible.
What is the run time cost?
None.
Can you describe a possible implementation?
I am not familiar enough with the go tool internals, but I assume it can be done by reusing the type inference in use for
:=
plus some new code for the magic predeclared identifier.Do you have a prototype? (This is not required.)
No.
How would the language spec change?
See above.
Orthogonality: how does this change interact or overlap with existing features?
It overlaps with
:=
and makes proposals to remove variable shadowing more palatable.Is the goal of this change a performance improvement?
No.
If so, what quantifiable improvement should we expect?
How would we measure it?
Does this affect error handling?
It affects the case
:=
shadowingerr
by making it more palatable to write:It also makes this possible:
If so, how does this differ from previous error handling proposals?
It is not a comprehensive solution to error problems.
Is this about generics?
No.
The text was updated successfully, but these errors were encountered: