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: "escape statement" for error handling #57236

Closed
golightlyb opened this issue Dec 10, 2022 · 1 comment
Closed

proposal: Go 2: "escape statement" for error handling #57236

golightlyb opened this issue Dec 10, 2022 · 1 comment
Labels
error-handling Language & library change proposals that are about error handling. FrozenDueToAge LanguageChange Proposal v2 A language change or incompatible library change
Milestone

Comments

@golightlyb
Copy link
Contributor

A lot of error checking in Go takes the form:

  1. Check if an error has been returned
  2. Return something

There are many attempts at no. 1 (#41908, #33029, #32848, #37243, #32848, #56895).

There are also attempts including no. 2 (the draft design, #56355, #21161, #18721 - most of these return zero values followed by the error).

This proposal suggests a new "escape statement" written \ foo, bar with the syntax EscapeStmt = U+005C ExpressionList .

  • which may appear only directly after an assignment (not any general expression!)
  • where the last value of that assignment is exactly either type error or type bool
  • if the last value is an error and is not nil or if the last value is a boolean and is false, returns from the enclosing function the values following the backslash (acting like a return statement when it comes to defers, etc.)
  • Otherwise, the values following the backslash are not evaluated
  • the examined value is never treated as an unused value

Note that this syntax does not allow an empty ExpressionList, unlike the Return statement.

Allowing checks for boolean values also allows checking e.g. value, ok := map[key] map lookups.

When formatting the code, the escape statement should be indented to keep the happy path left-aligned and read like traditional error handling. It should also be followed by a line break.

Example

This is os.File dirFS.join.

Before:

// join returns the path for name in dir.
func (dir dirFS) join(name string) (string, error) {
	if dir == "" {
		return "", errors.New("os: DirFS with empty root")
	}
	if !fs.ValidPath(name) {
		return "", ErrInvalid
	}
	name, err := safefilepath.FromFS(name)
	if err != nil {
		return "", ErrInvalid
	}
	if IsPathSeparator(dir[len(dir)-1]) {
		return string(dir) + name, nil
	}
	return string(dir) + string(PathSeparator) + name, nil
}

After:

// join returns the path for name in dir.
func (dir dirFS) join(name string) (string, error) {
    ok := dir != ""
        \ "", errors.New("os: DirFS with empty root")
    
    ok := fs.ValidPath(name)
        \ "", ErrInvalid
    
    name, err := safefilepath.FromFS(name)
        \ "", ErrInvalid
    
    if IsPathSeparator(dir[len(dir)-1]) {
        return string(dir) + name, nil
    }
    return string(dir) + string(PathSeparator) + name, nil
}

Note that ok and err are not treated as unused values.

Note that even boolean expressions, like fs.ValidPath(name), must be assigned to a boolean value first.


(Some Qs elided as covered above)

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

Harder. Though easier to learn than the more advanced existing techniques for error handling.

How does this proposal differ [from those proposed before]?

  • checks both error and boolean values
  • handles returns, not just the error check
  • less verbose
  • more restricted
  • most importantly, if you squint, the code looks like it has the same shape as existing error handling
  • previous proposals handling returns would automatically return zero values for all but the last value (I feel this isn't worth doing)
  • errors / ok values still have to be explicitly captured (maybe as descriptively named variables) instead of becoming implicit
  • non-error-handling code stays the same without any syntax changes or wrapping

Is this change backward compatible?

AFAIK, Go 1 programs would continue to work - backslash currently only appears in string or rune literals and is not valid, anywhere else.

What is the cost of this proposal? (Every language change has a cost).

Compiler changes, syntax changes, breaking tools, documentation updates, etc.

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

Would benefit from #21182

Does this affect error handling?

Yes (sorry)

Is this about generics?

No

@gopherbot gopherbot added this to the Proposal milestone Dec 10, 2022
@seankhliao seankhliao added LanguageChange v2 A language change or incompatible library change error-handling Language & library change proposals that are about error handling. labels Dec 10, 2022
@seankhliao
Copy link
Member

Duplicate of #21146 just with a different syntax

@seankhliao seankhliao closed this as not planned Won't fix, can't repro, duplicate, stale Dec 10, 2022
@golang golang locked and limited conversation to collaborators Dec 10, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
error-handling Language & library change proposals that are about error handling. FrozenDueToAge LanguageChange Proposal v2 A language change or incompatible library change
Projects
None yet
Development

No branches or pull requests

3 participants