I do not think ternary belongs in Go. As Kevin and disroot noted below, I also prefer cleaner syntax even if it is more verbose. Its usage would also overlap with with the if statement, so which would you use when? I really appreciate the opinionated go fmt (and gofumpt) so we have do not to bother with such choices.
Dne nedelja, 16. februar 2020 19.28.00 UTC+1 je oseba lgo...@gmail.com napisala: > > 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/ec62d749-fb42-4f59-a6a4-e41265855fb1%40googlegroups.com.