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: Go 2: left side syntax for new variable #61933

Closed
jimsnab opened this issue Aug 10, 2023 · 3 comments
Closed

proposal: Go 2: left side syntax for new variable #61933

jimsnab opened this issue Aug 10, 2023 · 3 comments
Labels
LanguageChange Proposal v2 A language change or incompatible library change
Milestone

Comments

@jimsnab
Copy link

jimsnab commented Aug 10, 2023

Author background

  • Would you consider yourself a novice, intermediate, or experienced Go programmer? experienced
  • What other languages do you have experience with? c/c++, asm, ruby, python, c#, dart, perl

Related proposals

  • Has this idea, or one like it, been proposed before? unsure
    • If so, how does this proposal differ?
  • Does this affect error handling? no
    • If so, how does this differ from previous error handling proposals?
  • Is this about generics? no
    • If so, how does this relate to the accepted design and other generics proposals?

Proposal

  • What is the proposed change?

Within a scope, when there is a mix of existing and new variables to declare, allow some syntax to differentiate which variables need to be new within the scope.

Instead of:

// go v1
func example() (err error) {
  if something {
    var data any     // <-- trying to avoid this
    data, err = otherFunction()
    fmt.Println(data)
  }
  return 
}

a left side syntax to apply := semantics on a per argument basis; here I chose new token as the way

// proposed
function example() (err error) {
  if something {
    new data, err = otherFunction()
    fmt.Println(data)
  }
  return
}
  • Who does this proposal help, and why?

There is a particular inconsistency with := behavior whether a statement is at the function root scope, or in a nested scope.

// go v1
function example() (err error) {
  data1, err := otherFunction()   // data1 instantiated, err is not
  if something {
    data2, err := otherFunction()  // error, `err` declared and not used
    fmt.Println(data1, data2)
  }
  return
}

With the new syntax, a mix of instantiation and existing can be specified.

// proposed
function example() (err error) {
  data1, err := otherFunction()   // data1 instantiated, err is not
  if something {
    new data2, err = otherFunction()  // data2 instantiated, err is not
    fmt.Println(data1, data2)
  }
  return
}

or

// proposed
function example() (err error) {
  new data1, err = otherFunction()   // data1 instantiated, err is not
  if something {
    new data2, err = otherFunction()  // data2 instantiated, err is not
    fmt.Println(data1, data2)
  }
  return
}

It would also help in this common pattern:

function example() (err error) {
  if something {
    if new data, err = otherFunction(); err != nil {
      return     // error assigned to return value `err` as expected
    }
    fmt.Println(data)
  }
}

These examples are contrived for simplicity. The examples show the mix with return value err, because it is so common, but the scenario applies to any left side variable. The use cases around this mixed instantiation are broad.

The use of new as the keyword is unimportant. Any syntax that allows the variable to be marked for duck type declaration is welcome. Or, the proposal could be reversed, and "fall through" types marked, like

// proposed
function example() (err error) {
  data1, err := otherFunction()   // data1 instantiated, err is not
  if something {
    data2, <err> := otherFunction()  // data2 instantiated, err is not
  }
  return
}
  • Please describe as precisely as possible the change to the language.

Add a keyword or symbol to mark a left side parameter as "new"

  • What would change in the language spec?

Unsure, I do not have language authoring expertise.

  • Please also describe the change informally, as in a class teaching Go.
  • Is this change backward compatible? yes
    • Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit.
      Show example code before and after the change.
    • Before
    • After
  • Orthogonality: how does this change interact or overlap with existing features? The := assignment logic
  • Is the goal of this change a performance improvement? Easier tasks such as rearranging code, and less labor. Making a var data mydatatype line above a statement can become a chore when mydatatype is not trivial.
    • If so, what quantifiable improvement should we expect?
    • How would we measure it?

Costs

  • Would this change make Go easier or harder to learn, and why? Difficult to predict.
  • What is the cost of this proposal? (Every language change has a cost). Don't have the context or expertise to estimate a cost.
  • How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected? Most
  • What is the compile time cost? Minimal
  • What is the run time cost? None
  • Can you describe a possible implementation?
  • Do you have a prototype? (This is not required.)
@jimsnab jimsnab added LanguageChange Proposal v2 A language change or incompatible library change labels Aug 10, 2023
@gopherbot gopherbot added this to the Proposal milestone Aug 10, 2023
@DeedleFake
Copy link

DeedleFake commented Aug 10, 2023

Adding new keywords is not backwards compatible, and adding new as a new keyword is even less backwards compatible than most because new is already a predeclared identifier.

A similar proposal that has been suggested on several occasions involves moving the : from the := and attaching it to the variable names on the left, such as :data2, err = otherFunction(). That would be backwards compatible, but that was shot down for being too subtle if I remember right. See #377 (comment), where it was proposed before Go 1.

Random thought I just had that also might have been proposed before: Reverse the colons so that attaching a : to a variable with := causes it to not be shadowed, and then make it an error to put colons on every variable on the left-hand side and an error to use the colon with a new identifier that doesn't shadow anything. I don't think that quite solves the a[b], c := f() problem, though.

@jimsnab
Copy link
Author

jimsnab commented Aug 10, 2023

What if the logic was reversed and syntax used parenthesis?

data2, (err) := otherFunction()

It is a v1 a non-name error to do this.

@ianlancetaylor
Copy link
Contributor

Closing as a dup of #377.

@ianlancetaylor ianlancetaylor closed this as not planned Won't fix, can't repro, duplicate, stale Sep 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LanguageChange Proposal v2 A language change or incompatible library change
Projects
None yet
Development

No branches or pull requests

4 participants