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: improve error handling syntax #36390

Closed
cmidt-veasna opened this issue Jan 5, 2020 · 8 comments
Closed

proposal: Go 2: improve error handling syntax #36390

cmidt-veasna opened this issue Jan 5, 2020 · 8 comments
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

@cmidt-veasna
Copy link

cmidt-veasna commented Jan 5, 2020

Salute to everyone here, for the pass few weeks, I've read through all error handling proposal and I know most of them is likely to be rejected at the moment however I would like to put my idea here to help shape up the future if possible.

This proposal aiming to keep old syntax relevant and maintain compatibility.

This proposal utilize 2 new symbols ? and => with an existing symbol ! to improve error handling and various part of the language.

  • Use exclamation mark "!" symbol if we want to panic application
  • Use question mark "?" symbol if we want to return from the function
  • Use "=>" symbol to provide custom error or wrapped error

Acceptant Syntax

  1. Symbol ! and ? is allow to use with the last variable in assign or define statement only.
  2. The last variable must be a bool or an error type where bool would only work with map, channel and casting
    • err? := firstPatient()
    • patient, ok! := dictPatient["boob"]
    • number, ok? := it.(int)
    • patient, ok? := <- patientQueue
  3. Symbol ? is allow to use in function or closure where return signature contain error type however it's not required when using with channel, casting or map
  4. Symbol ! is not allow to use with channel
  5. Both symbol is not allow to use in for loop (Range) and if initial statement.

Syntax pattern: var1, var2(?|!) := val1, val2 [=> error]

Note: To distinguish with a different opertor "!=", it required to have a whitespace after either ? or ! which mean statement err?:= firstPatient() is invalid.

patient, err? := findPatient(name)
// equivalent to
patient, err := findPatient(name)
if err != nil {
    return err
}

id := "mly123"
patient, ok! := dictPatient[id] =>
        fmt.Errorf("Patient id %s not found", id)
// equivalent to
id := "mly123"
patient, ok := dictPatient[id]
if !ok {
    panic(fmt.Errorf("Patient id %s not found", id))
}

Compiler accepted

// channel usage
ch := make(chan bool)
// return as soon as channel close
b, ok? := <- ch
select {
// return as soon as channel close
case b, ok? := <- ch:
}

// suppose findPatient return a patient and an error
// return as soon as err is not nil
patient, err? := findPatient(name)
patient, err? := findPatient(name) => fmt.Errorf("cannot find patient name %s: %w", name, err)

patient, err! := findPatient(name)


// panic as soon as patient name "boob" is not exist in map "dictPatient"
patient, ok! := dictPatient["boob"]
// return as soon as patient name "boob" is not exist
patient, ok? := dictPatient["boob"] => &MyError{ Name: "boob", Message: "not existed" }

name, ok? := iPatient.(string)
// we can use error message generated by compiler instead.
name, ok! := iPatient.(string) => fmt.Errorf("iPatient is not a string")

// only ! can be use outside of function or closure
package foo
var patient, err! = findPatient("some name")

// ! can be use with error type in "init" function
package foo
func init() {
    config, err! := parseConfiguration("path to file")
    number, ok? := s.(int)
    number, ok! := s.(int)
}

Compiler rejected

// channel do not accept ! mark nor custom error or wrapped error
b, ok! := <- ch
b, ok? := <- ch => fmt.Errorf("error message")

// wrong type and need to be use with last variable
patient?, err = findPatient(name)
// allow one usage only
patient?, err! = findPatient(name)

// suppose getPatient return a patient and a bool
// ***
// *** it's possible to make this statement valid if we treat 
// *** this statement the same as type casting statement.
patient, existed? = getPatient(id)

// ? only allow to use within function or closure
package foo
var patient, err? = findPatient("some name")

// ? is not allow to use with error type in init function or function that
// does not have error type as part of return signature
package foo
func init() {
    config, err? := parseConfiguration("path to file")
}

