1. 22
  1.  

  2. 25

    I feel uneasy about this talk. Sure, it contains true statements that I can fully endorse. But there is this undertone in it. It feels a bit like they would advice cooks to do away with knifes in the kitchen, because you can cut herbs with scissors and onions with a grater and switch over to buying ground meat, because knifes can be dangerous and you need experience to handle them. What a contrast is Rich Hickey’s talk Simple made Easy in comparison http://www.infoq.com/presentations/Simple-Made-Easy

    It seems like they are trying to solve a social / educational problem with code quality by leaving out features from the language. My feeling is, that in the end the lack of such features will be compensated in code bases with boilerplate code, leaving users with complex and large code bases.

    The only way to reduce complexity imho is careful design, design review and culture that values thought over commit frequency.

    1. 11

      I am not a Go fan by any stretch, so watching this video was an odd experience. I found myself agreeing with many of Pike’s statements but then not understanding how he wound up at Go. For example, I didn’t understand how the Go team got to interfaces and run-time subtyping. Objects are complicated, they combine many concepts (data, compute, identity, time, dispatching). Parametric polymorphism + structs seem to get you many of the benefits without the cost, and is more type safe (none of that interface{} stuff), and is simpler. The talk of the great simplicity of Go is not borne out, IMO.

      1. 7

        but then not understanding how he wound up at Go

        exactly my feeling

        1. 3

          run-time subtyping

          That’s wrong. Interface sub-typing is structural and is checked by the compiler.

          Parametric polymorphism + structs seem to get you many of the benefits without the cost

          Except there are costs depending on how your implement it. Just because the costs aren’t important to you doesn’t mean they don’t exist.

          The talk of the great simplicity of Go is not borne out, IMO.

          It is borne out in my experience of using the language and watching others pick up, learn and use the language effectively.

          1. 6

            That’s wrong. Interface sub-typing is structural and is checked by the compiler.

            Yes, the types are checked, but the dispatching happens at run-time and it is the only form of polymorphism in the language, which is what I was trying to express.

            My point is not if Go is simple or not, but that in listening to the talk I, personally, felt a disconnection between what the speaker said and the language he got out of it. YMMV, I’ve been on lobste.rs long enough to know that you have a different opinion and experience than me.

            Except there are costs depending on how your implement it. Just because the costs aren’t important to you doesn’t mean they don’t exist.

            I’m not entirely sure what you mean here, since the types exist only at compiletime the implementation is a type checker (which the OCaml type checker can do on-par with Go given that it has a much more sophisticated type system) and it compiles down to the same code that would exist now, more or less. So your counter here doesn’t really have any merit given the technical aspects of implementing what I said. It could have non-technical costs, but you seem to be referring to implementation here if I read you correctly.

            1. 1

              I’m not entirely sure what you mean here, since the types exist only at compiletime the implementation is a type checker (which the OCaml type checker can do on-par with Go given that it has a much more sophisticated type system) and it compiles down to the same code that would exist now, more or less. So your counter here doesn’t really have any merit given the technical aspects of implementing what I said. It could have non-technical costs, but you seem to be referring to implementation here if I read you correctly.

              If your implementation strategy is monomorphization, then you’re almost certainly going to pay for it with compile times. If Go had parametric polymorphism, and folks started using that in lieu of interfaces in some cases, then you’ll end up with more work for the compiler to do.

              Aside from the compile time cost, you’ve now also got to deal with language complexity, implementation complexity and code complexity.

              My point is not that one is better than the other, my point is that various approaches to polymorphism come with trade offs, and waving them away is without merit.

              1. 2

                If your implementation strategy is monomorphization, then you’re almost certainly going to pay for it with compile times. If Go had parametric polymorphism, and folks started using that in lieu of interfaces in some cases, then you’ll end up with more work for the compiler to do.

                It doesn’t have to be, it can be a pure compile-time verification and compile down to interface{}.

                Aside from the compile time cost, you’ve now also got to deal with language complexity, implementation complexity and code complexity.

                I believe just parametric polymorphism would be simpler in both implementation and usage than interface that are structurally typed. The dispatch table alone requires a fair amount of work relative to this. But YMMV.

                My point is not that one is better than the other, my point is that various approaches to polymorphism come with trade offs, and waving them away is without merit.

                I’m not, though. My claim was that parametric polymophism + structs lets you do the existing structural typing, and you get type safety. I’m claiming that you get more for less.

                1. 1

                  It doesn’t have to be, it can be a pure compile-time verification and compile down to interface{}.

                  … and now you pay for it with slower run time performance because everything is boxed. Adding a convenient way to write slow code will dramatically change how code in the language is written and its performance characteristics. It’s a huge trade off.

                  I believe just parametric polymorphism would be simpler in both implementation and usage than interface that are structurally typed. The dispatch table alone requires a fair amount of work relative to this. But YMMV.

                  Just parametric polymorphism is quite limiting. Are you really just thinking of ML style polymorphism with its eqtype kludge? Or do you also want the ability to specify more refined constraints like Haskell’s type classes? Or perhaps Go should grow ML’s module system to make up for the limitations of pure parametric polymorphism?

                  Parametric polymorphism is already present in Go in a limited form. It is blessed, but it is pretty amazing how far just a little bit will get you.

                  1. 2

                    … and now you pay for it with slower run time performance because everything is boxed.

                    No, polymorphism in Go already requires objects so the situation would be no different than now when it comes to polymorphism. Java has similar restrictions for parametric polymorphism.

                    Just parametric polymorphism is quite limiting.

                    It’s really not that limiting, with structs you can get what Go gives you now + extra type safety, unless I’m missing something.

                    Parametric polymorphism is already present in Go in a limited form. It is blessed, but it is pretty amazing how far just a little bit will get you.

                    Cool! Can you give me an example or point me in the right direction? As far as I am aware, Go only has subtyping polymorphism. Or do you mean the builtins like map?

                    1. 1

                      No, polymorphism in Go already requires objects so the situation would be no different than now when it comes to polymorphism. Java has similar restrictions for parametric polymorphism.

                      I’m well aware of this. My point stands. I was pretty clear: adding a convenient way to write slow code will dramatically change how code in the language is written and its performance characteristics. Parametric polymorphism would increase the amount of generic Go code, and thus increase the amount of slow Go code. (Given your implementation strategy of “box everything.”)

                      It’s really not that limiting, with structs you can get what Go gives you now + extra type safety, unless I’m missing something.

                      I don’t see any reason why we should believe that parametric polymorphism covers all use cases of structural subtyping.

                      Cool! Can you give me an example or point me in the right direction? As far as I am aware, Go only has subtyping polymorphism. Or do you mean the builtins like map?

                      That’s what I said “blessed.” Maps and slices and chans and pointers are type constructors. append, make, len and a few others have special built-in polymorphism.

              2. 1

                Yes, the types are checked, but the dispatching happens at run-time

                Yes, but this is also the case in Scala or OCaml, isn’t it? (unlike Rust, C++ or Haskell which mostly use code specialization/monomorphization)

                1. 1

                  I cannot speak for Scala, however that is true of the object part of Ocaml (which is very infrequently used), but Ocaml also has parametric polymorphism which does not implement subtyping, it just lets you express the relationship between types in an expression, and that is how one implements functions like map, in Ocaml the type is ('a -> 'b) -> 'a list -> 'b list, which is not possible to express in Go in a type-safe way.

                  So this isn’t about code specialization or code monomorphism, it’s about what the type system lets one express (or in this case, not express).

          2. 5

            One of the end results of this extreme focus on simplicity is that any Go code is relatively easy to understand. I cannot say the same for other languages.

            Google wanted to build a language that wasn’t intimidating, that was easy to hire new people for, where you can shuffle devs from project A to B with little overhead, and Go is the result. For language nerds like me, this is boring. But I can see the business advantage. Hiring a dev to be productive within days (or hours) is a big win.

            I do agree though, there are other ways for achieving the same end result. Go just takes the shortcut and forces you into this approach. Brutal, but effective.

            1. 10

              Brutal, ambitious, time will tell whether this effectively works

              1. 5

                For language nerds like me, this is boring

                I consider myself a moderate language nerd. After six months of Go, two things have worked well for me.

                One is generating the most valuable repetitive code. I’ve used emacs lisp rather than Go specific tools, due to familiarity.

                The other is implementing little languages more expressive than Go where that expressiveness is more valuable than hand written Go. Those have been logic / query languages over graphs.

                1. 5

                  Go is like the Simple English version of Wikipedia. It’s obviously simple to anyone who is already comfortable with English, like Go is obviously simple to anyone who has experience with C-descended curly-brace languages. The assumption is that the simplified version is easier for new speakers to pick up, which hasn’t really been studied. I’d like to see Google’s results here in teaching people to program with Go.

                  Rob Pike is right in that programming is moving toward multi-core and distributed processing, and Go is right to focus on it. The problem is the barrier to getting good at programming in this environment isn’t overcoming notation. We use it everywhere. People who aren’t strictly software engineers have been using APL and derivatives like K, and things like Excel formulas with great efficacy. Forcing them to use something like Go because it’s “simpler” would probably make their jobs harder, just like forcing you to write in simple English would make it more difficult for you to communicate. Just try writing something in Toki Pona. The barrier to becoming a good programmer in the world that Google is probably correctly predicting is more conceptual: understanding how distributed processes interact with each other. How channels work, how the stuff in the sync package works. Go isn’t doing much to simplify that, even adding its own notation for channels. Notation and syntax probably aren’t the problem.

                  1. 3

                    Your last statement appears to be at odds with the previous one. If notation and syntax aren’t the problem, then adding custom notation for channels doesn’t complicate things.

                    I don’t think Go is using syntax to create simplicity. It’s the type system, the tooling, and the standard library that are doing it. Since you can’t overengineer or overcomplicate things with hyper-elegant abstractions, like you could with Haskell or Scala, you’re restricted to a simple, albeit verbose, toolset.

                    Hence, your comparison with Simple English is on the nose. Limiting yourself to a simple vocabulary may cause things to become needlessly verbose, but that’s a tradeoff if you don’t want the cognitive overhead caused by succinctness.

                    Time will tell if such simplicity is better for the future of software engineering than the opposite, whatever that is.

                    1. 2

                      Interesting comparison to simple language Wikipedia. Even as a native speaker, it’s much easier to understand than Pynchon. Maybe this helps people learn English or not. I do know I would feel much more comfortable editing Wikipedia than Pynchon. They each have their place, but if the role of software in a company is to share information (more or less), one option is more appropriate.

                      1. 2

                        I’m not convinced that comparing Go to Simple English is relevant. I agree that both languages share a goal of simplicity, but the former is a programming language, and the latter is a natural language, which makes the comparison hazardous.

                        Simple English provides a simplified grammar, and Go is similar on this topic. But Simple English also provides a limited vocabulary, unlike Go which doesn’t try to limit your vocabulary in any way (libraries can be as large and rich as you need).

                        The real question is not about grammar and vocabulary, it is about abstraction. Most complaints are about Go lacking generics and sum types. I’m not sure this level of abstraction finds an equivalent in the English grammar and vocabulary. It’s probably expressed using the existing grammar and vocabulary. It’s a “layer” above English.

                        In other words:

                        • a natural language like English will express an abstract concept like generics using its standard grammar and vocabulary;
                        • a programming language like Rust or OCaml will integrate generics directly into its grammar.
                    2. 3

                      The only way to reduce complexity imho is careful design, design review and culture that values thought over commit frequency.

                      But there are many ways to increase complexity, and designing a language that doesn’t bring too much incidental complexity into your project is not a trivial task.

                      My feeling is, that in the end the lack of such features will be compensated in code bases with boilerplate code, leaving users with complex and large code bases.

                      “Are you quite sure that all those bells and whistles, all those wonderful facilities of your so called powerful programming languages, belong to the solution set rather than the problem set?” – Dijkstra

                      It feels a bit like they would advice cooks to do away with knifes in the kitchen, because you can cut herbs with scissors and onions with a grater and switch over to buying ground meat, because knifes can be dangerous and you need experience to handle them.

                      To me it feels like other languages tend to give you a swiss army knife containing a grater, a chainsaw and a scalpel, just to cut a tomato. Except C, which gives you a sword that makes it too easy to accidentally cut the planet underneath you in half, but has no handle.

                      1. 2

                        “Are you quite sure that all those bells and whistles, all those wonderful facilities of your so called powerful programming languages, belong to the solution set rather than the problem set?” – Dijkstra

                        It is pretty hard to channel dijkstra on this matter: http://www.cs.utexas.edu/users/EWD/OtherDocs/To%20the%20Budget%20Council%20concerning%20Haskell.pdf

                        It definitely is a brilliant question.

                        1. 3

                          I don’t fully understand your criticism of the talk. What (I think) Pike says is that, when designing a PL, features should be made (a) few, (b) orthogonal and © carefully designed, so that their use woiuld be simple; and that this may require sime complexity in implementation, or hard thinking about design. Elsewhere he says that a reasonable amount of boilerplate is an acceptable price for conceptual simplicity. So I don’t think I agree with your feeling that it’s about taking essential tools away from programmers.

                          Sure, lack of features will coerce programmers into certain programming style. But so does every programming language, they’re all “opinionated” by their nature.

                          1. 4

                            It probably all boils down to how we emphasize which side of that boilerplace<->abstraction trade off. I have a tendency to opt for a more functional approach with more statical guarantees and I have a bias against boilerplate, because I have seen it as a source of bugs.

                            So choosing between Rust and Go, I would probably pick Rust (if my decision was based on language features only).

                            1. 1

                              I have a tendency to opt for a more functional approach with more statical guarantees

                              Well, this makes sense.

                              and I have a bias against boilerplate, because I have seen it as a source of bugs.

                              Badly designed language features and unreadability caused by complexity are sources of bugs that Pike has seen, I guess.

                            2. 2

                              My criticism of the talk is probably not completely independent from my impression of Go. I can understand language designers opting for exceptions and opting for algebraic datatypes like Rust for error path handling.

                              Sure, lack of features will coerce programmers into certain programming style. But so does every programming language, they’re all “opinionated” by their nature.

                              I don’t believe that by cutting back features it will coerce programmers in to a programming style. if less features are in a language, the more code is built around lacking features, with arbitrary choices in “style”.

                              I admire Go for one feature: gofmt was a terrificly good idea.

                              1. 3

                                My criticism of the talk is probably not completely independent from my impression of Go.

                                Which is fair enough, eventhough Go designers admit that it has warts and lacks certain features that would be really nice to have (e.g., generics).

                                I don’t believe that by cutting back features it will coerce programmers in to a programming style.

                                I think languages nudge (or sometimes force) programmers in certain directions, e.g., by making certain constructs convenient to use (that’s why everything in Perl (4) is a regexp substitution), or by somehow forming a culture among the users (that’s why everything in Java is a final abstract factory factory factory).

                                if less features are in a language, the more code is built around lacking features, with arbitrary choices in “style”.

                                I’m not sure about that: if a certain language feature is lacking, one can just use another construct, or write code in a completely different way that will be natural for this language. In C++ (the language that caused Go to be designed), it seems, quite a lot of code is written for working around broken features.

                            3. 1

                              Add, Haskell was a far, far simpler language in 2001 than it (well, ghc) is today.

                          2. 2

                            I guess the core of my discomfort is that some tasks are easy if you have the knowledge about the code that the compiler already has.

                            Thus in a minimal language, all such tasks not covered by the language designed become hard, sometimes impossible.

                            One of the things I love about D, is it has provided a sane and sensible interface to access, act on and use much of the information the compiler has…. and then feed that back into the compiler.

                            ie. Many features in D which in other languages would require compiler support, have been implemented by allowing an adult compile time conversation between the code and the compiler at compile time.

                            1. 1

                              seems like they are trying to solve a social educational problem

                              Except the earliest writings say the core team set out to design a language for themselves.

                              The only way to reduce complexity is careful design

                              Agreed, and judicious use of tools to support those designs.

                            2. 4

                              Good one. Some of the points in this talk remind me of his article Less is exponentially more, which has been posted to lobste.rs twice to no comments and few upvotes.

                              1. 3

                                Then surely, they should have moved to lisp?

                                1. 3

                                  I always feel like lisp is conceptually simple w/ the AST to code parity, and then I look at any implementation and I see how large the standard libraries are… https://clojure.github.io/clojure/clojure.core-api.html defines 601 “functions and variables” which is 100 more terms to learn than you’d find in a 768 page book on french verbs http://www.amazon.com/501-French-Verbs-Barrons-Language/dp/0764179837

                                  A very pure lisp like Shen has 46 core function which is far more manageable: http://www.shenlanguage.org/learn-shen/shendoc.htm but in the end, the complexity is only half in the language and half in the accidental complexity that comes out of what people build with the language.

                                  I’ve seen some successful lisp code which makes sense to the author (which is part of what Rob Pike is arguing is hard), but it fails on the second side in that it is not quickly and easily decipherable by an outside observer. That reduces the quality of code reviews and the quality of the code in general becomes more a matter of “trust me I know what I’m doing” than “as you can see the code does what we want it to”.

                                  It’s not that Go is as conceptually perfect as a LISP style (or ML style) language, it’s just that it’s easier to not tie yourself in knots with code golf tricks.

                                  1. 1

                                    Good point. Perhaps. I don’t know Lisp enough to tell if I agree.

                                2. 5

                                  To extend on what @data_hope said here, IMO I think a better name for this talk would be “Easy is Complicated”. I think many of the things Pike describes are about being easy, and by that I mean what Hickey describes in that it is “close at hand”, or “familiar”. For example, he talks about newbies wanting map and filter where a for-loop would do. But for-loop’s are not simple, they conflate a bunch of properties such as order, side effects, iteration. They describe not only what to do but how to do it as well. One cannot simply flip out a for-loop for something parallel, for example. With map and filter, it is simple because it describes what, not how. You want to iterate over a collection and do something to it. Maybe it happens in parallel. Maybe it happens in random order, etc. Objects have the same behaviour, they conflate identity, state, computation, and time (generally). They are not simple, in the Rich Hickey definition, but they are easy because most people are used to objects. The thing with constants is another example.

                                  That isn’t to say that being easy is bad or Go is bad or anything of the sort, but I think looking at this talk through the eyes of Simple Made Easy is illuminating. Go is definitely easy, but whether it is simple might be a bit more of a debate.

                                  1. -1

                                    Go – the Donald Trump of programming languages. :-)

                                    Unironically: It is interesting to see that both work really hard to provide their audience with simplistic answers to hard issues and that both have plenty of people defending that if you would only stop trying to look behind the curtain you would also understand the appeal.