Live data from Hacker News

Twelve Years of Go

go.dev

201–210 of 244 posts

Re: Twelve Years of Go

#201
post #98

Earlier quoted context omitted.

My non-Go code is starting to look more like my Go code. One of the things Go taught me is that I was not being as careful about my errors as I should be. It can be argued that exception-based handling provides you a nice baseline default, but it makes it way to easy when doing network or system-type programming to thoughtlessly default to that, when you need to be thoughtfully defaulting to that. With sufficient car…

I think this is for sure the first time I have ever heard someone say that Haskell makes it too easy to handle error cases.

I've used Scala in production codebases and it was common to just "let the EitherTs handle the exceptions". What ended up usually happening was swallowed exceptions that nobody bothered to handle and log because it was much less idiomatic Scala/FP to actually log what happened underneath than it was to return the first error that happened by short circuiting the EitherTs in for/yields (Maybe and do notation, for Haskellers). So we'd get 5xxes and log lines like "row not found" and have absolutely no idea why.

I see a lot of the same issues in Rust code today FWIW. People just keep bubbling up errors and at the toplevel say "fuck it" and dump them, without _actually_ building a reasonable error chain to offer the programmer a story behind how the error happened. The fact is, error handling in any language is tedious. Whether you do it with a sum type, a product type, or Go's error values, either way there's going to be lots of verbosity and boilerplate.

Re: Twelve Years of Go

#202
post #98

Earlier quoted context omitted.

My non-Go code is starting to look more like my Go code. One of the things Go taught me is that I was not being as careful about my errors as I should be. It can be argued that exception-based handling provides you a nice baseline default, but it makes it way to easy when doing network or system-type programming to thoughtlessly default to that, when you need to be thoughtfully defaulting to that. With sufficient car…

Go’s error handling is a strange this to praise considering it is entirely possible to ignore it without warning and the way to check error kinds was bolted on through type assertions when errors are supposed to be values in Go. Error kinds are important especially in network programming when the error can be dozens of different things. Compare this to something like Rust or Haskell which force you to handle errors a…

Pretty much every form of Go tooling warns you when you ignore an error. If you only choose to run "go build", yes you can ignore it, but a simple "go vet" call and it'll be plain as day.

Re: Twelve Years of Go

#203

Earlier quoted context omitted.

Go’s error handling is a strange this to praise considering it is entirely possible to ignore it without warning and the way to check error kinds was bolted on through type assertions when errors are supposed to be values in Go. Error kinds are important especially in network programming when the error can be dozens of different things. Compare this to something like Rust or Haskell which force you to handle errors a…

Pretty much every form of Go tooling warns you when you ignore an error. If you only choose to run "go build", yes you can ignore it, but a simple "go vet" call and it'll be plain as day.

    a, err := foo() // oops, unhandled error
    err = bar()
    if err != nil { ... }

or

    fmt.Println("...") // oops, unhandled error
or more insidiously

    err1 := foo()
    if err1 != nil { ... }
    err2 := bar()
    if err2 != nil { return err1 } // oops

Re: Twelve Years of Go

#204
post #101
post #50

Earlier quoted context omitted.

If you think there's some virtue in writing verbose and inexpressive imperative code, what does Go provide in that department that you couldn't have got from Java 1.44?

I have often thought that if you could travel back in time and make Java's interfaces work like Go, there would be no Go today. The first-order effects of that change may not seem like much, but the second-order effects of that change is profound. In Java, interfaces must temporally precede their implementations; in Go they don't have to. This turns out to be huge in practice. It turns out that huge swathes of all th…

Java's interfaces (nominal typing) is superior for both readability as well as IDE performance. Working on a large golang code base, it's always a struggle for both the programmer as well as the IDE to find out what interfaces a given struct implements. Coding is also more tedious as it's not straight forward to add a new function to an interface and get immediate feedback at the struct declaration site about the missing functions. It's just a big mess overall.

This is of course not to mention the dangers of unintentionally implementing and interface and having bad things happen (this happened in the golang stdlib out of all places as I recall).