Thought

I've experimented with this syntax and my thought is, the syntax is short however it probably add a bit complexity to the compilation as the transformation or code generation must be done after a full type check is completed.

@gopherbot gopherbot added this to the Proposal milestone Jan 5, 2020
@AndrusGerman
Copy link

Thank you for your proposal I find it very interesting, although I don't like the idea of ​​placing signs after the variables, it can be a bit confusing and too many new concepts that seem complicated to reuse.
Mix the arrow functions with error handling I get a lot of attention.

@proyb6
Copy link

proyb6 commented Jan 6, 2020

How would you handle with more than one type of errors, a single line of code can be challenging?
More difficult is handling 2 or more variables.

results, index, err := ...

@bradfitz bradfitz added error-handling Language & library change proposals that are about error handling. LanguageChange labels Jan 6, 2020
@ianlancetaylor ianlancetaylor changed the title proposal: Improve error handling syntax proposal: Go 2: improve error handling syntax Jan 6, 2020
@ianlancetaylor ianlancetaylor added the v2 A language change or incompatible library change label Jan 6, 2020
@ianlancetaylor
Copy link
Contributor

Personally I don't think we need to make it easier to panic on errors. As I understand this proposal that can be implemented easily enough using the => syntax (=> panic(err)).

The use of ? and => has some similarities to #33074. The use of => has some similarities to #32848 and #33029.

In your example

patient, ok! := dictPatient["boob"] =>
        fmt.Errorf("Patient id %s not found %w", id, err)

the code uses a variable err that is not defined anywhere. Is that a mistake in the example?

If we use ? with a map lookup or channel read or conversion, that can force an immediate return from the function. What values does the function return?

For that matter you don't really spell out what values the function returns if we use ? with a function call. Do you mean this case to work as with the try proposal (#32437)?

@cmidt-veasna
Copy link
Author

@proyb6 this syntax can handle multiple variable just fine as the symbol "?" or "!" can only be used with the last variable in assign or define statement. It similar to other proposal as it enforce the function to have error type as the last value in the return signature.

The syntax does not support the case where function return more than 1 error but technically, we can support such as case by dropping a few rules such as:

  1. allow more than 1 usage
  2. allow both symbol to use with any variable as long as it an error type variable
  3. first rule is no longer applicable

Symbol ! and ? is allow to use with the last variable in assign or define statement only.

However this syntax does not allow explicit return statement, so it would be impossible for compiler to generate or transform the code without restriction. So I don't see this syntax would support such as case.

@cmidt-veasna
Copy link
Author

@ianlancetaylor

  1. Yes, totally that was a mistake. I correct my example in the proposal. There was more example there in the draft but I decide to drop some of it and not check it properly. I'm not sure if I were allow to alter the original proposal, so apologize to that.
  2. When use "?" with map and channel, the function will return default value or nil with an error value as the last value. The error value can be provided explicitly with "=>" or generated by compiler. We can enforce explicit error value as I believe the compiler won't generate a perfect error message.
  3. In contrast to (#32437), the error value did spell out when use ? with a function call.

Just clarify, I did not mention clearly about a statement after "=>". The syntax was inspire by lambda expression and the statement must return an error value if it's a function call or explicit error value. So we cannot call panic function after "=>", only function as such as errors.New("....") is valid.

@ianlancetaylor
Copy link
Contributor

Go doesn't have lambda expressions (other than function literals which is clearly not what you mean). So I think you need to clarify what can follow =>.

@cmidt-veasna
Copy link
Author

@ianlancetaylor there are 2 type that valid after "=>":

  1. A function call which turn a single value and it's an error value. For example: fmt.Errorf()
  2. A value of an error. For example: &MyError{}, suppose MyError implement Error method.

@cmidt-veasna
Copy link
Author

Close this proposal as not many in the community interested in such as syntax change.

@golang golang locked and limited conversation to collaborators Jan 19, 2021
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

6 participants