Great suggestion f := os.Open("filename.ext") else err != nil { log.Fatal(err) }
is much needed syntax improvement vs the current syntax. I would further suggest f ?= os.os.Open("filename.ext") : log.fatal("Cant open filename.ext") But the GO 'custodians' get apoplexy whenever they see any syntax that resembles the C ternary operator. Chill-out 'custodians' !! '?' is just a symbol that can be replaced by some another one On Saturday, February 15, 2020 at 6:06:39 PM UTC-5, teknoslo wrote: > > This is more of a request for comments and not a complete proposal. I will try > to keep this short(ish) and simple. > > Note that the `else` I will write about is not to be confused with the usual > `else` used with `if`. It is an `else` in a slightly different context. > > `else` is basically an `if` with a variable initialized to the last return > value > of a function call from the previous line. > > Note: "from the previous line" is a simplification. Between the function call > and the `else` statement white space and comments are allowed, but nothing > else. > > Another note: "function call" is also a simplification. It can be any > statement > that returns a value. It could be, for example, the "comma ok" idiom used for > testing whether an entry in a map is present. > > A few simple rules: > > - Only the last return value is ever taken, not multiple. > - If there is no return value, `else` is not possible. > - The variable is defined only within the scope of the `else` block. > - The name of the variable can be any valid identifier. > - Braces are mandatory. > > > Code like this: > > f, err := os.Open("filename.ext") > if err != nil{ > log.Fatal(err) > } > > would become: > > f := os.Open("filename.ext") > else err != nil { > log.Fatal(err) > } > > The `err` variable in the example above is automatically initialized to the > last > return value of the function call `os.Open`. The variable could have any valid > variable name and is defined only in the `else` block. > > I like to read the example above with an implicit try before the function > call. > I.e., try opening filename.ext, else if err is not nil... For this reason, I > call this construct else catch. > > A longer example from Error Handling - Problem Overview > <https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md>: > > func CopyFile(src, dst string) error { > r, err := os.Open(src) > if err != nil { > return fmt.Errorf("copy %s %s: %v", src, dst, err) > } > defer r.Close() > > w, err := os.Create(dst) > if err != nil { > return fmt.Errorf("copy %s %s: %v", src, dst, err) > } > > if _, err := io.Copy(w, r); err != nil { > w.Close() > os.Remove(dst) > return fmt.Errorf("copy %s %s: %v", src, dst, err) > } > > if err := w.Close(); err != nil { > os.Remove(dst) > return fmt.Errorf("copy %s %s: %v", src, dst, err) > } > } > > would become: > > func CopyFile(src, dst string) error { > r := os.Open(src) > else err != nil { > return fmt.Errorf("copy %s %s: %v", src, dst, err) > } > defer r.Close() > > w := os.Create(dst) > else err != nil { > return fmt.Errorf("copy %s %s: %v", src, dst, err) > } > > io.Copy(w, r) > else err != nil { > w.Close() > os.Remove(dst) > return fmt.Errorf("copy %s %s: %v", src, dst, err) > } > > w.Close() > else err != nil { > os.Remove(dst) > return fmt.Errorf("copy %s %s: %v", src, dst, err) > } > } > > By using the else catch we declutter the function calls, more specifically > assignments, thus improving readability. Error handling stays familiar, > explicit, and simple. > > And since the variable in else catch is defined only in the `else` block, we > do > not need to re-assign the `err` variable again and again, making the code more > obvious and unambiguous. > > I would like to note that the else catch example is longer, but I think length > should not be equated with readability. > > > > Else catch is not meant to replace the `if err != nil` idiom, but rather > complement it. It would allow for a clear separation of return values we > "care" > about and error handling. Or put another way, it would allow for a clear > separation of a happy and an unhappy path of execution. > > > > What about the error handling blocks? > > We should not try to stash away error handling. Most gophers are already used > to > skipping error handling blocks while reading Go. Using else catch would make > that even easier. IDEs could collapse else catch blocks on command. > > > > Else catch is orthogonal and can be used for anything, not just error > handling. > We just have to remember that it always takes the last (and no more) return > value of a function call from the previous line. > > For example, we can test for existence of a key: > > m := map[string]int{ > "route": 66, > } > i := m["route"] > else !ok { > i = -1 > } > > > > Now, there is a slight problem with current else catch. If it is basically an > `if`, what happens if we use multiple variables in the condition? Which > variable > came from the last return value? > > firstTimeBonus := true > apples := map[string]int{ > "bob": 7, > ... > } > apples["john"] > else !ok && firstTimeBonus { > apples["john"] = 3 > } > > In this case we can probably figure out that variable `ok` is the last return > value of `apples["john"]`. But it is not explicitly stated that `ok` came from > the last return value. What if `ok` variable was already declared and we > unknowingly shadowed it? And how would the compiler know to which variable to > assign the last return value? > > This could be solved by allowing only one variable in the `else` condition. > Then the example above would be invalid, which it should be, because the if > statement would be more appropriate. Also if there was only one variable > allowed > in the condition, there would be no confusion as to where the variable came > from. > > > > I believe something like else catch could be beneficial to Go, mainly > improving > readability. But there are a few problems to consider. > > `else` would have different semantics depending on the context. This should > not > be a problem for people, but it could be for the compiler and other tools. > > Go would have a new, not widely known construct. How much would it impact the > learning curve of the language? > > > > This is just an idea and I am interested in what you think. > > - Would else catch be useful to you? > - Could it be simpler? Maybe a keyword or a built-in that could take the > last return value and we could use if with a short statement instead of > `else`. > - Do you see a problem with it? Does it feel too much like magic? > - Is it trying to solve a problem you even have? > - Do the pros outweigh the cons? > > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/5f7ba765-ac52-418f-96f5-f715e16baec0%40googlegroups.com.