Live data from Hacker News

Lies we tell ourselves to keep using Golang

fasterthanli.me

391–400 of 561 posts

Re: Lies we tell ourselves to keep using Golang

#391
post #375

Earlier quoted context omitted.

If you want a big standard library why not use something like Java or C#? I mean, you even have UI toolkits available from the get go

With Go you can develop a web service with few to no external deps or frameworks, compile it into a single, static binary and then deploy it in a minimal distroless container. With Java and C# there's a lot of other fuss involved with figuring out deployment. The code, build, test cycle is also much slower in C#/.NET ime. That's starting to improve a bit with the newer dotnet, but still feels behind other everything…

Java can literally hot-swap classes, how does it have a slower code-build-test cycle? It also has possibly the best debug mode and observability.

Re: Lies we tell ourselves to keep using Golang

#392
post #384

Earlier quoted context omitted.

I don't think it's necessarily the HN moderation team's job to tell us what we should and should not find interesting. It's a crowdsourced news aggregation site and discussion forum, not a magazine with an editorial board. That's fundamentally not how HN works, though. It's neither just crowdsourced nor just editorially curated. This thing ends up being a dupe fairly straightforwardly, it's not some weird edge case.…

I don't see how one can say that this ends up being a straightforward dupe, unless you're just observing that it's criticism of Go by the same author and with a similarly provocative title. I admittedly haven't read "Mr Golang's Wild Ride" since it first hit HN a couple years ago (and I don't really intend to, I have my doubts that it would be an edifying use of my time) but, based on what I remember of it, this new…

I think you're getting somewhat hung up on the content of the piece and the moderation in this case doesn't have much to do with it. Critique pieces of popular languages are themselves popular and get frequent and regular coverage on HN. This one had one significant discussion yesterday, last year and also the year it was published. That's a pretty good run and it will undoubtedly appear again, along with its update. But not on the front page for two days straight because almost nothing gets to sit on the front page for two days straight, that mostly being the point of a front page of daily links.

Re: Lies we tell ourselves to keep using Golang

#393

Earlier quoted context omitted.

> operator overloading is the spawn of Satan I used to agree with you, because of the abuse of operator overloading like iostreams and making DSLs with it. D does support it, but in a way that discourages non-arithmetic uses (such as it won't allow = > to be overloaded separately). Operator overloading allows for things like complex numbers, arbitrary precision numeric types, etc., to be done with a library module.

> Operator overloading allows for things like complex numbers, arbitrary precision numeric types, etc., to be done with a library module. Why is this desirable vs. implementing those types in the language itself? I think we've gone down a weird path where implementing things "in userspace" is seen as an inherent good -- why?

This is probably the best talk ever on the general topic: https://m.youtube.com/watch?v=_ahvzDzKdB0 [Growing a language by Guy Steele], seriously give it a look if you have the time and do put up with the seemingly strange start.

But at around the end it asks this (paraphrasing): Should a language have complex numbers implemented natively? Should it have numbers module n implemented natively? What about intervals, or rational numbers?

I also dislike the ridiculous overloading of cryptic symbols, but neither extreme is good. Not allowing overloading will give you BigDecimal.of(3).add(BigDecimal.ONE).divide… , while allowing it unrestricted will give you things like msg #!! something. But perhaps a sane middle ground is to allow only basic operators (+,-,*,/) to be overloadable.

Re: Lies we tell ourselves to keep using Golang

#394
post #379
post #361

Earlier quoted context omitted.

> If something blows up in production in an unexpected way, sometimes that's okay. You log the problem, fix it, and it's fine. as the person on call for such events, it's really not fine. would you rather handle these errors upfront during development time or unexpectedly and uncontrollably, during runtime? having been on-call in one way or another for ~10 years, i know which i'd prefer. after having used golang in p…

It’s a big assumption that you can even handle the error at the callsite, or that you will actually handle it correctly there, or just write some low-effort attempt because the overall picture is more important for now, but later on you won’t notice how it is not correct and it will just silently fail. Exceptions are in my honest opinion better on every single front. Checked exceptions would be the panacea but Java’s…

consider this example - one using dynamic code with exception-based handling (ruby), and one using golang's more explicit error handling:

ruby:

  begin
    res = Net::HTTP.post_form(APIURL, ...)
    puts res.body
  rescue e => e
    # do error handling
  end
go:

  response, err := http.PostForm(APIURL, url.Values{...})
  if err != nil {
    # handle PostForm error
  }
  
  defer response.Body.Close()
  body, err := ioutil.ReadAll(response.Body)
  
  if err != nil {
    # handle ReadAll error
  }
  
  fmt.Printf("%s\n", string(body))
Now, for which errors do you handle? In golang, you can see clearly where errors may occur. In Ruby, it's unclear whether HTTP.post_form is even capable of throwing errors, much less what they are. For the record, here are a few of the many types of errors that can be thrown by the ruby code. Here are a few:

  Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, ...
there's no way to tell _where_ the error will even come from - you might get a Net:: error, you might get a Timeout:: error, hell you could even get an Errno::! What most programmers wind up doing is handling no errors at all until they occur in runtime - or wrapping every single "suspicious" statement in a catch-all begin/rescue block, even when it's not needed.

In golang, each function capable of returning an error simply returns it, and you must handle it at that point in time. It is very straightforward. In my experience, it results in much more reliable code. In Ruby, you have no idea what's coming. Do you see what I mean?

Re: Lies we tell ourselves to keep using Golang

#395
post #391
post #375

Earlier quoted context omitted.

With Go you can develop a web service with few to no external deps or frameworks, compile it into a single, static binary and then deploy it in a minimal distroless container. With Java and C# there's a lot of other fuss involved with figuring out deployment. The code, build, test cycle is also much slower in C#/.NET ime. That's starting to improve a bit with the newer dotnet, but still feels behind other everything…

Java can literally hot-swap classes, how does it have a slower code-build-test cycle? It also has possibly the best debug mode and observability.

Sorry if it was unclear, I was specifically commenting about C# with regards to build, test, deploy cycle because I don't have much experience with Java. It's good to hear that it's not slow or cumbersome.

Re: Lies we tell ourselves to keep using Golang

#396
post #379

Earlier quoted context omitted.

It’s a big assumption that you can even handle the error at the callsite, or that you will actually handle it correctly there, or just write some low-effort attempt because the overall picture is more important for now, but later on you won’t notice how it is not correct and it will just silently fail. Exceptions are in my honest opinion better on every single front. Checked exceptions would be the panacea but Java’s…

But people write "low-effort attempts" at exception handlers all the time. So using exceptions instead of error values doesn't actually change the situation.

Defaults matter. Exceptions give me the question whether I want to worry about this piece of code here, or just go on and be reminded that it is actually important at runtime with an unmissable runtime error which has exact character number for the origin of the mistake. Even Java’s checked exceptions can be just added to the method signature.

(Ab)using Result types without good syntax for dealing with the very common case of “handle it higher up” (Rust’s ? macro is ok, not perfect but it is a much better compromise) is coming from a wrong angle imo.

Re: Lies we tell ourselves to keep using Golang

#397
post #268

The author writes well and makes compelling points. His "I want to get off Mr Golang's Wild Ride" post is good too. But I don't find myself agreeing with his position, which is "you shouldn't use Go for production services" (he explicitly says this in one of his Go posts, I forget which one and don't have time to look right now). The better alternative to Go is Rust. Okay, sure, I'm willing to admit that in the examp…

The content is mostly ok, but the title suggests that there's some obvious alternative to Go that we should be using. If he's implying it's Rust, then he's totally disconnected from reality.

It's really not, and it's even saying so explicitly in the article.

Re: Lies we tell ourselves to keep using Golang

#398
post #394
post #379

Earlier quoted context omitted.

It’s a big assumption that you can even handle the error at the callsite, or that you will actually handle it correctly there, or just write some low-effort attempt because the overall picture is more important for now, but later on you won’t notice how it is not correct and it will just silently fail. Exceptions are in my honest opinion better on every single front. Checked exceptions would be the panacea but Java’s…

consider this example - one using dynamic code with exception-based handling (ruby), and one using golang's more explicit error handling: ruby: begin res = Net::HTTP.post_form(APIURL, ...) puts res.body rescue e => e # do error handling end go: response, err := http.PostForm(APIURL, url.Values{...}) if err != nil { # handle PostForm error } defer response.Body.Close() body, err := ioutil.ReadAll(response.Body) if err…

I’m not familiar with Ruby, but in java you can just specify the try-catch block’s scope as explicitly as you want.

``` try { var response = http.postForm(APIURL,) } catch (Exception e) { # handle PostForm error }

try { var body = ioutil.ReadAll(response.Body) } catch(SomeSpecificExceptionType e) { # handle specific exception differently } catch(Exception e) { # run for every other kind of error }

If a given method is defined as `void postForm(…) throws IOException` you have to handle the exception at the call site, or mark the containing call itself with a similar throws clause.

I really don’t see anything not handled by these. Also, the defer part can be done by a try-with-resources construct that will clause the resource in every case, whether exited without exception or with one.

Re: Lies we tell ourselves to keep using Golang

#399
post #142
post #109

Earlier quoted context omitted.

As I understand it, he's talking about select/alt (i.e. guarded commands from CSP) being a native feature of the language rather than callback-based approaches. It's possible to implement CSP channels in most languages, but they're not first-class like go.

> It's possible to implement CSP channels in most languages, but they're not first-class like go. But does that matter ? In all my experience, I can't think of any instances where that wouldn't be a distinction without a difference. (Perhaps I'm missing something, though.)

It's the opposite - pointing out that X can just as well be implemented in language Y is the irrelevant point because anything can be implemented in any turing complete language.

Where languages differ is what they make easy to use, or first class.

As an example consider Go's autoformatter gofmt. It got released with the language, pushed and marketed as the way to format your code - first class. As a result, virtually all Go code is uniformly formatted. Contrast that with autoformatters in other languages pre-Go. They existed, but often multiple per language, each with hundreds of configuration options, all with minimal uptake in their ecosystems.

Re: Lies we tell ourselves to keep using Golang

#400
post #385
post #148

As people have remarked, Amos's style can be grating and hyperbolic. That doesn't make a lot of his complaints about Go as a language incorrect. I do think he's misunderstanding that the design intent is "networked C" and that Go + Protobuf is much better than he thinks. A lot of his complaints with the language and runtime boil down to: - It's got a primitive type system (yep, nobody disagrees) - It leaves a lot of…

What I don’t generally get is why Go when there is Java already? Like other than the somewhat smaller memory footprint that is not inherent to the language, but the runtime — in what way is Go better that could not have been a Java library? Hell, with Google’s resources one other GC/mode could be added to OpenJDK that prioritizes memory footprint (at the expensive of throughput - there is no free lunch). Sure, Java h…

There are a few things, mostly due to the runtimes but also because the JVM bytecode assumption has real implications for system behavior.

Let's start with bytecode. It "requires" (except for AOT work) a warm-up / JIT phase that tends towards slower start times. This isn't hard and fast, but in practice it's true. (And when you search for "jvm startup", you end up at lots of pages about how to tune things to try to make this better). For some people, just as bad or even worse (remember, distributed system) is the impact that JIT-compilation and warm-up has on tail latencies. The static nature of most compiled languages mean this isn't a thing you worry about. You've got enough tail latency problems in your life, you don't need "oh hey, I just saw this loop for the Nth time, I took 10ms to hot compile it!".

That leads into the runtime and some of the language choices around it. Java GCs are generally fighting a harder problem than Go's GC, and with a very different tuning point. Java making everything an object and support classloading and so on, has real knock-on effects for the amount of work required to get high-quality, low-pause GC to work. This is much better today than it was in 2008 when the Go team started, but it's still the case that Go has an out-of-the-box better GC experience. Yes there exist special, tuned GCs (e.g., Azul's C4, Shenandoah) but Java GCs have to really be super clever compared to the fairly simple strategies that work in Go; I applaud the ingenuity in Java GC work, but if what you care about is "reasonably good at collecting memory, never pauses for long", the Go language decisions made the GC problem easier.

I think it's fair to ask "Shouldn't Google have just improved Java?", but I think you miss out on lots of the concurrency ergonomics. Again, this has to be compared to a decade ago. Especially post 2010 (Oracle acquisition) it was super unclear that you'd want to attempt to "bet on Java".

To be clear, I do think Go is at the wrong point on the language/type-system sophistication curve for my tastes. That said, I find myself shaking my head at most Java code, while looking at the Go code and thinking "sigh, lots of repetition. I hope one day that gets better, but at least it's obvious".

Post reply on HN