1. 60

  2. 12

    The error draft proposals look great – this is a real need.

    I would like to see Go’s standard types get useful higher-level list operations like Ruby’s Enumerable, map, reduce, filter, etc but I’m not sure Go needs to expose that for all types. Maybe special casing the standard types gets us 80% of the benefit of generics without further complexity to user code.

    1. 8

      Regardless of the proposals themselves I find the openness of the team impressive and laudable.

      1. 7

        Hm the handle thing reminds me of set -o errexit and trap ERR in shell, but it generalizes to bigger programs. That is, it’s not just a global handler; it’s scoped.

        Interesting idea I hadn’t seen before. I might steal that for Oil! :)

        1. 2

          While I somewhat like the error value design the handling seems a bit sad. Two new keywords that only replace a relatively simple if statement seems to go against Go’s principle of keeping the language simple and the number of keywords down. Adding two keywords for the same domain seems a bit much.

          While the general concept looks nice it does not seem like a great fit for the Go language.

          1. 4

            They don’t only replace if statements. They allow you to keep from being repetitious about how you handle errors, and allow for layered error handling. They also don’t complicate control flow too much (the proposed design could be implemented with function-local gotos quite easily). I don’t think it adds an untoward amount of complexity, though it does add some.

            Generics, if anything, add enough complexity where I could see a complaint being raised (though I’m liking the look of the proposal, even if I’m wondering how it’s going to work).

            How would you handle error handling in a backwards compatible way that achieves a similar amount of reduction in boilerplate?

            1. 1

              I think the particular keywords/syntax may still be open to bikeshedding. Especially if/once they open a formal proposal later. (Not sure if this will happen, as it’s the first time they publish “draft designs”, so it’s apparently an experiment with a new formal process.) But I can full well be wrong on this.

            2. 2

              Read briefly through the overview and generics/contracts portions (it will require some more in-depth reading), but it looks pretty good.

              I also appreciate the practical natures of the developers impacting the design - Why not use F«T»

              1. 2

                Great read on the process this artifact is a part of: https://blog.golang.org/toward-go2

                1. 1

                  Three good overviews and great (and reassuring!) indicators of plausible futures.

                  The check handling smells a little of special-casing, much as map is special-cased today to avoid the need for generics; in this case, it’s avoiding LISP-style macros for being able to insert code in the current scope. The problems caused by cpp macros have led to allergy and it’s certainly possible to abuse them to create monstrosities.

                  So at some level, it’s a very “go” approach to not support something “insanely powerful” and instead special-case the perceived most-critical use-cases, map[K]V in Go 1, check in Go 2.

                  1. 1

                    The generics story doesn’t really make sense to me. Let’s say I have a function Fun1 that works on a list of anything that’s equatable. However, I’m writing a new function Fun2, using the old one, that works on a list of anything that’s well-ordered—a more specific condition. How do I specialize Fun1 in my definition of Fun2, when I must provide a concrete type in order to call the function?

                    1. 2

                      I’m not sure I see the problem. it seems straightforward to me:

                      contract Equal(t T) { t == t }
                      contract WellOrdered(t T) {
                          t < t
                      func Fun1(type T Equal)(list []T) { ... }
                      func Fun2(type T WellOrdered) (list []T) { ... Fun1(list) ... }
                      func main() {
                          Fun1([]float64{1.0, 2.0, 3.0})
                      1. 1

                        Where is this behavior described? I was under the impression that you had to hand the function a concrete type.

                        Also, note that my choice of “well-ordered” was arbitrary. However, a more rigorous definition is required, as there must be guarantee of exclusivity, i.e., “for all a and b, exactly one of a < b, a == b, and a > b is true”.

                        func Ident(val T) {
                            return val
                        contract WellOrdered(t T) {
                            len(Filter([3]bool{t < t, t == t, t > t}, Ident)) == 1
                            // sightly inefficient as Go has strict evaluation
                            // also, conditions aren't enforced in contract bodies, only usage

                        I get that it isn’t Go’s goal to provide these kinds of guarantees. But in that case it would be inaccurate to call the contract “WellOrdered”.

                    2. 1

                      Handle/check looks like an excellent way to do error handling in a Go fashion. I hope it lands in Go soon, but we’ll see.

                      1. 2

                        I wouldn’t hold my breath, I think it’s going to be at least a year before the Go2 things start showing up. I think Brad Fitzpatrick estimated 1.15/1.16 (which is 2 years from now).

                      2. 1

                        Just finished reading the error handling and generics drafts. Really great work! Exactly what I hoped for the future of Go.

                        1. 1

                          Looks great! But I don’t understand the rationale behind not allowing genericity on struct methods. Why is that case any more complicated than on normal functions, which they say this proposal will support?

                          1. 3

                            I think it is due to reflection and their “dual-implementation” constraint. In Go you can query any type for number of methods (and iterate over them) using reflect.Type. It would be impossible to implement reflect.Type.Method* family of methods for public type using static generics implementation strategy. When compiling package you have no way to know how many different methods type will have in final executable.

                            1. 1

                              Ah, I see. Seems like an odd concession to make – I would think the utility of generic methods would outweigh the use of reflection. Also, what would have happened if generic functions were also at odds with the reflection API? Would that have torpedoed the whole thing?

                              1. 2

                                Go has a philosophy of only adding orthogonal features.

                                They aren’t willing to have ‘reflection works except on generic methods’, and they aren’t going to break backwards compatibility on reflection.

                                1. 2

                                  Well sure, but now they’ll have ‘generics work except on methods.’ As annoying as it seems I respect the unwillingness to break backwards compatibility, though.

                                2. 1

                                  They want to maintain compatibility with Go1 which means that all the old APIs should still produce correct results.

                            2. -2

                              oh well