Skip to content
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: spec: Mixed Declaration-Assignment Operators in Multi-Variable Assignments #71522

Closed
3 of 4 tasks
mikeschinkel opened this issue Feb 1, 2025 · 2 comments
Closed
3 of 4 tasks
Labels
LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee LanguageProposal Issues describing a requested change to the Go language specification. Proposal
Milestone

Comments

@mikeschinkel
Copy link

mikeschinkel commented Feb 1, 2025

Go Programming Experience

Experienced

Other Languages Experience

Go, PHP, Javascript, Bash, SQL

Related Idea

  • Has this idea, or one like it, been proposed before?
  • Does this affect error handling?
  • Is this about generics?
  • Is this change backward compatible? Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit

Has this idea, or one like it, been proposed before?

Yes, this concept has been explored in multiple previous Go issue discussions, though with different proposed solutions.

This proposal builds on these earlier discussions while taking a more focused, backward-compatible approach that specifically addresses the refactoring use case. Previous proposals either suggested more sweeping language changes or focused primarily on error handling patterns, whereas this proposal targets a precise pain point with minimal language modification.


Issue #377: Various changes to :=

This early discussion focused primarily on variable shadowing concerns and := behavior with return parameters. While it was ultimately declined (":= is for new variables"), this reasoning actually supports this proposal because:

  • It maintains the principle that := declares new variables
  • It makes the distinction between new and existing variables more explicit
  • The syntax clearly shows developer intent regarding variable reuse vs. declaration
  • It doesn't change any existing shadowing behavior or special cases

Issue #6842: Allow tuple assignment to mix new and existing variables

This issue suggested a different syntax (x, :=y = expr) for mixing declarations and assignments. While it was not accepted, this proposal differs in key ways:

  • It maintains Go's existing operator placement conventions
  • The syntax makes it clear per-variable whether it's new or existing
  • It focuses specifically on refactoring use cases rather than general syntax enhancement
  • It requires simpler parser changes

Note this proposal provides a superior solution to the concerns raised in #6842 about struct field
and array index assignments. Where #6842 raised valid concerns about ambiguous behavior during
error cases, our proposal eliminates this ambiguity through explicit declaration intent:

goCopys.field =, err := someFunction()   // Explicitly shows: field exists, err is new
arr[i] =, newVal := compute()      // Explicitly shows: array element exists, newVal is new

This explicit syntax addresses the fundamental safety concern raised in #6842 - the risk of unintended modifications during error cases. Rather than restricting functionality, our proposal makes the developer's intentions clear through syntax.


Issue #30318: proposal: spec: make it easier to use existing names in short variable declarations

This discussion provides strong support for this proposal by documenting real-world refactoring pain points:

  • Multiple developers describe the exact problems this proposal solves
  • The discussion shows these issues persist across many code bases
  • Their examples align perfectly with this proposal's standard library case examples
  • No technical objections were raised that would apply to this approach

Issue #31064: proposal: Go 2: short variable declarations with existing variables

This issue further reinforces the need for better handling of existing variables during refactoring, though it proposed a different solution. The discussion supports this proposal's approach because:

  • It documents additional real-world refactoring scenarios that this proposal would improve
  • It shows how the current rules lead to unnecessary code complexity
  • The examples align with patterns found in the standard library
  • It addresses the same problems while maintaining clearer semantics about variable declaration status
  • Unlike the broader changes suggested in proposal: cmd/vet: require explicit variable shadowing #31064, this proposal maintains Go's existing scoping rules

Issue #38388: Go 2: reform the variable redeclaration syntax to avoid some confusions and inconveniences

While other proposals like #38388 suggest more sweeping changes to Go's declaration syntax, this
proposal:

  • Takes a minimalist approach that addresses the most common refactoring pain points.
  • It requires minimal changes to the language specification,
  • It maintains backward compatibility,
  • It preserves Go's existing safety guarantees, and
  • It introduces no new keywords or operators.

This focused approach aligns with Go's philosophy of incremental improvement while solving real developer needs.


