15 ms·
Next steps toward Go 2
- AtroxDev 7y agoLooks like they really plan to move forward with the `try` function... I'm personally not a fan of it, I hope they listen to the feedback they received on the GitHub Issue and not just push it through like the error inspection [0]. [0]: https://github.com/golang/go/issues/29934#issuecomment-489682919 https://github.com/golang/go/issues/29934#issuecomment-48968...
- kenhwang 7y agoIt looks like instead of making a better error handling system, they just made it easier to not type `if err != nil` everywhere. Then there's all that handler stuff that looks very much like Java's `try ... catch` in reverse order. Pretty underwhelming for what's supposed to be a modern language.
- tjholowaychuk 7y agoWhich can be solved with a snippet bound to `e`.
- eikenberry 7y agoThe problem `try` is addressing isn't typing the boilerplate, it is that it clutters up the code making it harder to read.
- dnautics 7y agoit's not as if `if err != nil` doesn't clutter up the code!
- eikenberry 7y agoSorry, I said that poorly. I mean that the problem `try` is fixing is that all the `if err != nil ..` clutters up the code and they are introducing `try` to clean that up.
- zellyn 7y agoIs Go “supposed to be a modern language”? I'm not sure even the language designers would agree with that characterization.
- Thaxll 7y agoWhat is a modern language anyway?
- BlueTemplar 7y agoWell, for one, it handles text as being UTF-8 by default, even at the lowest level (and in no case assumes that byte = character !)
- pjmlp 7y agoOne that takes into account features that have made into the mainstream during the last 20 years, instead of feeling like an Algol-68 subset.
- Thaxll 7y agoI don't care about the features in the last 20 years if I'm able to do my job efficiently which Go as a language provides. Never wonder why those great academics languages with a ton of features are not adopted?
- jerf 7y ago"Then there's all that handler stuff that looks very much like Java's `try ... catch` in reverse order." The key characteristic of Go's error handling is that you have to handle errors in the scope in which they occur, vs. exception handing which is designed around throwing errors up the stack until something finally handles it, often quite distant from the point of the error and lacking context. "try" just re-spells that. It isn't a step towards exception handling; it's exactly as "exception-handle-y" as if err != nil { return err } already is, whatever value you may consider that to be. Part of the goal is to make correct handling where you actually do something with the error that much easier, instead of having to do something essentially unrefactorable for every error, through a combination of allowing error handling to be factorable in this new scheme, and some other changes to errors to add more structure by convention to create official ways of composing them together and examining these composed errors in sensible ways.
- pacala 7y agoThe confusing part is the underlying assumption that there exists a way to "handle" errors, understood as a way to workaround the error and somehow continue execution. This is most of the times futile, there is nothing to "handle", other than abort the execution and report the condition. For example, consider a bug that causes a data structure invariant to be violated. The correct "handling" of the situation is to fix the bug and rerun the code, not add layers and layers of error "handling" code ahead of time.
- tptacek 7y agoThat's literally the case that "panic" is there to handle.
- pacala 7y agoThe example was a worst case example. There are weaker versions thereof, for example the familiar: def handle(request): try: return Response(200, process(request)) except UserError as ex: return Response(400, ex.message) except InternalError as ex: return Response(500) The principle stays the same, there is not much to "handle" and no option to recover without external help, either by providing a well-formed request for 400 errors or by providing well-behaving code for 500 errors.
- pjmlp 7y agoIt still needs to catch up with CLU, released on 1973.
- AnimalMuppet 7y agoIn what way?
- pjmlp 7y agoGenerics to start with.
- staticassertion 7y agoGo is new, not modern.
- blaisio 7y agoThey aren't really moving forward with it, they are implementing an experimental version of it so people can try it in real code. Many things are added temporarily when a new version is in development. Eg. the error handling changes they mentioned were implemented, and then later most of it was removed before the feature freeze. So there's still plenty of time to stop the proposal.
- butterisgood 7y agoIt looks like a monad for Either or Result to me, and I think it's an improvement. The good news is if you hate it you don't have to use it, but since it'll be in the language (if they take it) you'll have to know how it works. I don't think this is worse than things like "for:else" in Python.
- jzoch 7y agoInteresting to go with Monad "by convention". They wont build in an explicit type but rather utilize convention (placing err as the last param and giving it a certain shape) to replicate that behavior
- butterisgood 7y agoYep. Being practical and simple with easy to remember rules seems to be more of a value to the designers than to build a language with “features from Ivory Towers” (in the Haskell sense anyway). The designers hope to give Go users “what’s needed to write good code” without having the learning curve of other languages. I suspect this balance is hard to strike at times and I rather admire their efforts.
- the_duke 7y agoThis looks pretty much exactly like the old try!(expr) macro in Rust, which has since been replaced with the postfix `?` operator. One crucial difference is that the proposal uses a named `err` return value that can be manipulated in defer. This is supposed to allow cleanup and wrapping of the error type. Rust solves wrapping is by allowing auto-conversion between error types (if they implement it). My first intuition is that it would be an improvement over omni-present `if err != nil {}`, but it feels somewhat awkward and tacked on. Especially the mutable `err` return value. Of course there also was a reason why try! was replaced with `?`: awkward nesting and chaining. Go would have the same problem.
- zeeboo 7y agoTo be clear, you can name the return value whatever you want. People just typically name their error values `err`. Also, the mechanisms to mess with named return values in defer already exist: https://play.golang.org/p/7nFyiuAa3Ra https://play.golang.org/p/7nFyiuAa3Ra
- the_duke 7y agoJust to clarify, I was aware that named returns already exist in Go. My main point is that this somewhat weird pattern is encouraged by the proposal since no other wrapping mechanism exists. And IMO wrapping is really essential for debuggable code.
- zeeboo 7y agoI totally agree that good error wrapping is essential. In fact, I've been using this exact system for wrapping my errors for years, and it's been great (https://godoc.org/github.com/zeebo/errs#WrapP https://godoc.org/github.com/zeebo/errs#WrapP). I suspect it's only "somewhat weird" due to lack of familiarity, and that adding an additional mechanism to wrap errors when one already exists is not in the spirit of a language built from small orthogonal components.
- the_duke 7y ago
- saturn_vk 7y agoWhat the hell happened to the catch/handle draft proposal. That looked a lot more useful
- ngrilly 7y agoIt was abandoned in favor of the try proposal, mostly because the handle statement was coming partly redundant with the defer statement, but with subtle differences.
- allochthon 7y agoThe statement looks like an assignment, and unless I was really used to seeing it, I would never expect an implicit return.
- atombender 7y agoMy main beef with this and other proposals is that they don't clear up a fundamental flaw in Go: Multi-value returns with errors as a poor man's sum type. Most functions in Go have a contract that the return values are disjoint, or mutually exclusive — they either return a valid value or an error: s, err := getString() if err != nil { // It returned an error, but "s" is of no use } // s is valid This pattern so ingrained that there's hardly a single Go doc comments on the planet that says "returns value or error". The same goes for the "v, ok := ..." pattern. But this is just a pattern and not universally true. A commonly misunderstood contract is that of the `Read` method of `io.Reader`, which says that when `io.EOF` is returned, the returned count must be honoured. This is an outlier, but because the convention of disjointness is so widely adopted, many developers make this assumption (it's trivial to find repos in the wild [1] that make this mistake), and so this is, in my opinion, bad API design. (As an aside, it's also true that multi-value returns beyond two values almost always become cumbersome and impractical, especially if said values are _also_ mutually exclusive. Structs, having named fields, are almost always better than > 2 return values.) This kind of careless wart is typical of Go, just like other surprising edge cases like nil channels (or indeed nil anything). I would much rather see a serious stab made at supporting real sum types, or at least mutually exclusive return values. For example, I could easily see this as being a practical syntax: func Get() Result | error { ... } This union syntax showed up in the Ceylon language, and it's a neat pattern for a conservative language that doesn't want to venture into full-blown GADTs. Such a syntax would be a much better match for a try() function, since there's no longer any doubt about the flow of data — there's never a result returned with an error, it's always either a result or an error: result := try(Get()) or simply support existing mechanisms for checking: if err, ok := Get().(error); ok { ... } if result, ok := Get().(Result); ok { ... } switch t := Get().(type) { case Result: // ... case error: // ... } I'd love to see a `case` syntax that allows real local variable names: switch Get().(type) { case result := Result: log.Printf("got %d results", len(result.Items)) case err := error: log.Fatal(err) } And of course, you could have more than two values: switch Get().(type) { case ParentNode: // ... case ChildNode: // ... case error: // ... } The Go compiler can be strict here and require that every branch be satisfied or that there's a default fallback, although some might prefer that to be a "go vet" check. A full-blown sum type syntax would be awesome, though I know it's been discussed before, and been shot down, partly for performance reasons. Personally, I think it's solveable. I'd love to be able to do things like: type Expression Plus | Minus | Integer type Plus struct { L, R Expression } type Minus struct { L, R Expression } type Integer struct { V int } [1] https://github.com/search?q=%22read%28%22+%22if+err+io.EOF%22&type=Code&l=Go https://github.com/search?q=%22read%28%22+%22if+err+io.EOF%2...
- yingw787 7y agoI'm not familiar with golang, but I did read about a concern with variable mutability and race conditions when communicating across channels: https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/#mutability-is-hardcoded-in-the-language https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/#muta... """ As we saw above there is no way in Go to have immutable data structures. This means that once we send a pointer on a channel, it's game over: we share mutable data between concurrent processes. Of course a channel of structures (and not pointers) copies the values sent on the channel, but as we saw above, this doesn't deep-copy references, including slices and maps, which are intrinsically mutable. Same goes with struct fields of an interface type: they are pointers, and any mutation method defined by the interface is an open door to race conditions. So although channels apparently make concurrent programming easy, they don't prevent race conditions on shared data. And the intrinsic mutability of slices and maps makes them even more likely to happen. """ Is this still a concern, and if it is, would it be addressed in Go 2?
- blaisio 7y agoThat isn't really the sort of thing Golang is trying to address, at least, not directly. Go is very unlikely to add immutable data structures at this point. And Go is not built to prevent race conditions. There is a race detector that can detect many race conditions in running programs, but nothing in the type system.
- yingw787 7y agoIMHO type systems are pretty much impossible to change after the fact (see: Python's `str` type and the whole 2/3 migration fiasco), which is why I thought to bring it up since it's a major version change. I think a lack of support for efficient immutable types gets in the way of `golang` being a concurrency-first language, if the language endorses CSP with native support for goroutines and channels in the first place. How you can write simple, reliable, and efficient user code (https://golang.org https://golang.org) if using your favored concurrency model results in race conditions?
- apta 7y ago
- tjholowaychuk 7y agoI'd rather have nice command output, that could use a lot more love than this try() stuff, and maybe ditching the weird go.mod format it doesn't really add value—if anything it hurts because you can't manipulate those files with regular codecs. When it comes to error context it would be nice to facilitate structured logging, rather than arbitrarily formatted strings.
- zerr 7y agoWhy I would switch from Perl 6?
- ryuukk_ 7y agonobody asks you to switch it is always nice to try new stuff, it makes u aware of current trends, and ready to move in case of job opportunity
- butterisgood 7y agoHmmm so Go is getting monadic behaviors with "try" to hide error handling issues with examining every single one with "if". I think this is a rather large improvement to error handling. I need to read more about how it works with "go" and "defer" (it's all in there).
- millstone 7y agoIt looks like a big improvement but it's definitely not monadic. It's a hidden return.
- butterisgood 7y agoIf you sequence (>>=) a series of Maybe's in Haskell you have hidden returns as well. Since we're talking about the application of "bind" you could think of the "invisible semicolon" in Go as the same kind of bind between "try" statements in Go, and get very similar behaviors - conceptually. At least, that's how I think I've understood "try" to work. (pseudocode... ) f := try(open(...)) num_bytes := try(write_some_bytes(f, ...)) I hope my function bailed out early at "f := try(open(...))" because the line "num_bytes..." literally makes no sense at all if f hasn't been even declared "f :=" vs "f =". In the end, if I don't like it, I don't have to use it, but I still have to understand it if it's in the language and I'm reading other people's code.
- sagichmal 7y agoAn improvement, really? It seems to me that it reinforces a bad pattern (returning an error directly without annotation) and will make return analysis of functions in code review a lot harder. For what, to reduce typing? Doesn't strike me as a good tradeoff, and certainly feels at odds with Go's principles so far.
- butterisgood 7y agoI'm not sure I'm getting what you're saying. Try can only be used in functions that use error types as the last returned type. The compiler should be rejecting uses outside of that. So why is this any harder than thinking about "go" or "defer"?
- _hardwaregeek 7y agoSo wait, they're introducing magic "function" that has a variable number of generic return arguments? Huh. In Rust the try! macro makes sense because A. there's a precedence of macros and B. there's a precedence of generics. But in a language with neither macros nor generics, this just seems odd. Kinda like making the Justice League movie without any of the requisite standalone movies.
- kyrra 7y agopanic() and recover() are a built-in function, so there is already some precedent for doing this.
- jerf 7y agoAlso append(), copy(), new(), etc. Technically ("well, acksually"), Go doesn't "lack generics". It lacks user-defined generics. The language implementation has several generics in it, you just can't add your own. So if you hear "Go doesn't have generics" that can give you a slightly incorrect impression about the language itself, but of course what people do generally mean is that it lacks user-defined generics and that that is bad, so there's still certainly a valid criticism there. It just may not quite be what you thought it was.
- aikah 7y ago> Technically ("well, acksually"), Go doesn't "lack generics". Yes it does, generics are types. You bet all these append(T[A],A)T[A] tricks are hard-coded in the compiler in an adhoc fashion, and not part of Go's type system.
- AnimalMuppet 7y agoI don't think I'd bet that way...
- bsaul 7y agoI’ve heard this « go has generic it just doesn’t let you access it » argument so many times, it would be really good if someone could actually point to the piece of compiler code that define those generic capabilities. My guess is they don’t have anything usable by the end user any way, otherwise they wouldn’t spend so much time thinking about a design for go 2. It probably means whatever is in the compiler isn’t that elegant, nor reusable.
- azhenley 7y agoGo 1.14 will include the following "smaller" proposals: - A built-in Go error check function, “try”. - Allow embedding overlapping interfaces. - Diagnose string(int) conversion in go vet. - Adopt crypto principles.
- conroy 7y agoHere's a short example comparing existing error handling, the check proposal, and the experimental try proposal https://gist.github.com/kyleconroy/e48c83425349f2d3954d4e76471ff3f5 https://gist.github.com/kyleconroy/e48c83425349f2d3954d4e764...
- apta 7y agoFunny how it's also wrong. handle err { w.Close() os.Remove(dst) // (only if a check fails) } the error returned from w.Close() is not handled.
- zeeboo 7y agoThat `Close` call only happens in the case that an error happened during either copying or closing. The point of checking errors on `Close` is so that you catch problems during flushing of any buffered writes. In this case, the `Close` is not to ensure the data is flushed, but to ensure that the file descriptor is released in error scenarios, justifying that the error need not be checked. On the other hand, w := try(s.Create(dst)) try(io.Copy(w, r)) try(w.Close()) return nil this code has the problem where if there were an error in the `Copy`, the file descriptor would be leaked. So, yes, one of the examples is wrong.
- paulkon 7y agoLOC reduction of 10% with check/handle statements and 20% with try()/defer along with somewhat reduced clarity of what will happen on error. I'm not a fan of the verbosity at present either, but seems like the check/handle syntax is less direct and the try()/defer func syntax is less flexible.
- kodablah 7y agoWhy is there a defer in the "try" example? To just show wrapping even though the "existing" one doesn't wrap? Also, the "try" example doesn't defer-close "w" in case copy fails. Seems that they aren't the same example.
- ixwt 7y ago
- tschellenbach 7y agoGo so far has always prioritized the things I care most about: - performance & high concurrency - a small language feature set so I can hire & train awesome programmers with a different background - practical solutions, with a focus on getting things done I feel confident that with Go 2 they will continue to go down this road. The `try` syntax looks kinda confusing with the implicit return. On the other hand, nothing too crazy.
- stcredzero 7y agoI have to say, as time goes on, the more I like contracts. Go concrete types can satisfy go Interfaces. Go concrete types and Interfaces can satisfy contracts. I would actually feel better if the proposed generics were a little less powerful. Composing generics can get ugly. This could be countered by community norms, however.
- unscaled 7y agoThe "Go is performant" gospel seems to be coming from people who came from Python and JavaScript to Go. I don't think Go prioritizes performance more than most other popular statically-typed language Java[1], Haskell or Swift (or less popular ones like Ocaml). And Go obviously doesn't prioritize performance as much as C++ or Rust. Case in point is with very same error handling proposal discussed here. You're going to have to pay a performance price for using a handler since the Go compiler not only avoids inlining defer blocks (if I understand correctly), but even allocates dynamic memory for each block. Meanwhile, equivalent RAII in C++ has no overhead over manual code. Yes, the Go compiler team is now working on working on fixing this issue, but defer is not a new language construct and they should have started fixing that long ago, considered how often it's being used. What's worse, they still didn't make it a stated goal to eliminate the overhead of using defer completely, but only talk about reducing overhead in common cases. This approach makes me sad, because Go does have the engineering power and stated design goals to be more serious about performance. Yeah, I feel confident Go will keep improving, but just the same as Java does (without the same hype). [1] Although until recently they did have radically different choices about which kind of performance to optimize, e.g. Java went up with throughput (Throughput-optimized, JIT tricks for fastest execution after warmup), while Go went for low worst-case latency and faster startup time.
- ameixaseca 7y agoThe proposal for `try` made my eyes bleed. It combines a number of features from metaprogramming and generic types but in a hard-coded manner and doing a number of assumptions about functions signatures, etc. I guess that's the idea of Go, to restrict the language power by giving just the functionality the designers think the programmer should have, but to not allow anything too fancy. However, if you put some thought to it, it really sounds silly when you know that this will only limit your ability to actually use the language and not really "simplify" anything, since it only adds to the general cognitive load of the language - in this case, one more exceptional case.
- swiley 7y agoHaving read a decent amount of go code I'm really quite convinced the restrictions are beneficial. Personally I find it easier to read than just about any other language.
- qtplatypus 7y agoCan I politely suggest that the fact that you have read a decent amount of go code is directly related to the fact that you find it easy to read? I’ve read and programmed in many languages and apart from some outlayers the more I’ve read that language the more readable it is.
- nullwasamistake 7y agoI'm of the opinion that making a language too simple results in the worst code. Sure it's easier to learn, but you end up with crap when you're trying to do something complex and there's no good way to represent it. BASIC and VBA are extreme examples but they support my opinion :). Go has a ton of shortcomings. No good popular package management system with versioning, hacky JSON parsing, no generics. Rust is becoming a good counter example, they listen to the community and pump out features that everyone is excited about. Like async recently. Google has a habit of ignoring the community. Angular is a great example. I've been following a feature request for close to 3 years that has over 100 comments asking for it. A simple thing too. Many people have opened PR's and begged for it in vein, even as recent as a week ago.
- baby 7y agoMy biggest concern is how they will implement generics and if it will lead to generics being abused and making codebases worse. FWIW, eventhough Go is less expressive than certain languages, it wins in clarity and readability.
- pjmlp 7y agoYep, quite readable. https://fosdem.org/2019/schedule/event/kubernetesclusterfuck/ https://fosdem.org/2019/schedule/event/kubernetesclusterfuck...
- aikah 7y ago> Go is less expressive than certain languages, it wins in clarity and readability. Not having to deal with inheritance is clear and readable enough. Generics wouldn't make the language less clear and readable. Furthermore, it's not an ALL or NOTHING case. Generics could be restricted to generic functions for instance, not types per say. Go already makes a lot of trade-offs, i don't see why this trade-off would be controversial. But to me generics are the least of Go's problems. A lot could be done to make the language easier to use, like co-variant interfaces for instance, a tons of other stuff could be added in a relative "invisible" fashion that would not impact the language's syntax.
- weego 7y agoI dislike the try implementation, one of Go's strengths for me after working with Scala is the way it promotes error handling to a first class citizen in writing code, this feels like its heading towards pushing it back to an afterthought as tends to be the case with monadic operations
- kbd 7y agoIt's just syntactic-sugar. From the proposal (https://github.com/golang/go/issues/32437 https://github.com/golang/go/issues/32437): f, err := os.Open(filename) if err != nil { return …, err } is simplified to: f := try(os.Open(filename)) > I dislike the try implementation What would you suggest instead?
- politician 7y agoIt doesn't matter what we suggest. There are 100s of suggestions on that Git ticket, and it's a fait accompli masquerading as an RFC. Down-vote if you want, but Go modules package management was handled in the same way. It's not without precedent.
- CamouflagedKiwi 7y agoAnd hopefully try will have the same outcome, i.e. something significantly better than existed in the ecosystem before. Basically I agree that the process for modules may not have been ideal, but the outcome was pretty good. We could do a lot worse than getting the same again.
- losingthefight 7y agoI mean, everyone is entitled to their own opinion, but I actually liked dep and never had a problem with it. With Go modules, it has been a massive problem converting our microservices over to Go modules, especially because some dependencies like Resty caused a lot of headaches and I lost several man weeks going through the process. Dep worked and modules doesn't seem to have brought us any real benefit, but again, my use case is my own and perhaps for you module was a better experience.
- invasionofsmall 7y agoI have been using for a year. It's a glorified bash script. Let's hope it will become something more similar to a programming language.
- arendtio 7y agoDoes someone know if there is a good reason why try uses parenthesis? I mean, wouldn't it look even cleaner without them? f := try os.Open(filename)
- tptacek 7y agoOne possible reason is that funcall semantics will probably change (Go 2 is likely to have generics), and so simple funcalls keep the language orthogonal; new operators are forever.
- krferriter 7y ago> Go 2 is likely to have generics Big if true. It's one main complication keeping me from adopting Go for more things.
- tptacek 7y agoIt's mentioned in the post we're commenting on.
- ploxiln 7y agoThey did not want to create a new "keyword" that would possibly conflict with some existing variable name. So try() is a built-in function, similar to len(), and if you already have a variable named "try" (or "len") then it shadows the built-in (takes priority in that scope).
- undecidabot 7y agoIt's mentioned in the design doc under "Properties of the proposed design": https://go.googlesource.com/proposal/+/master/design/32437-try-builtin.md#properties-of-the-proposed-design https://go.googlesource.com/proposal/+/master/design/32437-t...
- icholy 7y agoArgh ... check/handle is so much better
- cpeterso 7y agoAn interesting Go2 proposal that didn't make the cut is "change int to be arbitrary precision", i.e. make the builtin int type a bigint to avoid integer overflow and conversion bugs: https://github.com/golang/go/issues/19623 https://github.com/golang/go/issues/19623
- ryuukk_ 7y agoAre there plans to improve C interop ? i mostly care about opengl
- imetatroll 7y agoI use golang quite a lot. The way this should be used is being ignored by all of the examples I have seen so far. When an error occurs people should be doing what they already should be doing. That is to say, immediately log/wrap the error with context (file + line information) so that the error can be immediately found. Then if there are any callers of this failing function, they are the ones who should use try. func A() error { if err := do(); err != nil { log(err) return err } return nil } func B() error { try(A()) return nil } To be honest though, I don't personally like this proposal.
- tracker1 7y ago(User Defined) Generics support. edit: clarify.
- rdm_blackhole 7y agoI am not a big fan of "magic" happening behind the scenes. I understand that the current error handling is a bit too verbose but at least it makes the code readable. I am not sure if this is really the best way to fix this issue TBH.
- smitty1e 7y agoI sure am glad that no one did a "Go 2 considered harmful" gag.
- alecmg 7y agocame here just to make that joke :(
- infogulch 7y agoSome don't like the magic, and some are worried about losing annotated errors. If you can tolerate just a little bit more magic, you can solve the error annotation problem: f := try(os.Open(filename), "opening config file") Place the context string just after the last, error parameter. That is, make try also also allow the pattern: try( a1, a2, ..., error, string ). Bonus points if the last arg could be a func(error) error, that way you can pass a local closure to wrap the error in a scoped context and also avoid pre-calculating an expensive error string even in the non-error case. It's just a language feature, you can make up any interface you want. We're already on the magic train, might as well ride it.
- agnivade 7y agoAll of these have already been discussed in the GH issue. It is all being taken into consideration. Check out https://swtch.com/try.html https://swtch.com/try.html for a thematic grouping of the issue.
- infogulch 7y agoThat's a heck of a reference, thanks for sharing! And there it is https://swtch.com/try.html#args https://swtch.com/try.html#args under Alternative: Add arguments to try. Seems I have some reading to do.
- courtf 7y agoThere's a lot of talk in these comments about the new 'try' built-in and error handling in general which gives me the sense that errors are more controversial and in need of criticism than the proposed generics design. I see it the other way around. I'm in favor of generics for Go, but I can't support this design and I think it will have a negative effect on library stability. Rather than narrowing the scope of contracts to remain mostly orthogonal to existing features, they have it totally open-ended. They clearly didn't want to put too much restraint on what can be stipulated by a contract, and consequently it just feels like a solution looking for a problem (or like they didn't want to to make any hard decisions for which they might be critcized). With contracts as they are, they are incredibly powerful and stomp all over the type system and interfaces in terms of their practical utility. This is not orthogonal design, or really any sort of design, it's a blank page. They feel like a complete abdication of the designers' responsibility to make Go a simple language that tries to only pull in minimal features while reducing overlap. It's context.Values again but far worse. Please stop trying to make everyone happy, it's impossible (and I realize the irony here). I liked generics when they were going to be super strict (and consequently super simple from the user's perspective), no upper or lower bounds on the type, just essentially a glorified gogenerate. This feels like you all are trying to answer to the critics rather than to the code.
- remon 7y agoNot a huge fan of the try built-in spec as proposed but I struggle to understand the reasoning behind people arguing that the current error checking/handling paradigm "at least makes the code readable/understandable". It doesn't. The whole issue with golang error checking boilerplate is that your brain will start seeing it as noise, which may obfuscate issues within the code. This is especially true for code you have not worked on yourself.
- JulianMorrison 7y agoYeah, and this new change doesn't alter how explicit the code is. The new "try" just means "return error from here without setting the LHS if the RHS returns an error". It is the standard boilerplate captured. When this is in common use, it will greatly improve the visibility of non boilerplate error handling.
- zupa-hu 7y agoAh, contracts seem ugly. If only operators could be method names we would not need contracts, we could just define generic types like an interfaces: type T generic { +(T) (T) ==(T) (bool) } Donno where to suggest this.