Live data from Hacker News

An Honest Review of Go (2025)

benraz.dev

101–110 of 184 posts

Re: An Honest Review of Go (2025)

#101
post #62

Earlier quoted context omitted.

C# is pretty close.

This was not the case for a long time. Actually it seems like it's fairly recently you get native AOT and trimming to actually reduce build sizes and build time. Otherwise all the binaries come with a giant library

Even back in .NET Core 3.1 days C# had more than competitive performance profile with Go, and _much_ better multi-core scaling at allocation-heavy workloads.

It is disingenuous to say that whatever it ships with is huge also.

The common misconception by the industry that AOT is optimal and desired in server workloads is unfortunate. The deployment model (single slim binary vs many files vs host-dependent) is completely unrelated to whether the application utilizes JIT or AOT. Even with carefully gathered profile, Go produces much worse compiler output for something as trivial as hashmap lookup in comparison to .NET (or JVM for that matter).

Re: An Honest Review of Go (2025)

#102
post #76
post #3

I commend Go for popularizing the channel-based concurrency, since I do think that that is a very elegant way of structuring stuff (especially compared to mutexes), but I have to admit that I don’t have a lot of fun writing Go. I agree with a lot of the sentiment of this post; the weirdness with “tuples”, the weirdness of the error types, and etc. It’s not a “bad” language, just one that I don’t enjoy using. Historic…

What are they top 3 languages that you have used that can be used as Go alternatives ranked by fun in your opinion (I am guessing Clojure and Rust are two of them)?

You’re right! I think overall I have most fun with Clojure.

I also really like Julia; it has a channel mechanism and it has a very nice macro syntax. It also is obscenely fast at number crunching tasks and I find the language pretty pleasant to use with a nice syntax. I use Julia whenever I need to do anything involving CPU bound number crunching stuff (which admittedly isn’t too often).

All that said, I have been mostly favoring Rust because the memory footprint is so much smaller and I still have a fair amount of fun with it :).

Also, depending on the task, I also get a fair bit of mileage out of ZeroMQ, which can bolt on channel-like semantics in a pinch. It’s not as nice as having it build directly into the language but it does support more flexible patterns. Whenever I have to use Java I almost always end up importing JeroMQ the moment that that built in BlockingQueues stop being sufficient.

Re: An Honest Review of Go (2025)

#103
post #40

Earlier quoted context omitted.

"Enum" is literally defined as a numbering mechanism. While integers are the most natural type used to store numbers, you could represent those numbers as strings if you really wanted. The key takeaway is that a enum is a value , not a type. The type the link was struggling to speak of seems to be a tagged union. Often tagged union implementations use enums to generate the tag value, which seems to be the source of c…

Disagree. Enums are named for being enumerable which is not the same thing as simply having an equivalent number. It’s incredibly useful to be able to easily iterate over all possible values of a type at runtime or otherwise handle enum types as if they are their enum value and not just a leaky wrapper around an int. If you let an enum be any old number or make the user implement that themselves, they also have to im…

> Enums are named for being enumerable which is not the same thing as simply having an equivalent number.

Exactly. Like before, in the context of compilers, it refers to certain 'built-in' values that are generated by the compiler; which is done using an enumerable. Hence the name. It is an implementation detail around value creation and has nothing to do with types. Types exist in a very different dimension.

> It’s supposed to be a union type

It is not supposed to be anything, only referring to what it is — a feature implemented with an enumerable. Which, again, produces a value. Nothing to do with types.

I know, language evolves and whatnot. We can start to use it to be mean the same thing as tagged unions if we really want, but if we're going to rebrand "enums", what do we call what was formally known as enums? Are we going to call that "tagged unions" since that term now serves no purpose, confusing everyone?

That's the problem here. If we already had a generally accepted term to use to refer to what was historically known as enums, then at least we could use that in place of "enums" and move on with life. But with "enums" trying to take on two completely different, albeit somewhat adjacent due to how things are sometimes implemented, meanings, nobody has any clue as to what anyone is talking about and there is no clear path forward on how to rectify that.

Perhaps Go even chose the "itoa" keyword in place of "enum" in order to try and introduce that new term into the lexicon. But I think we can agree that it never caught on. If I, speaking to people who have never used Go before, started talking about iotas, would they know what I was talking about? I expect the answer is a hard "no".

Granted, more likely it was done because naming a keyword that activates a feature after how the feature is implemented under the hood is pretty strange when you think about it. I'm not sure "an extremely small amount" improves upon the understanding of what it is, but at least tries to separate what it is from how it works inside of the black box.

Re: An Honest Review of Go (2025)

#104
post #65

Earlier quoted context omitted.

I use Go as my preferred language and I think the author is mostly right. There’s no way for me to know or even check what are the possible errors this function can return? Sure, sometimes a comment in the library might be illuminating, but sometimes not. I agree that errors as values that I can handle at the call site rarely feel useful. Some of the Is, As ergonomics have improved, but damn if coding agents don’t lo…

The article claims: "The user now has an interface value error that the only thing they can do is access the string representation of." This is false. Didn't used to be, but that was many years ago.

>this is false.

It's mostly false.

Technically, if you use `fmt.Errorf`, then the caller can't get anything useful out of your errors.

Types are promises. All the `error` interface promises is a string representation. I acknowledge that most of the time there is more information available. However, from the function signature _alone_, you wouldn't know. I understand that this is more of a theoretical problem then a practical problem but it still holds (in my opinion).