Languages like Scala with HKTs or Kotlin with delegates (if I'm not mistaken) solve the issue of delegating to interfaces without much boilerplate. It's just that golang authors have not been exposed to other languages since the 70s.

Re: Twelve Years of Go

#205
post #50

Earlier quoted context omitted.

If you think there's some virtue in writing verbose and inexpressive imperative code, what does Go provide in that department that you couldn't have got from Java 1.44?

Go is constantly being improved and refined compared to Java 1.44, there is a strong community of third party packages, you aren't shoehorned into the OOP box by basic language design, you get green threads in the form of goroutines while in Java land you are dealing with native threads & the issues they involve (curiously just learned Java <1.3 actually did use green threads, I suppose they were a casualty in the ef…

Java is getting green threads by means of Project Loom, and value types by means of Project Valhalla.

Not to mention it has sum types and pattern matching, something not available in golang. golang doesn't even have proper enums, quite astounding really.

Re: Twelve Years of Go

#206
post #92

Earlier quoted context omitted.

I write a variety of CLI tools for my own use in Java. On this low-end Chromebook (Samsung Chromebook 3 with a Celeron N3060 @1.60GHz) I can start the JVM, load the classes for my CLI program, and print a help message, jpavel@penguin:~$ time rcr -h Usage: RCloner get|put [args] RCloner list real 0m0.316s user 0m0.208s sys 0m0.126s in less than 1/3 of a second. And this is with stock openjdk version 1.8.0_302, which d…

I think he was talking more about serverless functions, where 300ms longer for answering an HTTP-request would be pretty long.

See GraalVM: https://quarkus.io/

Re: Twelve Years of Go

#207
post #106
post #94

I can attest to the fact that programming in Go taught me a lot of good engineering. I certainly find myself better trained at handling errors, for example. However, I always feel exhausted when implementing real-world systems with Go given the lack of $things (that everyone feels is a virtue). Over time I realized that a lot of people just aren't as lazy (or scared of breaking things) as I am - they find it easier t…

If you are or your coworkers are constantly copying and pasting code, stop, and think a bit more. I do a lot of Go development and almost never copy and paste anything anywhere. (And even in those cases it's usually justified. I just a few minutes ago copied and pasted a big struct... but it's because the first struct was defining a JSON message, and the second struct was defining a very similar, but not quite identi…

I agree with the poster you're replying to. The large golang projects I've been involved with have been extremely tedious to work on, even on projects started from scratch.

The language is extremely weak (it's not expressive), which translates to overly verbose code that is difficult to traverse. Logic that can be expressed in a couple of lines in Java becomes 10+ lines in golang, with code scattered everywhere. Not to mention that golang lacks enums or sum types (the latter have now made it into Java), which are a huge safety and productivity booster.

Re: Twelve Years of Go

#208
post #203

Earlier quoted context omitted.

Pretty much every form of Go tooling warns you when you ignore an error. If you only choose to run "go build", yes you can ignore it, but a simple "go vet" call and it'll be plain as day.

a, err := foo() // oops, unhandled error err = bar() if err != nil { ... } or fmt.Println("...") // oops, unhandled error or more insidiously err1 := foo() if err1 != nil { ... } err2 := bar() if err2 != nil { return err1 } // oops

In the first and the last case, it seems obvious to me where the error is. An obvious code smell caught in review. The second error, yeah, but lots of languages don't enforce error handling around printing to stdout, and even though Rust does in theory, in practice everyone just unwraps it and moves on with their day.

Re: Twelve Years of Go

#209

A good twelve years. Go really changed the way I think about programming. I used to be excited by programming language features instead of what problem I was actually trying to solve with programming. I'd spend hours condensing 10 lines of perfectly working code into 1 line of the most concise text possible; huffman encoded better than even gzip could imagine. And I'd feel great about it. I'd imagine people reading i…

Go’s package and dependency system is actually the only reason I have never started using it more. The lack of true versioning, unspoken assumption of GitHub, package system, and all of the confusion between god mod, go get, go install, etc. just hurts my brain. I think Rust actually has this perfect. It’s clear. You just specify the name and version and features in the Cargo.toml file and it is pulled from crates.io…

> The lack of true versioning, unspoken assumption of GitHub, package system,

These aren’t true. There is true versioning and no assumption of GitHub. Shouldn’t this be a complaint about the assumption of crates.io?

> No installation-time execution either.

This is also not true. There is no installation-time execution.

Re: Twelve Years of Go

#210

Earlier quoted context omitted.

> That's not 100% accurate; as a concrete example, contain the implementations of this interface method But why? I've often wanted to know what a method does in Ruby and have had to resort to .method(:x).source_location because it is so dynamic only the compiler knows once it has finished running it. I've never had to find all the places that conform to an interface in Go (a very different question) or Java, because…

Most interfaces in Go code have exactly two implementors that will ever be plugged in: the production code and the mock. You want to be able to delve down through the layers of production code, e.g. handler to controller to gateway, to trace what's going on in an RPC request.

IMO those interfaces shouldn't exist, I don't use mocks often.

Think about interfaces like io.Reader - why would you want or need to know every implementor of these?

Post reply on HN