Many of the discussions on these issues occurred during consideration of a backward-compatibility-breaking Go 2.0. Since then, the Go team has committed to maintaining backward compatibility, making incremental improvements that don't break existing code. This proposal aligns with that approach by introducing new syntax that's fully backward compatible while addressing long-standing developer pain points.

Does this affect error handling?

This proposal is not focused on error handling; it addresses the broader issue of mixed declaration and assignment operators in multi-variable assignments. However, it would have a positive impact on code organization in error handling scenarios, which represent a common use case for multi-variable assignments in Go.

In current Go code, developers frequently need to predeclare error variables when refactoring error handling logic, particularly when moving error handling code between functions or restructuring error checks. As noted by Robert Griesemer in Issue #6842, this creates situations where developers must add explicit variable declarations, even though the intent and logic of the code remain unchanged.

For example, when refactoring code that handles errors across multiple operations, developers currently write:

var err error
result, err = firstOperation()
if err != nil {
    return err
}
result, err = secondOperation()

The proposed syntax would enable more direct expression of the same logic:

result =, err := firstOperation()
if err != nil {
    return err
}
result =, err := secondOperation()

This improvement in code organization is a side benefit of the proposal's broader goal of making variable declaration status more explicit in multi-variable assignments. It maintains Go's existing error handling patterns while reducing the structural overhead commonly encountered when refactoring error handling code. The proposal does not modify how errors are handled or processed; it simply makes the code structure more maintainable when working with existing error handling patterns.

Is this about generics?

While this proposal does not specifically address generics, it has been designed to work seamlessly with Go's generic type system. The proposed syntax for mixed declaration-assignment operators maintains compatibility with generic type inference and type parameter substitution. Since the proposal only affects how variables are declared and assigned, not how types are determined, it integrates naturally with the existing generic type system without requiring any special handling.

Proposal

Abstract

This proposal introduces syntax for allowing mixed declaration (:=) and assignment (=) operators in multi-variable assignments. This enhancement specifically targets reducing cognitive load and boilerplate during code refactoring, a common pain point in Go development.

While the current syntax is generally adequate for initial code authoring, refactoring operations
often require developers to add explicit variable declarations and split assignments, increasing complexity and the potential for errors.

This proposal also endures to maintain complete backward compatibility while reducing cognitive
load during common refactoring operations, providing immediate value to Go developers without
requiring additional changes to existing codebases to gain its benefits.

Background

In current Go, when refactoring code with multi-variable assignments, all variables must either be declared using := or assigned using =. When refactoring moves some variable declarations earlier in the scope but not others, developers must add explicit var declarations and change := to =. This creates friction during refactoring and increases the cognitive load of what should be simple code modifications.

Many developers note that while writing new code with the current rules are straightforward _
— e.g. "just declare the variable" — the real pain point emerges during refactoring when code
structure needs to change. This proposal aims to address this specific refactoring scenario as
how new code is written is a less relevant use-case for this proposal. Still, new code can
benefit by being more explicit, when applicable.

Syntax and Semantics

This proposal builds on Go's existing multi-value assignment rules, adding the ability to mix := and = operators:

response =, err := client.Do(req)  // response exists, err is new

The rules remain straightforward:

  • Use = for variables already in scope (like current assignments)
  • Use := for new variables (like current short declarations)
  • Right-hand expression must return the correct number of values
  • Existing type inference and scope rules apply unchanged

This maintains Go's current semantics while enabling cleaner refactoring operations.

Rationale

Refactoring Go code frequently requires moving variable declarations and changing code structure. These changes often impact the declaration status of variables, leading to cascading modifications:

  1. When moving code, variables that were previously declared by := may now be declared earlier
  2. This forces developers to:
    • Add explicit var declarations
    • Change := to = at usage sites
    • Split multi-variable assignments
    • Coordinate all these changes while maintaining correctness

Each of these required changes introduces potential for errors and increases cognitive load during what should be simple refactoring operations. These refactoring challenges have been well-documented in multiple Go issue discussions (#30318, #31064), showing that developers consistently encounter these pain points across different codebases and over many years.

The proposal preserves Go's fundamental principle that := declares new variables. Rather than
expanding := to cover every possible declaration scenario, it specifically addresses the common
refactoring case where some variables in a multi-variable statement are new while others already
exist. This maintains the simplicity of := for new variables while reducing friction during code maintenance.

This explicit syntax helps prevent accidental variable shadowing, a common source of bugs in current Go code. Consider the current behavior:

a := 1
a, b := 2, 3  // Silently shadows a

The proposed syntax makes variable reuse explicit when that is the developer's intent:

a := 1
a =, b := 2, 3  // Clearly shows intent to reuse a

Real-world Impact

The need for this change is demonstrated by developer experiences shared across multiple Go issue discussions.

From Issue #31064: Variable Declaration and Resource Management

"Having to split declarations across multiple lines makes it harder to see the logical
grouping of operations, particularly in resource management code where deferred cleanup is
involved"

"The current approach of forcing var declarations actually makes the code less clear because
the type information gets separated from the initialization"

"Every time you need to move a variable declaration earlier, you end up touching multiple
lines of code, increasing the chance of introducing bugs"

From Issue #30318: Refactoring Experience

"When refactoring code, I often find myself in a position where I need to initialize vars
before a loop/function/if statement and then update them within that block. This forces me to
either: Initialize with := and update with =, or declare the vars with var and then use = for both operations... I find it frustrating to have to declare all these variables manually when they could be inferred."

"Not being able to reuse variables in := declarations is a constant source of friction when
refactoring... A lot of Go code has long functions with many variables, and during refactoring
you often need to move initializations around... every time I change the order of operations,
I need to explicitly redeclare variables that were previously declared by :="

From Community Discussions

The broader Go community has repeatedly encountered these challenges, as evidenced by discussions across multiple platforms. Developers frequently express confusion about variable declaration patterns, particularly in error handling scenarios.

From Stack Overflow, developers highlight how the current behavior can lead to subtle bugs:

"The current behavior of := can lead to unexpected variable shadowing. For example, when a :=
1 is followed by a, b := 2, 3, the first 'a' is silently shadowed rather than reused. This
creates subtle bugs that could be prevented with more explicit syntax."

In a Reddit discussion, experienced developers express frustration with the current limitations:

"The error message 'no new values on left side of :=' is particularly frustrating because it
doesn't guide developers toward the correct solution. Often, we know exactly what we want to
do - reuse some variables while declaring others - but the language forces us to restructure our code in unnatural ways."

The Go Forum discussions reveal that even seasoned developers struggle with these constraints in their daily work:

"The error variable handling in Go often leads to confusion, especially for newcomers. The
requirement to predeclare variables just to handle errors properly seems to go against Go's
principle of clear and straightforward code."

These experiences demonstrate that the challenges this proposal addresses represent real friction in day-to-day Go development.

Benefits

  1. Simplifies Common Refactoring Operations:

    • Moving code between blocks or functions
    • Extracting variables used in multiple places
    • Adding error handling to existing code
    • Converting local variables to struct fields
  2. Reduces Cognitive Load:

    • No need to track variable declaration status
    • Fewer coordinated changes required
    • Clearer expression of intent
  3. Improves Code Maintainability:

    • Less boilerplate during refactoring
    • Reduced chance of introducing errors
    • Better support for incremental code evolution
  4. Preserves Code Structure:

    • Avoids splitting multi-variable assignments
    • Maintains logical grouping of operations
    • Keeps related code together
  5. Improved Error Messaging:

    • The proposal enables more precise and actionable compiler error messages. Instead of the current generic "no new values on left side of :=" error, the compiler could provide specific guidance:
    // Current error
    foo, err := bar()  
    foo, err := baz()   // error: no new values on left side of :=
    
    // Proposed error
    foo, err := bar()     
    foo, err := baz()   // error: no new values on left side of :=; use = instead

    These clearer error messages help developers understand and correct common mistakes while learning the language.

The benefits of this approach have been validated by multiple developer discussions (#30318, #31064), where the ability to clearly express intent during refactoring was consistently highlighted as a key need.

Mental Model

Current Complexity

When refactoring code that uses :=, developers must maintain multiple mental contexts simultaneously. They must track which variables are already declared in the current scope, remember which variables need explicit declarations, consider whether to split multi-variable assignments, and manage the coordination of multiple changes while preserving correctness. This cognitive overhead diverts attention from the actual refactoring task at hand.

Proposed Simplification

This proposal reduces cognitive load during refactoring by enabling developers to indicate their intent explicitly for each variable. The syntax allows single-line changes that preserve code structure while maintaining clear communication about variable lifecycle. This approach eliminates the need to coordinate multiple changes across different parts of the code.

Impact on Code Understanding

The proposed syntax makes variable handling more explicit. When developers see var1 =, var2 := func(), they immediately understand that var1 exists while var2 is new. This eliminates the need to search for previous declarations and enables local reasoning about variable lifecycle. The syntax reduces the mental juggling required during refactoring operations.

Impact on Development Workflows

The proposed syntax specifically addresses several workflow challenges identified in #31064:

  1. Code Review Impact:
    The changes become more localized, with clearer intent during refactoring changes. Reviewers can more easily verify correctness because fewer lines need modification.

  2. IDE Integration:
    The explicit syntax enables simpler refactoring operations, clearer static analysis opportunities, and better quick-fix suggestions.

  3. Maintenance Benefits:
    The proposal reduces the chance of introducing bugs during refactoring, preserves logical grouping of operations, and maintains clear connections between variable declarations and their usage.

Impact on Development Workflows

The proposed syntax specifically addresses several workflow challenges identified in #31064:

  1. Code Review Impact:

    • Changes are more localized
    • Intent is clearer when reviewing refactoring changes
    • Fewer lines need to be modified
  2. IDE Integration:

    • Simpler refactoring operations
    • Clearer static analysis opportunities
    • Better quick-fix suggestions possible
  3. Maintenance Benefits:

    • Reduced chance of introducing bugs during refactoring
    • Better preservation of logical grouping
    • Clearer connection between variable declarations and usage

Costs

The implementation costs of this proposal are minimal and well-contained. The changes required are straightforward and build upon existing Go language features without introducing fundamental complexities.

The costs are minimal because:

  • No new operators or keywords are introduced
  • Existing variable declaration rules remain unchanged
  • IDE tooling can easily suggest correct operator usage
  • The syntax follows naturally from existing Go patterns

Implementation

The implementation would require changes to:

  1. The Go parser to recognize mixed operators in multi-variable assignments
  2. The type checker to verify correct usage of declaration/assignment operators
  3. The compiler to ensure proper variable initialization

Examples

The following examples — the first three (3) of which are from the Go Standard Library —
demonstrate real refactoring challenges found in the Go code.

While the standard library examples come from just a few files in only one standard package —
net/http — similar patterns appear throughout the standard library, indicating these are
common refactoring needs rather than isolated cases.

Example 1: Context Deadline Management

This example shows how refactoring context management often requires splitting logically related operations.

Source: net/http/client.go#L365-L367

// Current implementation requires splitting the operation
var cancelCtx func()
req.ctx, cancelCtx = context.WithDeadline(oldCtx, deadline)
return cancelCtx, func() bool { return time.Now().After(deadline) }

// Proposed syntax preserves the logical grouping
req.ctx =, cancelCtx := context.WithDeadline(oldCtx, deadline)
return cancelCtx, func() bool { return time.Now().After(deadline) }

This pattern demonstrates key benefits:

  • Preserves code structure by avoiding split declarations
  • Maintains logical grouping of related operations
  • Reduces cognitive load by eliminating the need to track variable declaration status

Example 2: Request Parsing with Error Handling

This example illustrates how refactoring error handling often forces separation of related variable handling.

Source: net/http/fs.go#L139-L148

// Current implementation requires separate var declarations
var url_ *url.URL
var requestURI string
if rp.method == "CONNECT" && rp.protocol == "" {
    url_ = &url.URL{Host: rp.authority}
    requestURI = rp.authority // mimic HTTP/1 server behavior
} else {
    var err error
    url_, err = url.ParseRequestURI(rp.path)
    ...
}

// Proposed syntax keeps the operation unified
var url_ *url.URL
var requestURI string
if rp.method == "CONNECT" && rp.protocol == "" {
    url_ = &url.URL{Host: rp.authority}
    requestURI = rp.authority // mimic HTTP/1 server behavior
} else {
    url_ =, err := url.ParseRequestURI(rp.path)
    ...
}

This pattern shows how the proposal:

  • Simplifies error handling code structure
  • Reduces boilerplate during refactoring
  • Makes the code's intent clearer

Example 3: Request Body Management

This example shows how refactoring can force separation of error handling from the operations that produce them.

Source: net/http/transport.go#L618-L619

// Current implementation splits related operations
if resp, err := altRT.RoundTrip(req); err != ErrSkipAltProtocol {
    return resp, err
}
var err error
req, err = rewindBody(req)

// Proposed syntax keeps related operations together
if resp, err := altRT.RoundTrip(req); err != ErrSkipAltProtocol {
    return resp, err
}
req =, err := rewindBody(req)

This pattern demonstrates how the proposal:

  • Supports incremental code evolution
  • Reduces chances for errors during refactoring
  • Keeps related operations together without artificial splitting

Example 4: Resource Management Pattern

This example demonstrates how refactoring resource cleanup code often requires separating declarations:

// Current pattern requires splitting declarations
var file *os.File
var err error
file, err = os.Open(name)
if err != nil {
    return err
}
defer file.Close()

buf := make([]byte, size)
n, err := file.Read(buf)  // Forced to use var err above

// With proposed syntax
file =, err := os.Open(name)
if err != nil {
    return err
}
defer file.Close()

buf := make([]byte, size)
n =, err := file.Read(buf)  // Clear intent to reuse err

These real-world examples from the standard library demonstrate how this proposal addresses actual refactoring pain points in production Go code. Each case shows how the current syntax forces artificial separation of related operations during refactoring, and how the proposed syntax would maintain better code organization while reducing cognitive overhead.

Compatibility

This proposal maintains complete compatibility with existing Go code:

Source Compatibility

  • All existing Go code continues to compile without changes
  • The new syntax is only enabled when explicitly mixing operators
  • Existing := and = behaviors remain unchanged
  • No changes to current variable scoping rules

Backward Compatibility

Since the Go team has moved away from breaking changes:

  • This proposal requires no Go 2 transition
  • Fits within current Go 1 compatibility guidelines
  • Introduces no deprecation requirements
  • Creates no migration burden

Future Extensions

This proposal is intentionally limited in scope to address a specific pain point in Go development. No future extensions are envisioned as part of this proposal. The goal is to solve the concrete problem of mixed declaration and assignment in multi-variable statements while maintaining Go's simplicity and clarity.

Questions for Discussion

  1. What level of tooling support should be recommended?
    • Automatic detection of refactoring opportunities
    • Quick fixes for converting between forms
    • Linting rules for consistency

The proposal itself is complete and does not require resolution of these tooling questions, which can be addressed as follow-up enhancements.

Language Spec Changes

The language specification would require changes to Section 11.4 "Short variable declarations" to accommodate mixed declaration-assignment operators in multi-variable assignments. The primary modification would extend the current short variable declaration rules to allow mixing of = and := operators within the same statement."

The current spec language in Section 11.4 states that short variable declarations must declare all non-blank variables. This would be modified to allow a mixture of declarations and assignments, where each variable on the left side of the assignment would be explicitly marked with either = (for existing variables) or := (for new variables).

The modified specification would add language similar to:

"A mixed declaration-assignment statement may declare some new variables and assign to existing ones using a combination of = and := operators. Each variable on the left side must be explicitly marked with either = (indicating assignment to an existing variable) or := (indicating declaration of a new variable). The expression list on the right must return the same number of values as the number of variables on the left. Type inference for newly declared variables follows the same rules as current short variable declarations."

For example, this syntax would be valid:

existing =, new := expression

The type-checking rules would remain unchanged:

  • Variables marked with := must not already exist in the current scope
  • Variables marked with = must already exist in the current scope
  • The type of each expression on the right must be assignable to the corresponding variable on the left

This change preserves Go's existing scoping rules and type system while enabling more explicit handling of variable declarations and assignments in multi-variable statements.

Informal Change

Today we're going to look at a proposed improvement to Go's variable declaration and assignment syntax. As you know, in Go we use := to declare new variables and = to assign values to existing variables. But what happens when we're working with multiple variables at once, and some are new while others already exist? Currently, we have to split these operations or add explicit variable declarations, which can make our code more complex than it needs to be.

Let's look at a common scenario. Imagine you're writing code that makes an HTTP request and processes the response. You might start with:

response, err := client.Do(request)

Later, as you refactor your code, you might need to reuse the response variable but declare a new error. In current Go, you'd need to write:

var err error
response, err = client.Do(request)

With the proposed change, you could write this more directly:

response =, err := client.Do(request)

The syntax tells Go exactly what you want: "use the existing response variable, but declare err as new." It's like having the best of both worlds – you can mix and match := for new variables and = for existing ones in the same statement.

This might seem like a small change, but it makes a big difference when you're refactoring code. Instead of having to add variable declarations or split your operations across multiple lines, you can clearly express your intent in a single line. The code becomes more maintainable and easier to understand, as the syntax directly shows which variables are new and which are being reused.

Think of it as being more explicit about your intentions. Rather than Go having to guess whether you want to create new variables or reuse existing ones, you're telling it directly: "this one is new, that one already exists." This clarity helps both the compiler and other developers understand your code better.

Is this change backward compatible?

Yes, this change is fully backward compatible with existing Go code. The proposal introduces new syntax without modifying the behavior of any existing Go code. All current Go programs will continue to compile and run exactly as they do today.

Consider this existing code:

response, err := client.Do(request)  // Works today
response, err = client.Do(request)   // Works today

After the change, this code continues to work identically. The new syntax only takes effect when explicitly combining = and := operators:

response =, err := client.Do(request)  // New syntax, optional

The proposal maintains Go's commitment to backward compatibility by adding capabilities without breaking existing code or changing current behavior. No code changes are required to adopt Go versions that include this feature.

Orthogonality: How does this change interact or overlap with existing features?

This proposal interacts minimally with existing Go features, as it builds directly on Go's established variable declaration and assignment operators. The change maintains the current semantics of both := and = while enabling their combined use in multi-variable statements. This approach preserves Go's existing scoping rules, type system, and variable lifecycle management.

The proposal complements Go's current error handling patterns without modifying them. It works seamlessly with Go's multiple return values, defer statements, and package-level variables. The change has no impact on Go's type inference system, maintaining all existing type-checking rules.

This is not a performance-focused change, and will have no impact on performance; pro or con. The goal is to improve code clarity and reduce cognitive load during refactoring operations. The compilation and runtime behavior of programs would remain identical to their current implementation. There should be performance impact at runtime and I highly doubt any impact at compile time since the change only affects how variables are declared and assigned during compilation, not how they are handled at runtime.

Would this change make Go easier or harder to learn, and why?

This change would make Go easier to learn by making variable declaration and assignment rules more consistent and explicit. Currently, new Go developers must learn that they cannot mix := and = in multi-variable statements, even though this limitation doesn't serve a clear pedagogical purpose. When they encounter situations where some variables exist and others need to be declared, they must learn various workarounds that make the code less straightforward.

The proposed syntax actually reinforces Go's principles by making variable declaration status explicit. When a developer sees response =, err := client.Do(request), the code clearly communicates that response exists while err is new. This explicit marking helps learners understand variable lifecycle management more clearly than the current approach, where they must either split the operation into multiple statements or add separate variable declarations.

This explicitness aligns with Go's philosophy of clear, readable code. Rather than requiring developers to learn special cases and workarounds, the proposal allows them to express their intent directly. When teaching Go, instructors can now present a more coherent model: "use = for existing variables, := for new variables, and you can combine them when you need both." This consistency helps developers build a more accurate mental model of how Go handles variables.

Cost Description

The primary cost of this proposal is minimal and well-contained. It requires a small addition to Go's parser to recognize mixed operators in multi-variable assignments, along with corresponding updates to type checking logic. These changes are localized to specific components of the Go toolchain and do not affect other language features.

From a tooling perspective, IDEs and code analysis tools would need updates to properly handle the new syntax. However, since the change builds on existing operator behavior, these updates would be straightforward extensions of current variable tracking capabilities rather than complex new features.

The cognitive cost to developers is low because the proposal builds naturally on their existing understanding of Go's declaration and assignment operators. The syntax is intuitive for those who already understand Go's variable declaration rules, as it combines familiar operators in a logical way. No new operators or keywords are introduced, and developers can continue using existing patterns if they prefer.

Documentation would need minor updates to explain the new capability, but these changes would be small additions to existing variable declaration sections rather than extensive new material. The proposal's alignment with Go's current principles means that conceptual documentation would require minimal revision.

Changes to Go ToolChain

Primarily gopls, gofmt, and vet but really the underlying go/parser and go/types packages.

Performance Costs

The compile-time cost is minimal, requiring only straightforward parser and type-checker updates; there is no runtime cost as the change only affects how variables are declared during compilation.

Prototype

The implementation would require modifications to several key components of the Go compiler, with the most significant changes occurring in the parser and type checker.

In cmd/compile/internal/syntax/parser.go, the parser would need to be extended to recognize mixed operators in assignment statements. Currently, the parser treats := and = as mutually exclusive in multi-variable assignments. The modification would allow them to be mixed by updating the parseSimpleStmt() and parseAssignment() functions to handle individual operator tokens for each left-hand variable. The parser would need to distinguish between statements like x =, y := expr and traditional assignments.

The type checker changes would primarily affect cmd/compile/internal/types2/assignments.go. The assignability checks would need to be modified to handle mixed declaration-assignment statements. For each left-hand variable, the type checker would verify that variables marked with = exist in the current scope while those with := do not, maintaining Go's existing scoping rules. The check functions would need to track the declaration status of each variable independently within the same statement.

The go/types package would require corresponding updates to support the new syntax in the type checker. This would involve modifying the Check method to handle mixed declaration-assignment statements and ensuring proper type inference for newly declared variables while maintaining type compatibility checks for existing variables.

A prototype implementation could be developed in stages:

  1. First, modify the parser to recognize and generate AST nodes for the new syntax
  2. Update the type checker to handle these new AST nodes correctly
  3. Implement basic error reporting for invalid combinations
  4. Add support for the new syntax in go/printer for proper code formatting

The initial prototype could focus on these core compiler changes before addressing tooling updates. This would allow for early testing and validation of the syntax while deferring modifications to tools like gopls and vet.

@mikeschinkel mikeschinkel added LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee Proposal labels Feb 1, 2025
@gopherbot gopherbot added this to the Proposal milestone Feb 1, 2025
@gabyhelp gabyhelp added the LanguageProposal Issues describing a requested change to the Go language specification. label Feb 1, 2025
@mikeschinkel
Copy link
Author

mikeschinkel commented Feb 1, 2025

@seankhliao#21303 has been closed as a duplicate of #377, and #377 was filed in 2009 stalled because it was all over the map and almost all of the proposed solutions are not longer revelent given they were discussions had prior to decision to not have a Go 2 that introduced breaking changes.

Do you think we can actually get the discussion restarted somewhere, especially given all the effort I put into this proposal?

BTW, I filled this ticket because of concerns I have about #71460 being motivated in part as a very limited way to limit variable shadowing (pun not intended.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee LanguageProposal Issues describing a requested change to the Go language specification. Proposal
Projects
None yet
Development

No branches or pull requests

4 participants