Skip to content

proposal: syntax fix for := 'shadow variable' problem #30163

@BrianWill

Description

@BrianWill

Problem

The := syntax is error-prone when dealing with multiple targets and variables of enclosing scope:

// often a mistake:
var a int
{
  a, b := foo()    // creates a new 'a' in this scope instead of using 'a' of outer scope
}

// the fix
var a int
{
  var b *Bar
  a, b = foo()
}

Not only is the fix verbose, it defeats a nicety of inferred typing that it often spares us from having to remember precise return type(s), e.g. whether a returned type is a pointer or not:

a := bar()       // whether bar() returns an *X or just an X, we often don't need to care

Normally, Go disallows redeclarations, but it makes an exception for the := syntax, such that we can't look at an := assignment and know for sure which of the target variables are being declared:

x, y, z := foo()    // only one of x, y, and z must be new, but just looking here doesn't tell us which variables are new

Another problem is that we can't mix 'name' targets and 'non-name' targets:

a, b[0] := foo()          // compile error: b[0] is a non-name target

Proposal

A syntax that marks individual targets of assignment as new variables. Let's say for now we'll use ' as a suffix marker:

x', y, z' = foo()         // assign to new variable 'x', existing variable 'y', and new variable 'z'

We wouldn't remove the existing := syntax, of course, but in time its use would be considered non-standard style.

With this marking syntax, I don't see a good reason to disallow mixing in non-name targets:

a', b[0] = foo()          // ok

It would also be nice if we could optionally specify types of one or more of the newly declared target variables to make them different from the corresponding return type:

a' Fruit, b = bar()       // first return type of bar() is Banana, but we store it in a Fruit interface variable

As a last little bonus, perhaps type casts could be allowed on assignment targets:

a' int64(), b' = foo()     // the int64() indicates a cast of the return value assigned to 'a'

//spares us from having to create an additional variable of the type we don't want:
notA', b' = foo()
a' = int64(notA)

I think these syntax choices are compatible with the existing grammar, but regardless, I'm not strongly attached to this exact syntax.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions