1. 53
    1. 41

      It’s frankly kind of fascinating that something made by Google would even let you think about the word “union” when using it.

      Lol.

      1. 3

        It’s frankly kind of fascinating that something made by Google would even let you think about the word “union” when using it.

        Can someone explain the joke for me? :’(

          1. 2

            Hah! Thanks for spelling it out.

    2. 12

      Great read and agreed.

      My suggestion to people is to never release a version 1.x.x of a Go project to avoid the “v2 landmine”.

      This was good advice two years ago when Go module adoption was not widespread, but this is now a non-issue. You can now assume Go modules are used, and switching to v2, v3, etc. is straightforward.

      They also claim to have an internal tool that makes context.TODO() useful

      That would be nice to have. As it is I don’t see anybody using TODO at all.

      This also lets you create untagged union types, or types that can be a range of other types.

      I wish union interface constraints were generally useful, and hopefully they will be, but for the moment they’re only usable within the context of generics

    3. 6

      I’m fairly certain that the part about compilers not supporting easy cross-compiles until the rewrite in go is simply wrong.

      The code to support it is in go 1.0[1], and the signature feature of the Plan 9 compiler toolchain is that ALL compiles are cross-compiles. For example:

      cd /sys/src/cmd
      for(objtype in (arm64 386 mips))
         mk all && mk install
      

      will build and install the system for arm64, 386, and mips – and your arm64, 386, and mips machines will all be able to boot off the shared file server that these were installed to; the binaries don’t conflict.

      I also don’t think that the go compiler currently does much in parallel, a quick poke through the code finds module loading is the main thing that gets done in goroutines.

      [1] https://github.com/golang/go/blob/08b97d4061dd75ceec1d44e4335183cd791c9306/src/cmd/go/build.go#L242

      1. 4

        I probably need to rephrase that part about cross compiling being easier. It was possible on the old go compliers but it was more than 0 effort.

        1. 2

          I don’t think anything changed with the go rewrite. It was always export GOARCH=... and export GOOS=.... This was inherited almost directly from the plan 9 compilers.

          Looking at the code seems to bear that out.

          1. 4

            Yeah, but I more mean the setup effort. Once you set it up it was effortless, but it was not an out of the box default when you installed the compiler.

            1. 7

              Ah. I poked around, and it seems that apparently package managers stripped out cross compilers. I guess to save space? Building the toolchain from source got you working cross compilers out of the box.

              It seems that the go rewrite put all the backends into the same binary, and removed the ability for packagers to break cross compilation.

    4. 2

      I end up missing the brutal simplicity of Go interfaces in other languages like Rust.

      I feel like Rust gives you the freedom to enjoy this type of simplicity, though. Even though it’s often frowned upon by Rust enthusiasts, Rc<RefCell<dyn Trait>> is very similar to Go interface types. You don’t have to worry too much about lifetimes or concrete types, though it does add a little bit of additional overhead from the RefCell having to check outstanding references every time you want to actually do something with the contents.

      I suppose it’s not quite as simple, but Rc<RefCell<dyn Trait>> and Box<dyn Trait> both have a somewhat similar amount of cognitive load from typing as Go interfaces do.

      1. 5

        For me when I compare Rust version to Go version, Rust one seems much more complicated.

        1. 2

          Rust is more verbose, and things are arranged a little differently, but I would argue they’re similar in terms of actual complexity

          1. 4

            How can you look at

            let foo: Rc<RefCell<dyn Foo>> = Rc::new(RefCell::new(Baz(42)));
            

            and

            var foo Foo = NewBaz(42)
            

            and claim that they are anywhere near each other in terms of complexity?

            1. 6

              You can simplify both cases (Go, Rust) of construction to:

              let foo = Baz::new(42); // Rust
              foo := NewBaz(42)       // Go
              

              By moving some of that noise to Baz::new in Rust. It is a little bit unidiomatic but not much. The thing you can’t easily remove is borrow_mut(). Since Rust asks you to decide about mutability when you define a trait, even an implementation that does no mutations pays the (syntactic) price of that decision. In Go it is type that implements an interface that decides about that and callsites don’t differ for mutating and ‘pure’ versions.

              I completely understand that this is all for good reasons in Rust (and I very much like Rust) but for me Go (which I also like) is much less noisy (at the cost of weaker compile time guarantee).

            2. 1

              Complexity for whom? They have similar semantics. They do similar things. The “simplicity” is just that Go uses that kind of semantics everywhere. Except when it doesn’t.

              1. 4

                The rust version (Rc<RefCell<dyn Trait>>) comes with a high cognitive overhead. It is expressive, but I would definitively not qualify it as “simple”.

                1. 1

                  Yes. And understanding what is actually going on with the Go version is also pretty nontrivial.

                  I’m not saying that the shortcut isn’t useful, I’m just saying it’s a shortcut, not an abstraction.

                  1. 2

                    This thread started with a question about “cognitive load from typing”. Do you think that because Rust exposes implementation details in the type it has lower “cognitive load from typing”?

    5. 1

      the fact that it defaults to phoning home to Google every time you run a Go build without all the dependencies present locally is kind of questionable.

      Definetely annoying, and weird.

      I think that even without a company proxy, you can still use GOPRIVATE to keep private repositories from being checksumed by golang.org’s proxy.