6 ms·
Too bad the try proposal didn't make it. It was a good improvement on the great but too verbose error management system.
by sacado2 7y ago
Too bad the try proposal didn't make it. It was a good improvement on the great but too verbose error management system.
- sosodev 7y agoI think the common argument against try is that it was a macro in a language without macros. That’s pretty confusing behavior and you can’t expect anyone to understand that without reading the specification.
- mseepgood 7y agoYou mean a builtin, like panic().
- morelisp 7y agoPanic is a special form (a “keyword”); it is implemented by the compiler and not implementable within the language itself. Try was defined as a syntax transform. Calling it a macro seems reasonable.
- mseepgood 7y agopanic is a built-in and so was try: https://golang.org/pkg/builtin/#panic https://golang.org/pkg/builtin/#panic "The panic built-in function stops normal execution of the current goroutine. [...]" It's not among the list of keywords: https://golang.org/ref/spec#Keywords https://golang.org/ref/spec#Keywords "Q: Why is try a built-in? A: By making try a built-in, there is no need for a new keyword or operator in Go. Introducing a new keyword is not a backward-compatible language change because the keyword may conflict with identifiers in existing programs. Introducing a new operator requires new syntax, and the choice of a suitable operator, which we would like to avoid. Using ordinary function call syntax has also advantages as explained in the section on Properties of the proposed design. And try can not be an ordinary function, because the number and types of its results depend on its input" https://github.com/golang/proposal/blob/master/design/32437-try-builtin.md https://github.com/golang/proposal/blob/master/design/32437-...
- morelisp 7y agoThe Go documentation refers to panic as a "built-in function" but this is a white lie in the documentation. It is not a function; this will not compile: var _ func(interface{}) = panic It is a special form that happens to be spelled like a function. The distinction the Go documentation is drawing between "keyword" and "built-in" is largely about Go's internal parsing mechanism (i.e. can you have a variable named try, or panic, which you can). When Go says "keyword" they mean what would be more formally a "reserved word". Hence my preference for "special form", but this is not well-known outside the Lisp community.
- edflsafoiewq 7y agotry doesn't seem like it would have actually been able to replace that many error-checks in practice, since many of them do something other than just blind returning.
- deleted 7y ago[deleted]
- pleasenotry 7y agoThis proposal by deanveloper is the best I've seen against try. (apologies for indentation change - not sure why hn can't preserve it) https://github.com/golang/go/issues/32437#issuecomment-498932961 https://github.com/golang/go/issues/32437#issuecomment-49893... ________________________________________________________________ I actually really like this proposal. However, I do have one criticism. The exit point of functions in Go have always been marked by a return. Panics are also exit points, however those are catastrophic errors that are typically not meant to ever be encountered. Making an exit point of a function that isn't a return, and is meant to be commonplace, may lead to much less readable code. I had heard about this in a talk and it is hard to unsee the beauty of how this code is structured: // 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) } } // This code may look like a big mess, and was meant to by the error handling draft, but let's compare it to the same thing with try. // func CopyFile(src, dst string) error { defer func() { err = fmt.Errorf("copy %s %s: %v", src, dst, err) }() r, err := try(os.Open(src)) defer r.Close() w, err := try(os.Create(dst)) defer w.Close() defer os.Remove(dst) try(io.Copy(w, r)) try(w.Close()) return nil } // You may look at this at first glance and think it looks better, because there is a lot less repeated code. However, it was very easy to spot all of the spots that the function returned in the first example. They were all indented and started with return, followed by a space. This is because of the fact that all conditional returns must be inside of conditional blocks, thereby being indented by gofmt standards. return is also, as previously stated, the only way to leave a function without saying that a catastrophic error occurred. In the second example, there is only a single return, so it looks like the only thing that the function ever should return is nil. The last two try calls are easy to see, but the first two are a bit harder, and would be even harder if they were nested somewhere, ie something like proc := try(os.FindProcess(try(strconv.Atoi(os.Args[1])))). Returning from a function has seemed to have been a "sacred" thing to do, which is why I personally think that all exit points of a function should be marked by return.