Re: An Honest Review of Go (2025)

#105

Earlier quoted context omitted.

> Rust I cannot even compile after 24h Could I ask what hardware this is on? Even when building LLVM from scratch too as part of building the toolchain (which hasn't been the default for a while now, but could see Gentoo doing so), it never took that long on any hardware I own. (Granted, I never tried on the EEE PC I've got on some drawer, and its 2G of RAM would likely kill the whole thing before it got started.)

This is an older thinkpad I am using, 4 cores, 16G of ram. LLVM is now dependency you cannot get rid of. That is painfull, but in the morning, after several hours it is usually done. Rust is LLVM plus I am not sure what, really painfull. And Gentoo also forces many different arches and flags for some reason, use flags are masked, you cannot easily disable them.

That sounds similar to the hardware on my T460 (2 cores, 4 threads, 16G). Would you consider cloning the repo and building it with the same command as my other comment? I'm really intrigued if the issue is the hardware/platform or "just" the Gentoo configuration or something else that doesn't affect the default build process.

Re: An Honest Review of Go (2025)

#106
post #65

Earlier quoted context omitted.

The article claims: "The user now has an interface value error that the only thing they can do is access the string representation of." This is false. Didn't used to be, but that was many years ago.

>this is false. It's mostly false. Technically, if you use `fmt.Errorf`, then the caller can't get anything useful out of your errors. Types are promises. All the `error` interface promises is a string representation. I acknowledge that most of the time there is more information available. However, from the function signature _alone_, you wouldn't know. I understand that this is more of a theoretical problem then a p…

The subtlety missed in these conversations is that almost all the information there is for typical error handling --- that is, all the information that would be present in a typical Rust error handling scenario as well --- is encoded in the type tree of the errors.

(Rust then improves drastically on the situation with pattern matching, which would simply improve Go with no tradeoffs I can really discern, just so we're clear that I'm not saying Go's error story is at parity with Go. But I'd also point out that Rust error handling at a type level is kind of a painful mess as well.)

Re: An Honest Review of Go (2025)

#107

Not shilling for Go here but there are a few misconceptions in this blog post. In addition to the others mentioned: > All of these examples involve assigning to a constant a value known at compile time but none of them will work Maps are not known at compile time. Hash functions are randomized based on a seed only known at execution time. The hashed value of "HELLO" is actually different each time the program runs. E…

Doesn't protection from reassignment not exist in most languages anyways? In C++ you should be able to cast away the const. Realistically you probably can achieve this in any language with reflection.

Unless a const is literally a compile time constant inserted through the program, it's likely able to be changed somehow in most languages.

Re: An Honest Review of Go (2025)

#108

Earlier quoted context omitted.

I'm not sure I understand your argument. You're saying that you can't really use enums for field numbers. And let's say that you're absolutely correct about that. It still seems to me that you're addressing a completely separate issue from having a specific field that is an enum - not an enum of a field number, but an enum of something else, like encryption algorithm or SHA type or something. Am I missing your point?

I’m pointing out that proto’s enums are wrappers around proto field numbers, which are numerical ids for proto message fields that enable forward/backward compatibility across proto message version changes. These field numbers are necessarily sparse but don’t even need to be assigned sequentially, and in fact, because of the leaked implementation details from the internal field number range you have to assume they ar…

But why is sequential a requirement? That is, in C++ I can have an enum like

  enum mask {
    BIT_0 = 0x1,
    BIT_1 = 0x2,
    BIT_2 = 0x4,
    BIT_3 = 0x8,
    NIBBLE_0 = 0xF,
  ...
  };
C++ does sparse enums just fine. Are you saying that those are not "real" enums because their sparse? Or that C++ doesn't have "real" enums because it allows that? Or what?

Re: An Honest Review of Go (2025)

#109

One of the things I wish more people talked about isn't just the language or the syntax, but the ecosystem . Programming isn't just typing, it's dealing with dependencies and trying to wire everything up so you can have tests, benchmarks, code-generation and build scripts all working together well. When I use modern languages like Go or Rust I don't have to deal with all the stuff added to other languages over the pa…

> However, I'd pick Rust when the team isn't scared of learning to program for real.

I've been learning Rust. It's elegant, and I am enjoying it.

The Rust people however are absolutely annoying though. Never have I seen such a worse group of language zealots.

Re: An Honest Review of Go (2025)

#110
post #90
post #4

Lack of enums are the main point for me. The error story is not ideal but less bad than that most of the time, as you can downcast to access extra error data. Still, harder than it needs to be. Overall, I've grown to like using the language even despite its warts.

What is with people and their need for enums? Functionally using go const with iota gives you the same damn thing and people use enums that way 99% of the time. I find Rusts reliance on enums annoying as hell. At this point I consider Rust a bandwagon language. The syntax is abysmal and we have had memory safe languages far before Rust. That I wont get into because as a Vulnerability Researcher I find the Rust push s…

To be more clear, I want sum types with exhaustive matching - which Go does not support.

I get by without it Go enums are an inferior representation of the same logical concepts. Sure, I can have (kind, value) and cast things for a hacky sum type for some kind enum. But Go lacks closed enums/exhaustive matching.

You can at least validate the match arms with things like type switches and marker interfaces, but they're still not exhaustive and they're terribly verbose.

And, again, I can get by without them! But I miss them because Rust-style enum representation comes up _so often_, even if you don't like the rest of Rust.

Post reply on HN