Lies we tell ourselves to keep using Golang
Posted by Nekuromento@reddit | programming | View on Reddit | 351 comments
Posted by Nekuromento@reddit | programming | View on Reddit | 351 comments
Bananenkot@reddit
This I can't overlook. There's no excuse for a type system this pityful in a modern language.
aholmes0@reddit
Python's type annotations will make your head explode. Mine is long gone. :|
Maybe-monad@reddit
My Haskell brain says they're too weak
metaquine@reddit
My Java 24 brain says they're too weak
QuickQuirk@reddit
Does java actually have a decent type system these days? Serious question. Last I looked decades back, it was pretty much a copy of C/C++
metaquine@reddit
It's not Haskell but it does the job in very practical ways for the most part, the language has carefully added various constructs over the years. Most notable generics in 2005, lambdas in 2014; immutable lightweight records a few years ago, and pattern matching recently, to name a few favourites.. Hopefully we will see Value Objects soon. Google a feature list, you might be surprised.
QuickQuirk@reddit
thanks!
aholmes0@reddit
I don't use Java, but from what I'm aware of the answer is "yes, but generic type erasure was a bad idea."
Sigmatics@reddit
You don't really need the complex parts if you're not doing stuff out of the ordinary
SemaphoreBingo@reddit
Your "ordinary" must be quite limited, I've found it very easy to hit some unpleasant parts of the python type annotation systems.
JanEric1@reddit
Do you have examples?
aholmes0@reddit
Typing decorators appropriately can get nasty fast, or having to type "around" an inappropriately typed decorator.
JanEric1@reddit
Really? ParamSpec + Concatenate allow pretty straight forward typing for everything i have encountered.
But i think that also isnt necessarily a python thing, just a (not generally) functional language having to type higher order functions.
aholmes0@reddit
You've never run into issues with some random decorator from some library being typed inappropriately? Maybe that's true and you've been fortunate. Either way, I personally wouldn't consider
ParamSpec
to be "pleasant" (referencing u/SemaphoreBingo's "hit some unpleasant parts").I think it is, in a hand-wavy "this has been my experience" sort of way. I'm sure some languages hit similar issues, however, I can't help but immediately think of C# and how pleasant it is to handle functional programming techniques, including the static typing. However, C# is used in different ways from Python, so a 1-to-1 comparison of decorators specifically isn't really possible. You could compare attributes, subclassing, extension methods, etc. but none of them are exactly the same.
aholmes0@reddit
You really don't need to go deep to hit problems. Typing
*args, **kwargs
a pain and doesn't work in a lot of ways, and those two parameters are too commonly used (meaning "ordinary") in Python to be ignored. Generics are a pain. Callables with parameter names are a pain. The requirement to quote annotations for types that aren't yet defined is a pain. And it all ends up looking like a muddled mess. All but the simplest, e.g.x: int
, is just the least ergonomic type system I have to work with.Sigmatics@reddit
Fair, as soon as you get into dynamic arguments and Self return it starts getting a bit arduous
Halkcyon@reddit
It really isn't difficult anymore.
aholmes0@reddit
We don't all have the luxury of relying on later versions of Python, which is part of the pain. I write libraries and need to maintain compatibility. ¯\_(ツ)_/¯
Halkcyon@reddit
My dude.
Unpack
is available fromtyping_extensions
and__future__.annotations
has been there since 3.7.aholmes0@reddit
Good to know! Thank you. It can be difficult to keep up with the changes to Python's type annotations, and the tooling (in my case, Pylance) isn't always up-to-speed on accurate imports ... but I will remember
Unpack
next time I have the need. As for__future__
I just try to avoid it ... too many unusual things have occurred.Halkcyon@reddit
That's fair. In my experience, most of the kinks with Pydantic and SQLAlchemy have been worked out with delayed annotations now.
aholmes0@reddit
Thank god. :) Someday, perhaps, for me.
Asyx@reddit
Never ever would I want to defend Python (I make my money with Python. If there's one language I legit can complain about, it's Python) but Python is neither modern nor statically types.
The whole point of the internet boom languages was that they don't do static typing. They "just work". Type hints are a later addition because we realized how shit of an idea that was. And they are not even a type system because they are completely ignored by anything but tooling. You can say this function has a signature of
foo(bar: Baz[Bat])
but if I call it likefoo("go fuck yourself") # type: ignore
there's nothing you can do and your tooling won't bitch about it either.Go on the other hand is certainly more modern than Python and has static typing and I feel like we can expect a bit more then.
meneldal2@reddit
What makes python great is how many packages that do a lot of stuff that is a pain to implement yourself in other language but at the same time it's also the worst part of the language, because so many packages suck and don7t play nicely.
syklemil@reddit
I'm kinda just happy we can annotate types in Python at all these days.
Plus I feel like if I'm seriously limited by its type system, maybe the program shouldn't be in Python in the first place.
aholmes0@reddit
I agree on all points, and would like to add that nothing should ever be in Python. I'm tired of it. :)
shevy-java@reddit
Guess all those python devs having put python on #1 on TIOBE must be wrong then ...
aholmes0@reddit
In addition to u/syklemil's point - and I'm sure you know this as well - opinions aren't wrong or right, and what's popular or not (TIOBE aside) doesn't make something wrong or right. My personal opinions about Python are not wrong because someone has different opinions.
syklemil@reddit
Yeah, there's a good amount of de gustibus non est disputandum when it comes to programming languages too. Bryan Cantrill has a talk where he gets into platform as a reflection of values, which might be of interest.
And I think we generally as adults should be fine with the concept that other people have different opinions from us, without either of us really being right or wrong, and keep that kinda separate from technical arguments.
To use cooking as a metaphor, while there's no discussing taste, we can discuss skill and whether the cook achieved their goal. I might prefer wholegrain sourdough, you might prefer a classic baguette, but none of us prefer a burnt mess or an underbaked bread that's still mostly dough. And ask questions like "why is there jelly beans in this bread?" There might be a good answer and someone might love bread baked with jelly beans, but for most of us, it's just surprising and weird and we have questions.
aholmes0@reddit
Word.
syklemil@reddit
TIOBE essentially ranks language SEO. You know this.
It's an essentially useless metric for everything else, unless you honestly believe that languages like Scratch and FORTRAN actually shoot up into the top 10 of programming languages one month just to dip down again the next, and all just because there were more search hits for them that month.
dual__88@reddit
The trade-off there is higher compilation times. See rust
Aromatic_Lab_9405@reddit
Why is that an issue ? I use scala which is probably one of the "slowest compiling" languages. But it's rarely relevant, we have incremental compilation so the devloop is fast. The build takes some time ( like 3-4 minutes), but our tests take a longer time anyway (20minutes) , and the jvm is fast as fuck so i doubt overall build times would be lower in any other language with the same amount of tests anyway.
Bananenkot@reddit
The type system is not what makes these comp times long, it's llvm
dual__88@reddit
A bunch of languages use llvm, yet rust is the one with high compilation times.
crazyeddie123@reddit
It's a whole bunch of little things, and the team has been chipping away at it for years.
Maybe-monad@reddit
There's no excuse for lack of monads in a modern language
Nekuromento@reddit (OP)
You can do monads in Go: https://github.com/samber/mo Its just going to be extremely painful to use defeating the purpose mostly. Some sugar syntax would be useful but Go needs so much more then do-notation to be ergonomic
ammonium_bot@reddit
Hi, did you mean to say "more than"?
Explanation: If you didn't mean 'more than' you might have forgotten a comma.
Sorry if I made a mistake! Please let me know if I did. Have a great day!
Statistics
^^I'm ^^a ^^bot ^^that ^^corrects ^^grammar/spelling ^^mistakes. ^^PM ^^me ^^if ^^I'm ^^wrong ^^or ^^if ^^you ^^have ^^any ^^suggestions.
^^Github
^^Reply ^^STOP ^^to ^^this ^^comment ^^to ^^stop ^^receiving ^^corrections.
venir_dev@reddit
good bot
ammonium_bot@reddit
Thank you!
Good bot count: 1291
Bad bot count: 460
syklemil@reddit
You can also get ad-hoc monadic behaviour in Go. Pike does this in the Errors are values blog post, where he winds up with what is pretty much an invisible
do
-block inwhich is essentially analogous to the following pseudo-Haskell:
Though I think if Haskell has shown us anything, it is that getting arbitrary programmers to write monads rather than just use them is, uh, optimistic.
Nekuromento@reddit (OP)
I think this example is actually illustrative of Go's biggest annoyance for me - Go code is like playdough-like instead of lego-like. Everything is solved by smudging more code on top. You just keep on growing this ball of one-off solutions. Not composable, not reusable and solves no problems other then language inconvenience.
To me this example is just so profoundly sad.
syklemil@reddit
I think for me it's just one more of Go's inconsistencies, and the authors' unfamiliarity with other languages and programming language theory.
As in, part of the controversy around adding something like
?
to cut down on the incessantif err != nil
was that the idea of an invisible return rubbed a lot of people the wrong way. But they've also lived for I don't know how long with alog
statement that shuts the entire program down, and then Pike shows on the language blog how to invisibly turn an object inert and pretty much write what would be?
-code in Rust, only with the?
and not-yet-stabilisedtry
made invisible, as inAt some point the spiel about Go being explicit comes across as a case of an informed attribute, as in, if they repeat the statement often enough, people start to believe it.
k1v1uq@reddit
Monoids combine values.
Monads combine computations (Effects).
But monads can't be directly combined with other monads, which is why techniques like monad transformers, free monads, and other category-theoretic constructs have been developed.
But these approaches introduce their own set of problems.
Monads are elegant in theory, but they often underdeliver in practical, real-world code.
This is still an active area of research. Martin Odersky’s Caprese project, for example, is exploring ways to handle effects through capabilities.
Maybe-monad@reddit
Monads are monoids
k1v1uq@reddit
Yes, monads are monoids, but in a different category: the category of endofunctors :)
In plain terms, monads let you combine computations.
MaraschinoPanda@reddit
I mean, Rust doesn't have monads and most people agree it's a pretty well-designed language. Monads are actually pretty tricky to incorporate in a type system because they require higher-kinded types.
shevy-java@reddit
What are monads?
MaraschinoPanda@reddit
A monad is a type constructor
m
with a particular interface:pure
which takes a value of typea
and returns a value of typem a
flat_map
which takes a value of typem a
and a function froma
tom b
, and produces a value of typem b
This is pretty abstract, so it's usually taught using examples. A list is a type of monad, where
pure
corresponds to taking some value and wrapping it in a list (i.e.pure("foo")
produces the list["foo"]
), andflat_map
corresponds to applying the given function to each element of a list and then flattening the result.Explaining what a monad is has kind of been done to death online, and you''ll surely find a more comprehensive explanation by googling it, so I won't rehash it all here. Suffice it to say, monads are a pretty common abstraction in programming if you go looking for them.
devraj7@reddit
If you try to explain monads with Haskell syntax, you've already lost.
If the person asking the question already knows Haskell, they already understand monads.
MaraschinoPanda@reddit
I probably should have put m, though that syntax is also not universal. But to be honest I wasn't really trying to teach, just give a definition. I don't claim to know a good way to teach a beginner what a monad is.
wintrmt3@reddit
just a monoid in the category of endofunctors
AdvancedSandwiches@reddit
Operator overloading for people who use functional languages so they never learned why operator overloading is bad.
Just kidding. They're a prank Haskell users play on others. They made up a thing called "monads", which don't exist, and they compete to see who can keep the victim reading a word salad "explanation" the longest.
dlsspy@reddit
This may help: http://dustin.sallings.org/2021/06/23/monads-are-tedious-in-go.html
shevy-java@reddit
Some languages don't have a type system. :)
sccrstud92@reddit
All languages have a type system. Some of those type systems have more than one type.
zackel_flac@reddit
As Stroustrup said, there are two kinds of languages: those we complain about and those we don't use.
The Golang team made some bold decisions, and time proved them right IMHO. Git as a first class citizen was the right choice. Package management is simple, lots of tooling like race tracer & pprof as part of the core language. Code that reads well, even 10 years later. Async done right with clean concepts like Goroutines and channels. Cross compilation is easy as hell, and great C interoperability.
Honestly this language just feels right, and it continues to evolve.
starlevel01@reddit
Out of all the thought-terminating cliches people with nothing to say use, this is one of the more irritating ones. Just because people use it doesn't mean it's not bad.
Slices.
zackel_flac@reddit
Please elaborate, it's one of the greatest feature of go IMHO.
nulld3v@reddit
foo = append(foo, "bar")
Why not just:
foo.append("bar")
? Orappend(foo, "bar")
?Of course I understand the reasoning the authors give:
But 99% of users don't care about whether the underlying slice gets re-allocated or not, so I don't see the value in making all those users use an append function that behaves so unintuitively.
zackel_flac@reddit
That's where I disagree, this is what makes Go powerful in terms of performance. If you don't want to care about memory, there are tons of languages out there for that already, like python.
I mean, Golang embraces pointers like C before it. This is done to give more freedom and more performance to developers.
Despite what people tend to say, Golang is a system programming language. Yes it has a GC, so does D, so did C++ until they removed it a couple of years ago. GC is not incompatible with performance and memory management, quite the contrary, playing alongside the GC can improve performance big time in many scenarios.
nulld3v@reddit
The reason I don't consider Go to be a "systems programming language" is because the language and runtime are notoriously opaque. The runtime hides goroutine IDs, and does not offer "goroutine-local" variables. The user has very little control over allocation: there is no way to force a value to be stack-allocated.
Anyways, even if I accept your notion that Go is a systems programming language, the API design here still does not make sense. I am not saying Go can't expose a low-level
append
function. I am saying that the defaultappend
function is too low-level because the vast majority of users do not care about the low-level details.zackel_flac@reddit
How so? The whole source code is available. You even have projects like tinygo where people wrote their own runtime specifically targeting Arduino and embedded devices.
Fair enough, maybe Goroutine_local will appear one day, who knows. The language keeps evolving.
There are a lot of ways to control allocations. That's one of the strengths of Go. If something is not stack allocable, it's because there is a valid reason behind the scene. Stack/heap is usually a false problem anyway. Having huge stack can be a problem, especially for async. If you need to reduce allocation, you can simply use Pools, statically allocate or request buffers to be provided by the caller (who declares them on stack). Those details can't be done in JS nor Python for instance, nor Java.
That's your opinion. Having low level constructs allows you to create higher level ones from them. However the reverse is not possible, so to me, it makes sense to have them as low as possible.
nulld3v@reddit
I meant from an API perspective. Every language's runtime is open source... Being open source is the absolute bare minimum.
IDK about Python (I don't like the language anyways), and JS is indeed not a systems programming language, nor is it well designed. But Java absolutely has the exact same, if not stronger support for allocation control. Pools and buffers are very common, and obviously you can do static allocation too. Heap vs stack allocation behaviour is well defined, and simple to understand.
That's why Java is so popular at HFT shops. HFT devs often wrote zero-allocation Java, and paired it with some off-heap data structures (e.g. Chronicle Queue). And they did all this before modern Java added value-types (that finally gave devs absolute control over stack/heap allocation). And also why 3 billion devices ran Java.
However, the language designers made a devastating mistake early in the language's design process: Java's "slice"-ish equivalent, "ArrayList", had no generics. You can put anything in a Go slice: an int, a struct, a pointer, etc... Java's ArrayList can only hold pointers. You can't get an ArrayList of objects. Instead, you have to create a ton of individual objects, get all their pointers, and store those in the ArrayList. Similar "pointers only" mistakes were made in other areas of the language (e.g. they later added generics, but only allowed pointers in generics 🤦). This absolutely crushed Java performance and memory usage, and doomed the language.
I always, always support exposing more low-level language internals (again, one of the reasons I dislike Go is because it doesn't). I just don't want it as the default behavior when it doesn't make sense.
But yeah, it is just my opinion. And it's no dealbreaker either. IDK who is downvoting you, you are clearly arguing in good faith so I don't think it's fair to downvote you.
zackel_flac@reddit
I had no idea the Java ArrayList used to be with no generics, must have been a very old implementation!
Fair enough, personally I am happy with the way the runtime behaves, especially around GC control, things have improved a lot in the past couple of years. It had its issue initially for sure.
We are two :-)
Not sure how it differs from most languages. The big issue with Java is that every object has to be heap allocated, since pretty much everything is a pointer under the hood (for objects anyway). Which is indeed a bad thing performance-wise and that's where Golang shines (as well as other languages). The other big issue is the JVM. While it was a great idea in the 00s, it's also an annoying extra layer you have to deal with. Something like WASM ought to make the JVM completely useless, but I'm not sure when the shift will happen.
Yep, and this is possible in Golang with special care, especially when you start mingling with the unsafe package. That's one thing that annoys me with GC's haters. They often don't realize the cost of heap allocation still exists even without a GC. If you spend your time freeing and allocating all the time, your performance will be crap. So pleasing the GC is actuallynis a better exercise than doing things manually.
Well thank you, I am indeed not trolling here. I actually worked for decades in C++ and did a fair share of Java & Rust development. I used to be a Rust pusher for a decade. I only discovered Golang recently (5y ago) and over time just noticed how I preferred coding in it when I had the occasion. It actually rekindled my love for coding as a hobby.
jug6ernaut@reddit
I hate this quote so much. It’s basically “idc what you just said, lots ppl use the language”. How is that conducive to any conversation.
manifoldjava@reddit
Right.
And, if we're honest about Go, we should acknowledge its current user base was not gained on its own merit. If not produced by Google, it likely would have fallen flat -- there is nothing remarkably good about it to account for its traction.
zackel_flac@reddit
Docker is amongst the most successful tools done in Go and is outside Google's hands
hissing-noise@reddit
Yeah, but image someone else (not Google or top 10 IT companies in money) had released golang in 2009. They would be laughed from the face of the earth.
zackel_flac@reddit
With Ken Thompson and Rob Pike behind it? I think a lot of people have huge respect for Ken's contribution to the world in general, google or not.
hissing-noise@reddit
That would be basically the same problem. Appeal to authority. /u/manifoldjava s point still stands. If produced by some nobodies, everyone would have had a good laugh + delete session.
Same with Dart, by the way. It's ok now, but starting out as coffeescript-clone and adding static typing in two painful steps after TypeScript became a thing was absolutely ridiculous.
jug6ernaut@reddit
Yeah I think golang is definitely successful. In the realm of languages that can compile down to a single executable but they are also user friendly there hasn’t been a lot of competition tho until recent years.
I think Discord ended up replacing their golang code eventually didn’t they? (Almost certainly not all of it, but I remember reading they ended up replacing one of their more important services, maybe chat presence?)
zackel_flac@reddit
From what I recall they optimized part of it in Rust, but I don't know how successful this was. This was before the Golang team added GC configuration options, they were hitting some GC issues and most likely this would be solved nowadays.
hissing-noise@reddit
It's like some verbal form of that Mister Gotcha meme. And so is that XKCD comic.
florinp@reddit
"As Stroustrup said, there are two kinds of languages: those we complain about and those we don't use."
I can play a game: every time a bad language is discussed I can bet I find this quote in the comments.
Can we put this to rest and acknowledge the bad designs/decisions?
"Honestly this language just feels right, nothing overly complex to remember, you can focus on delivering features, and easily maintain the whole. It's hard to switch to something else after that one."
I think you are not accustomed with a well designed language that use the types to advantages.
E.Q : using monads compositions when you can pretend that exceptions/error don't exist and you can write only util code. Now that's easy to read and full type safe.
Gorutines? Clean concept ? Can you compose them ?
zackel_flac@reddit
If you can't recognize there is no perfect language out there and they all come with tradeoffs, then you have not worked in this field long enough.
There is no absolute good of bad things in life, even truer in engineering.
florinp@reddit
Correct: I have only 31 years of experience.
P.S. "ze there is no perfect language out there and they all come with tradeoffs, "Please specify where in my reply I've said anything about perfect language ?
zackel_flac@reddit
When you call me & others out for using Stroustrup's quote. Because that's all this dude is saying here. No matter how good things (languages specifically) are, they will always be reasons to dislike them. All I am adding is, that's because the world of engineering is full of tradeoffs. You surely know that by now after 31 years in the field.
florinp@reddit
I can agree with this.
fanglesscyclone@reddit
Brainfuck would obviously be a terrible language to use in production if you’re a HFT firm. If you worked in the field long enough then you know there are clearly many contexts in which certain languages or tooling is just bad, because better alternatives exist.
e-tron@reddit
If you worked in the field long enough then you know there are clearly many contexts in which certain languages or tooling is just bad, because better alternatives exist.
<-- you miss the availability of resources (within the budget) able to work on that, the tool doesn't have to be the "better" language than X, but just better enough, not the best.
florinp@reddit
Oh: yes. The lie we tell : never the best: good is enough.
But good enough is absolute, yet every programmer to use "good enough" think about themself.
Almost always this expression is an excuse for programmers the justify their lack of progress.
e-tron@reddit
> then you have not worked in this field long enough
true this.
florinp@reddit
yes: but no.
e-tron@reddit
> Honestly this language just feels right, nothing overly complex to remember, you can focus on delivering features
Exactly this one, So that you can focus on "business" complexity and even if lets say someone uses "X" language, all uses a tiny subset of it not most of the features it offers.
florinp@reddit
No: The complexity don't disappear. If is removed from language it will go in the user code.
Incorrect. For example a language like Go will pollute the code instead of business logic with checking error codes at each line.
compare this with:
e-tron@reddit
magic
Maybe-monad@reddit
real magic
lturtsamuel@reddit
The two boldest decision are no generic and the error handling
Now they have to painfully add generic back
And now they're still debating how to fix the error handling, with little consensus. The only consensus is that the current way sucks.
fungussa@reddit
Not at all. Genetics were deliberately excluded because if they were going to be done at all they had to be done right. Which is quite a contrast to other languages that take the approach: "let's throw generics in and see how it goes".
florinp@reddit
Oh. yes. pity that generics were not invented yet when Go was created /s
Or that we didn't had examples with languages that added generics later and the problems that situation generate /s
fungussa@reddit
Why are you pretending to know the history and complexity of language design decisions, just because "you've heard about generics before"?
The issue with Go's genetics are trivial, yet you're languages are coffee likely have some atrocious design decisions. Go had very few.
YW.
florinp@reddit
What are you talking about ?
Generics (parametric polymorphism ) is a solved solution. Care to give example what prevented Go to insert them at first release?
So your personal opinion can be used as fact ? Care to give example of atrocious designs in other languages ? You can begin with Haskell (or Scala, Idris , etc.)
The whole reply of yours is in fact:
lturtsamuel@reddit
And that doesn't end well. The generic syntax ends up to be inconsistent with the native generics such as maps
fungussa@reddit
Go makes you write K comparable in generics even if you’re using K as a map key - and yes, that feels redundant. But it’s by design: Go doesn't infer constraints from usage. You have to state them explicitly so the function's contract is always clear. Maps require comparable keys, but generics don’t automatically pick that up, because Go avoids hidden constraints. It’s a deliberate choice to keep things simple, predictable and easy to reason about
Ok-Scheme-913@reddit
If you have different rules for one part than another, then it's by definition more complex. On top, this is accidental complexity that shouldn't be there if they didn't fuck up.
Especially that map itself is a compiler-supported abstraction that couldn't be written in the language itself which again, just bad.
fungussa@reddit
You say that, yet parts of rust are an utter abomination. Why did they make such a mess?
jug6ernaut@reddit
Everything within the language is by design, that doesn’t mean the design doesn’t have problems.
fungussa@reddit
ALL languages have problems.
indearthorinexcess@reddit
well they didn't do them right because they tank your code's performance
zackel_flac@reddit
Error handling sucks in all languages. Because it goes against the normal flow. Exception is crap, errno is too easy to forget, and let's not even mention the horrendous ? which does not work when writing lambdas.
Personally I have done enough PR reviews in my career to appreciate explicit and repetitive error handling in Go. Readability is harder than writing code, if a dev has to add 3 lines instead of 1 to help the readers, I am all for that.
crazyeddie123@reddit
Of course ? works when writing lambdas. You just have to write a lambda that returns a Result.
AceSkillz@reddit
Maybe there's some specific context you're thinking of for '?', but so long as the return type of the lambda/closure implements 'Try' (which tbf is still unstable/language internal) aka Result or Option it works. And those are the two types you use '?' on outside closures anyway.
I can sort of understand if you were working with some interface that required a specific return type, but most of the Rust std lib code is generic over closure return types (I'm thinking of 'map' etc).
balefrost@reddit
Sure, but it sucks more in Go than in some other languages.
Exceptions aren't perfect but they have worked well in practice in several languages for decades. I don't see how the
if (err != nil) return err
boilerplate is any better.Indeed. And as someone who has also done many code reviews in my career, I find Go's need for constant error handling boilerplate to hinder readability. It serves to obfuscate the places where special error handling is occurring.
While I can understand a desire for error handling to be explicit, I do not understand the desire for error handling to be verbose. That just serves to lower the signal-to-noise ratio of the code.
zackel_flac@reddit
6 months down the line you now need to capture metrics when this error occurs. Now you can simply slip a one liner. Same with prints when you need to debug some logic.
Try to do the same in Rust, you have to rework a whole lot of your code if you use a
map_err
for instance.balefrost@reddit
Sure. On the other hand, I had to pay the cost that whole time to put the boilerplate in my codebase. I'm paying a cost up-front for a benefit that I might, one day, realize.
On the other hand, it's easy to take a single statement or even a block of code in Java, wrap it in a
try/catch
, and add whatever logging or stats tracking I want. It's usually a very easy refactor, but I pay the cost only when - and if - I need specialized error handling.I can't speak to Rust, since I don't use it.
Sure, I get what you mean. And I like Go's use of the term "panic". I think it implies the thing that exceptions should generally be used for - an unexpected condition that occurred at runtime.
But I think Java's checked exceptions are a good alternative to Go's
error
. Checked exceptions also indicate that something is expected to fail in a way that you would want to recover, but isn't a unitype and can more easily carry payload data (correct me if I'm wrong, buterror
can only carry a string plus other, wrapped error objects). Checked exceptions were a bad implementation of a decent idea.zackel_flac@reddit
I am not sure why you keep calling this a boilerplate. It's a clear signal that shows where a code branches out. It holds extra value. Boilerplate is pure code that is useless in terms of semantics, and is just there to please the compiler.
For instance, you could ignore an error, then the intent is clear: no return, and you can either proceed or retry, or whatever the way you need to handle it. The problem is an exception is that they will crash you at runtime out of the blue, because they are not part of the API of function. That's the main issue with them. An error in Go is part of your API contract. It's more explicit and you can make a conscious decision whether to handle the error, ignore it or simply propagate it.
balefrost@reddit
Boilerplate is anything that is repeated over and over without any significant difference between the repetitions.
I claim that
if foo, err := bar(); err != nil { return err }
is boilerplate because it occurs over and over again in any nontrivial Go codebase.In some cases, you can eliminate that boilerplate via refactoring - by extracting helper functions, for example. In Go, there's effectively no way to remove the boilerplate in the general case by refactoring. You might be able to use ad-hoc solutions in specific circumstances.
I would argue that the example code snippet above doesn't have much semantic meaning. It's such a strong idiom that you just sort of start to recognize it as "propagate the error up".
That's not entirely true. In Java, checked exceptions are part of the function signature, and the compiler ensures that you handle them.
But the only thing that the contract in Go says is "any error might occur". If the specific error matters, you still need to document what errors can occur and under what circumstances they can occur.
Again, Java's checked exceptions allow you to say "any of these errors can occur, but no unlisted checked exception will occur". That's not entirely true, since the JVM doesn't really distinguish and other JVM languages aren't as strict as Java. You still need to document when they can occur (though
FileNotFoundException
is pretty self-explanatory).I'm not saying that checked exceptions are perfect - they could be better. My point is that the things you like about Go's error handling can also be achieved with exceptions.
I'm not even arguing that exceptions are inherently better than error values. I'm not opposed to explicit error propagation. But I do find that Go's verbosity around the common error handling case just ends up hurting readability by reducing the signal-to-noise ratio. It's harder to see what's happening because so much of my field of view is taken up by the same, repetitive code pattern.
MighMoS@reddit
Exceptions suck because they're an unsolveable problem.
Code can throw while handling an exception, whether that be destructors, IDispsoable, defer, take your pick of what language you're in... This results in badness.
You can't read a block of code and tell what errors can be generated, or what can generate an error:
foo = getFoo()
. Does getFoo return null on failure, or does it throw? There's no way to tell reading from the calling code.Exceptions rule because you can defer (no pun intended) error handling to someone who can deal with the error. This is awesome when you've written the whole stack yourself and have thought about it. Exceptions suck because this is practically
goto
on steroids.Exceptions rule because they can include stack information. Exceptions suck because either you leak this information in prod, or disable it in prod, meaning its useless.
Exceptions are the coolest strategy of error handling that almost works.
balefrost@reddit
I do think like most if not all of your criticisms of exceptions also apply to Go's error handling.
Like if you view
defer
as analogous tofinally
, you can end up in the same "error handling code can itself generate an error". And you have the same problem - should the error within thedefer
function take precedence, or should the original error (if any) be propagated?Java solved this by allowing you to attach "suppressed" exceptions to any other exception. This is different than exception wrapping, which is a causal relationship. Exception suppressing is a way to pick one exception as "dominant" but still include the other exception as the stack is unwound.
I hear this complaint a lot. But I spent almost 20 years working in exception-heavy languages, and they never seemed that hard to reason about. Most of the time you let them propagate up, you put
catch
backstops at strategic places where error recovery makes sense, and you occasionally need something more sophisticated.They're a
goto
, but they're a structuredgoto
. I'd instead call them abreak
on steroids.florinp@reddit
No. Not more than error codes.
There are only 2 correct ways to deal with exceptions (that I know off) : Exceptions and Error Types via Monads.
Error codes were invented because that is all you can do in C. Not because are a good solution.
That depends on the user. For me error codes are horrible in the terms of readability. In plus are a beautiful way to generate bugs.
zackel_flac@reddit
Errors in Go have their own type. It's not error code based.
That being said, error code is fine as long as the documentation is properly done. Like for HTTP protocol, it's clean enough IMO.
florinp@reddit
It is. And one of the big problems with it is that is not enforceable. Beside others.
I can write a huge paper with all the problems of error codes
KagakuNinja@reddit
The fundamental problem with Go error handling is that they are returning a generic tuple on the stack, but that type is not expressible in the language.
Think about that for a minute. They have destroyed the core principle of functional programming. You cannot pass the output of one function to the input of another without adding boiler-plate code.
You say that "Exception is crap". Go of course has exceptions. They call them panics and restrict their use. Since runtime exceptions are inesacapable, any modsern language should simply support exceptions, although perhaps not as the primary mechanism for error handling.
The best alternative to exceptions is of course what everyone here is talking about: sum types, also not supported in Go.
zackel_flac@reddit
Which is precisely what Go does. You can recover/catch a panic with
recover()
. So yes, exceptions are there in Go, just not for everything like Java/C++.As mentioned above, they are not silver bullets. Look at Rust for a sec, there are at least 6-7 ways to deal with errors. This adds a huge burden to the readers. Sure it's fun to code, but coding is not all about writing.
Yep, and this is what I personally dislike about functional programming. It's damn hard to know where things branch out. Again in practice, being explicit is a good thing. I don't see it as a boilerplate at all, a branching is a flow indication and it's extremely valuable when debugging.
valarauca14@reddit
Everything is
Result<T,E>
.Now I will grant you
Result<T,E>
is a concrete type you an choose to build abstractions around, which lets people go wild.In my experience most sane rust code bases just do
?
or.map_err(|e| /*reformat error message*/)?
.zackel_flac@reddit
I was talking about handling it. You can return like, do ? (which does not work in lambdas), do map, do "if let", do "let else", do match and probably some other ways I missed. Oh yes our dear
unwrap
which invalidates Rust big claims of never crashing.valarauca14@reddit
Yes, yes, navel gazing such minor details is a good excuse to avoid productivity.
zackel_flac@reddit
We spend most of our time reading code, at least when working on a product that is actually used in production. Those are not small minor details, they are core to the fact they hinder reading and reviewing.
If code review is a minor detail to you, you probably are working on prtoduct with no critical mass.
valarauca14@reddit
???
If somebody reviews the code is really easy to say, "Hey why are doing a bunch of unnecessary crap with an error code". Or have a linter automate this and enforce org wide styling.
Your complaint assumes these don't happen or work, which is weird as most organization require this.
Halkcyon@reddit
Yes it does.
?
means "returnErr
early". That's it.zackel_flac@reddit
It does not work in a closure/lambda, as the compiler thinks you are returning from the scope where you define your lambda. But this is not my point, my point is about having 7 ways to achieve the same control flow is too much.
Prior to Rust 1.0 the motto was: do it one way and do it right. We have stray too far from that unfortunately.
Halkcyon@reddit
Is a generic type*
lturtsamuel@reddit
And what are those? Do you mean the various methods on the Result type? Or different libraries to do error handling?
Either way, each of these methods/libraries has well defined behaviour, and you don't have to use them unless you have to. On the other hand, with go's
if err != nil {}
you can write anything in that if statement and body. You can do a simple check and return just like?
in rust, and you can have arbitrary logic, just like what you will do in rust. The difference is that there's no utility finctions/libraries to help you with these arbitrary logic.zackel_flac@reddit
I meant the way to handle a
Result
: match, if let, let else, ?, map (and it's multiple variations), plain return & unwrap.Too much expressivity hurts readability IMHO. You are less prone to see logical issues as you can misread things more easily. The funniest thing I ever saw was something like:
bloo().map(|&foo|foo(bar??)??)?
And yes, the writer of this hellish line was a junior, but the fact you can end up in such a mess is really not good.vlakreeh@reddit
I'm not sure what you're getting at here. Are you talking about Rust's try operator and them not working inside closures? I don't get to write much Rust anymore but I badly miss it when I write Go or some other exception-based language.
zackel_flac@reddit
Yup that's what I referred to. My point being there are too many ways to achieve the same thing, and sometimes it does not work because the syntax is ambiguous.
Writing in Rust is fine. Reading is another task which I despise personally.
vlakreeh@reddit
Disagree the readability opinion but I do get where you’re coming from, if you aren’t that familiar with rust it is very confusing. One clarification is that the try operator does work in lambdas (called closures in rust) but they require you to explicitly declare the return type.
zackel_flac@reddit
FYI I worked with Rust non stop for a couple of years (3 to be precise) and C++ for 10y+ prior to it. But I also worked in a team, and the bad time I had was not writing code, it was reading other people's buggy code. It does not help that I was working on kernel related stuff, so unsafe all over the place, meaning we were benefitting very little from rust. For me this was a wake up call, it ended up being too close to C++ in terms of complexity.
I also used Ocaml a lot in the past, but I could never get used to ML syntax, it just does not feel right for me. I like seeing how my code translates into assembly right away. I understand that people like it, but for me it just gets in the way of my creativity. Everyone functions differently I guess.
syklemil@reddit
Nah, that was settled as a WONTFIX:
with a suggestion to use LLMs to write the error handling and IDEs to hide the result:
Cruuncher@reddit
This is the funniest response to a language flaw ever lol.
Yeah you have to write repetitive shit, but let's just rely on external tooling to help with that!
Or, use a reasonable language? 🤷♀️
SweetBabyAlaska@reddit
its purely a Golang team problem. There was an extensive discussion about trying a ton of different things here to make things smoother, there were a TON of people who stepped up and brought demos of their ideas. But the Go team said "no" because there was no overwhelming consensus on one way, which is a failure of leadership imo.
just copying the "try" statement from Zig and returning the empty/nil value plus the error as an optional would be a massive improvement.
Ok-Scheme-913@reddit
Hmm, maybe create some different syntax for better error handling, and we could create a program that takes that different syntax and write out all the if err boilerplate for us!
Hmm, maybe we could then fix a bunch of other errors of go as well, and instead tell this program to produce machine code, instead of go code! What an idea!
Cruuncher@reddit
Hmm, a transpiled golang with exception semantics... 👀
I could get behind that
syklemil@reddit
Yeah, I get that they don't want to add compiler complexity, but uh, last I checked LLMs were kinda complex and resource-hungry and all that. Maybe they're hoping that the users will use an LLM that earns Google some money?
valarauca14@reddit
Halkcyon@reddit
"Just use Gemini to write your Go code—easy!"
Kapps@reddit
If that’s your takeaway, you don’t understand the article or the language.
Which come to think of it is most replies in this thread.
florinp@reddit
LOL. let's design a bad language and rely to code completion.
The same error like in Java: because 80% of coding time is to write get/set let;s rely on IDE. Why design properties or immutable attributes ?
lturtsamuel@reddit
I hope I can tell this to customers when they complain about our product's lack of usability LOL
trialbaloon@reddit
My dishwasher sometimes wont wash every dish. The manufacturer told me to buy a robot to hand wash the remaining dishes....
GregBahm@reddit
Hu. "Bold" is right I guess.
Xenasis@reddit
I don't think this is consensus at all. I like the current error handling, and greatly prefer it to try/catch.
florinp@reddit
you don't put try/catch on every level. Usually is enough once on the higher level
jug6ernaut@reddit
If only there weren’t better ways to handle errors than try catch.
balefrost@reddit
I respect your opinion, but for me, it's almost the exact opposite. To me, Go feels awkward and strange. It's like it was designed to do the same thing as other languages, but always in some subtly different way.
For one example, Golang supports object-oriented programming, and even (via type embedding) has something that looks an awful lot like implementation inheritance. But then it doesn't quite provide the same affordances as other OO languages, and so there are things that you feel like you should be able to do, but can't.
I'll admit that familiarity matters. If I had learned Go first, then maybe I would view other languages as "weird". But in this case, Go entered into an existing language landscape. I've only written a little Go - I've written a little at home and I occasionally need to maintain a tool at work written in Go. But my limited experience with the language doesn't entice me to use it more often.
CobaltVale@reddit
Classic.
It's not supposed to be enticing it's supposed to be consistent and dependable.
balefrost@reddit
Sure, but I have "consistent" and "dependable" in a half-dozen other languages already. And Go seems to require me to jump through hoops that I don't need to jump through in other languages.
There are some specific reasons that I might choose Go. But for general use, I don't see any reason to pick it over Kotlin, C#, or even Java.
CobaltVale@reddit
Really? Like what? Not even Rust counts here due to its absurdly powerful macro's. Java and C# have several different "dialects", which all work even within the same codebase.
I know exactly what I'm getting when I hope into a Go repo. There isn't a Go project I can't just hop into and immediately understand it.
And then I can cross compile it, no fuss. No worries about what may or may not be supported on different platforms (lol @ .NET on linux)
In my pretty long experience in this field, I can't say I've had many other stacks do that for me.
balefrost@reddit
What are you referring to? Though both languages have evolved over time, there aren't independent dialects.
Surely that depends less on the language and more on the problem domain.
Like I can understand the argument that "the simplicity of the Go language makes code more approachable and readable". I don't know that I agree with that (I think Go's error handling approach leads to low signal-to-noise), but I can at least understand that argument.
But even if that's true - even if Go is inherently easier to read than Java - I don't think it has that much of an effect. A tricky algorithm is tricky no matter what language you write it in, and most of your time is going to be spent understanding how the algorithm works, not in trying to understand what the code even means.
People can write clean code or sloppy code in any language. I've certainly encountered sloppy Go code that is hard to navigate and hard to see how data flows around.
CobaltVale@reddit
They have multiple different ways of implementing the same thing that goes beyond synaptic sugar and will cause the compiler, and therefore, the underlying implementation to differ radically in performance, security, and stability. LINQ, Tuples, Pattern matching, reflection, attributes, TPL (lol), streams/lambda expressions, annotations, SpEL -- oh and have fun figuring out a standard project structure that works across teams let alone companies. These things are standard but released across different versions of these language specifications/runtimes and code bases will use one feature, then suddenly another, and then different teams will use these types of features in different ways causing a mess of dialects and accents.
This is not true for 99% of code bases. Even in deeply niche, technical domains the majority of code is not around some (even novel) algorithm. The majority of code is read and the majority of code is "platform" code. In any code base.
What are you basing this statement off of? It seems inexperienced.
Care to share? This is a bit difficult of a claim to believe considering Go does not leave you with many options, as designed.
balefrost@reddit
I have more than 20 years of experience. I worked at an aerospace company for about 10 years, and I currently work at a FAANG writing software in the networking domain. I've been paid to write code in at least 6 different languages, and I've dabbled in many more.
There are certainly some languages that are harder to grok than others. If you're not already familiar with Prolog, it can be hard to understand what a Prolog program is doing. Its execution model is so different from mainstream languages that it feels alien. Lisp and Haskell can also feel strange, though that's mostly due to the particular shorthand identifiers (e.g.
car
) and operators (e.g.<$>
) that they use.Most languages that derive from C are similar enough that you can typically look at the code and understand what it is trying to do. Sure, there are nuances in each language. Go has fewer nuances than C++. I'd agree that Go is easier to read at baseline.
But I don't think that's the hard part of grokking code. Every code base of a sufficient level of complexity will introduce its own concepts, idioms, and "way of doing things". Every library that you use has the same. There's domain-specific knowledge that you cannot easily deduce from the code as written but is essential to understand why the code is doing what it is doing.
To me, that's the hard part of reading code.
I cannot share it directly, no.
But when reviewing a change to that Go code, the changelist author had gotten their multiplicity wrong. In their original modeling, every Foo had a collection of Bars, and each Bar specified its own Baz. This didn't actually match the real system, in which the Baz was actually tied to the Foo. That is to say, all the Bars within a Foo shared a single Baz.
I noticed that, pointed it out in review, and we changed it. By more closely tracking reality, we were able to simplify the downstream code - it no longer had to account for a situation that could never occur, by construction. But those are the kinds of things that exist in that codebase and make it difficult to understand.
Such a mistake can be made in any language. Go doesn't - and can't - do anything to help you in that case. Like I say, you can write sloppy code in any language.
CobaltVale@reddit
Yeah but no one said it was impossible or that any language totally stops you from preventing you from doing stupid things.
It's that Go is consistent and it has decided to not add features by design. The language is plainly simple. It's harder to do something stupid or bespoke in Go than it is in other languages.
Even in the eample you gave, there's nothing that Go did or didn't do -- it was a developer/algo/platform mistake.
balefrost@reddit
Right, exactly. This was a relatively small tool, written in a language that's supposed to make it easy for inexperienced devs to write small tools, and yet the developer made this mistake.
My point is that Go's alleged "simplicity" advantage didn't seem to help here. The difficulty here wasn't in reading the code or writing the code, but in understanding what problem we were trying to solve.
You seemed incredulous that somebody could write sloppy code in Go. I gave an example, and you said "well, that's not Go's fault". I agree with you, but it's still sloppy code that was written in Go.
I don't understand the bold part. Surely all code we write is bespoke. If you're writing the same code over and over again, you're missing opportunities for refactoring. If you aren't defining your own concepts and abstractions in your codebase, then your code can't be doing anything particularly complex.
I am not trying to say "I think you are working on trivial problems". Rather, I think I don't understand what you are trying to say.
Right. From my perspective, those omissions make Go an unappealing language.
I'm not saying that "simple" is a bad goal. The problem in my opinion is that Go aimed for "simple" and instead ended up with "minimal". I think that they omitted too many things, and in doing so they missed the original goal of simplicity.
100 things can be simpler than 10 things. If those 10 things interact poorly with each other, but the 100 things are all independent and orthogonal, then the 100 things are almost certainly simpler.
drink_with_me_to_day@reddit
That "something" is called composition
balefrost@reddit
Go's "composition" is more like inheritance than "composition" in traditional OO languages.
I'm specifically talking about type embedding - the special-syntax language feature, not some more colloquial notion of composition. When you embed another type into your type, your type automagically gains all the methods and exported fields from that other type. You might even say that your type "inherits" these from the other type.
drink_with_me_to_day@reddit
Yes, that's what composition does, as well as inheritance
That's why you can switch between them, because both "solve" the same problem, each with some onus/bonus
balefrost@reddit
This is not what people mean by "composition" in most OO languages. In most languages, "composition" does not automatically expose the methods of the composed object. In fact, that's one of the defining differences between composition and inheritance.
drink_with_me_to_day@reddit
What does it expose?
balefrost@reddit
Typically, nothing. Typically, composition is done at the instance level. When you compose one instance into another instance, the surface area of the outer instance doesn't change in any way.
A good example of OO composition is the strategy pattern. In the first diagram on that page, the "Context" object composes the "Strategy" object.
I can maybe provide a concrete example. Suppose you have an array-like collection that keeps its elements sorted. This "sorted" invariant is maintained even if you add or remove items. Maybe this is useful because you will eventually binary search in the collection.
But in what order should the items be sorted? The container class probably shouldn't decide; that should be up to the user of the container.
Maybe the container's constructor could offer a
bool sortAscending
parameter. That gives the user two choices for sort order. But sorting can be more complicated than that. If I'm sorting a collection of complex objects, maybe I want to sort based on one of their subfields. Maybe I want to first sort by one subfield, then break ties using another.Another option is to customize the sort order using inheritance. Create a subclass of the container that overrides some specific method to do whatever sorting you want. But that's makes reuse harder. That sorting strategy could probably be reused in other contexts, but by hanging it off the bottom of the inheritance hierarchy, there's no easy way to reuse it elsewhere.
The "composition" approach is to construct the collection with an instance that represents the desired sorting strategy. That way, the strategy is truly pluggable and reusable.
Note that the sorting strategy itself is never exposed to users of the collection type. It's effectively an implementation detail.
Java's
TreeSet
is an example of what I'm talking about.Comparator
is an interface that represents a way to determine the relative order of two objects. TechnicallyTreeSet
has agetComparator
method, but that's probably not necessary. Strategies don't typically need to be interrogated in this way.In other OO languages, when people talk about composition, this is the sort of thing that they're talking about: assembling a graph of small objects that, together, produce the desired behavior.
zackel_flac@reddit
Curious to hear what you are missing from OOP and inheritance. Inheritance has been a pain for many years, because it's not flexible enough. More fundamentally, it's hard to choose if something should be a method, as adding a method has a big cost in terms of maintainability (you either hack the mother class, or you need to create a whole new one inheriting from it).
Interface/traits offer more flexibility than inheritance, you can define them on the spot when needed. They are almost the same underneath. Inheritance uses vtables while the others use a fat pointer.
balefrost@reddit
Right, which is why I was surprised to learn only recently about type embedding. I knew that Go was fairly against traditional OO. But type embedding seems like it carries most of the same downsides as implementation inheritance. Changes to the embedded type ripple through the apparent surface area of all types which embed it. If you change the signature of a method of an embedded type, that might cause some other type to no longer conform to an interface. And so on and so forth.
Here are some:
Formatter
orGoStringer
interfaces. As long as I get the signature exactly right, it works. If I get the signature slightly wrong, it silently does the wrong thing. My intent is for my type to implement the interface. This is useful information to both readers of the code and to the compiler, to help generate useful error messages. To be clear, I'm not entirely against structural subtyping. But I argue that nominal subtyping is very useful, and its omission is unfortunate.But I mean, I can work around all that. But my point is that other OO languages had more or less converged on a common set of primitives for expressing things. Go appears to support most of the same things, more or less, but does so in an atypical way. Why?
It feels to me like it's trying too hard to be different, just to be different. Like the creators wanted to say "OO is dumb, so we don't do it"... but then end up putting many of the same capabilities, with the same traps, into their language.
Maybe I'm missing some subtlety.
syklemil@reddit
That is pretty much what Pike wrote in that "Perhaps I'm a philistine about types" blog post:
There are numerous issues there IMO, including the bit where Pike seems to think of pretty much anything beyond the capabilities of the C and early Go, including generics, as something relating to inheritance. So it kind of stands to reason that someone with a vague grasp of types and inheritance beyond "inheritance bad" might wind up including something pretty much like inheritance by accident.
balefrost@reddit
One of the things that I like about languages like Java, C#, and even C++ is that a lot of their core functionality is provided by their library. Take, for example, container types like maps. In some languages, they're handled specially by the language. But in Java, C#, and C++, they're just part of the standard library. That means that you can have a variety of containers in the standard library (e.g.
std::unordered_map
vs.std::map
,HashMap
vs.LinkedHashMap
vs.TreeHashMap
) or provided by third parties (e.g.absl::flat_hash_map
). They all "feel" the same - none are second-class citizens.In fact, I view this as a very desirable property of programming language design. Perhaps Lisp is the extreme end of this, where macros let you really blur the line between built-in and provided-by-a-library. Languages like Java, C#, and C++ are obviously not that extreme, but they still get partway there.
syklemil@reddit
Yeah, I think a lot of us also prefer that things stay expressible within the ordinary type system. If someone prides themselves on having few keywords but then go and special case stuff like maps or tuples as something that only exists as syntax, not as ordinary values, then I think we just have different priorities—and different ideas about what the word "simple" means.
devraj7@reddit
This is a pretty typical display of ignorance from Pike where his only decision factor is "I don't feel the need for it" instead of assessing PLT features objectively, taking the time to understand them, their pros and cons, their applicability in multiple scenarios, etc...
syklemil@reddit
Yeah, my interpretation of it is that he starts with "allow me to be rude about that for a minute" and then proceeds to egg his own face.
Unfortunately I do find it to be somewhat of a pattern in the Go community that people are angry and dismissive of things they are ignorant about. But I guess that's a possible outcome if what draws them to Go is that they can be reasonably productive while learning as little as possible.
zackel_flac@reddit
Type embedding is still composition (so no inheritance), but it's a sugar syntax to make things quicker. When you embed you type inside a struct, you can still refer to it as a field because it's just composition under the hood. (Personally I rarely use it as I prefer composition to be explicitly called via named fields)
Hum, I am not following you here. If you pass your struct to a function that takes an interface (which all that matters) then the compiler will complain big time, telling you something is missing.
2) Fair enough, it's indeed not easy, but when is that required? As per 1) call a function with the needed interface and the compiler will start complaining if something is missing, that's all we care about I feel.
3) That is one of the things I love about Go, you have a constructor: all values default to their default value. That's it, dead easy and common across all structs. No surprises of partial struct I itialization like you can have in C++. If your struct requires specific construction, you use an explicite function or you simply don't export it and push your interface at the module level. That's how I code nowadays, I seldom export struct, but I export module-wise functions. This allows for safe singleton and encapsulation across multiple objects. That's the true shift away from OOP here.
4) Yep, and this is what is great as well IMHO. The same way you don't want constructors that bring new logic per type, here everything is copyable, no hidden behavior in disguise. How many times in C++ have you wondered: "is this assignment doing a shallow copy or a deep copy"? In Go you would use an explicit function to achieve that, making things consistent across all code bases, nothing hidden.
5) Hum, let me ask you, how many times did you change a private into public just to please the compiler? Personally this happened a lot. Because it's damn complex to know in advance that you won't need something to be accessed later on. Worse you start adding getter and setter just to be OOP-like. I am going back to the module encapsulation design. If you keep interfaces/API at the module level, then the only thing that matters is whether something escapes your module or not. If you want further encapsulation, just add a new module?
This was the whole point of Go. It was to be a replacement for C++ as the creators did not like the complexity brought by C++ over C (Ken Thompson is a key designer of Go btw). And they achieved that. Not everything brought by OOP is good, like not everything brought by functional programming is good either. Go picks what works and what's good but leaves a lot of superfluous features. Not saying they are all right decisions, but they at least make sense, they are not randomly choosing left and right for the sake of annoying everybody.
balefrost@reddit
There's no inheritance mostly because Go doesn't call its mechanism "inheritance". But the embedding type does magically gain a bunch of methods (and potentially fields) from the embedded type, and these do appear in the embedding type's API surface area. Both semantically and mechanically, it looks a lot like inheritance.
Heck, inheritance in C++ ends up looking a lot like Go's type embedding, at least structurally. In Go, you can refer to the embedded field. In C++, I can take a pointer to the base class. Heck, I can even engage in some good old-fashioned object slicing if I want. It's not exactly the same as in Go, but I think they're more similar than they are different.
I specifically was referring to "optional interfaces" in Go, like
Formatter
andGoStringer
. These are interfaces that are checked at runtime, not at compile time. Those particular interfaces come up in custom string formatting, but they show up in other contexts as well.Optional interfaces aside, being able to say "this struct is meant to implement that interface" is useful information for the reader. The longer I've been doing this, the more valuable I find these sort of "statements of intent".
Typically, when I want to make a change to an interface and need to know what types implement the interface. It's useful when I'm trying to make sense of a new codebase. It's particularly useful in cases where I can't lean on the compiler because I want to make a semantic change, not a structural change, to the interface.
That's just a constructor with extra steps. That is to say, we both agree that there is sometimes a need to have nontrivial initialization. In another language, I'd just add a constructor (which would in turn remove the implicit, default constructor) and I'm done. In Go, you might need to:
I'm not going to hold up C++ as the ideal here. It has inherited too much baggage from C, and it's really annoying that there's a distinction between value-initialization, zero-initialization, and default-initialization. But other OO languages have corrected that mistake. In Java, you get the Go default initialization behavior by default. But you have the option to do something different if it makes sense for your type.
These days? Basically never. In the codebase that I work in, most types are either views (in which case copies are cheap because they don't own anything) or types that own their data (in which case the copy constructor / assignment operator does the right thing, and we often don't need to write any code for that to happen).
For example, if I have a
std::vector
as a field in my class, then when that class is cloned, the vector will be cloned and each element of the vector will, in turn, be cloned. Most custom types get a copy constructor for free, and you only really need to define your own infrequently.Actually, I'd turn the tables on you here. Because Go doesn't allow you to control cloning behavior, and because the default behavior is sometimes incorrect, the user of the Go struct has to be familiar with the field of the struct. They need to know what will happen when the struct is cloned. Does the struct contain only scalar data, in which case the clone truly is a clone? Does it contain pointers, slices, or maps? I would expect that Go users need to think about this all the time.
But note that I didn't say "Go prevents me from writing complex copy constructors". I said "Go doesn't let me prohibit cloning". At least, if I could prevent automatic cloning, I could provide an ordinary method that clones safely. The well-known Mutex footgun in Go is a great example. Mutex is cloneable (because it's just a struct), but a cloned mutex is basically worthless. You always want to capture the mutex by pointer. The language should help you do the right thing, but Go provides no help here.
Very rarely. It probably indicates that some high-level component is trying to micromanage some lower-level component. Or it means that I put an abstraction in between two things that should not have been separated.
I'm not saying that I never do it. But I usually have an idea of how my class fits into the larger picture, and I know what affordances my class should expose to the outside world. If I need to switch something from private to public as a "back door", then my design needs more thought.
If you have plain data in C++, there's nothing wrong with structs. You only need to use
private
when you want to enforce some invariant. And if you want to enforce some invariant, then you do not want people messing with your data.I think your summary here is very good. I think you're right that intent was to try to simplify C++. And I think it's important to look at things in context. Go was initially released in 2009, with development starting in like 2007, and that's all before C++11 was released. C++11 was a huge improvement. Move semantics and smart pointers are fantastic. Most of the time, things "just work".
But even now, it's still an awkward language. I will not hold up C++ as a "good" language.
Java, C#, Go, and others were all responses to the complexity and problems of C++. But, personally, I feel that Go sliced too much off. To me, it's hard to work in Go and not feel like something is missing. I'm shocked that it took them 10 years to add generics. Multiple other languages proved that generics work pretty well. Java added generics in 2004. C# added them in 2005. Maaaybe they were still seen as "unproven" when Go initially started development in 2007. But I am so used to having generics (or C++ templates) that it would be painful to go back to a world without them. So I'm glad they did finally add them.
Sapiogram@reddit
Hard disagree. Goroutines are semantically indistinguishable from threads, which most languages have had for decades. Channels are borderline impossible to use without at best leaking memory, at worst getting deadlocks or data races.
zackel_flac@reddit
Goroutines are what we can call green threads. Similar to Rust's tasks, they are basically user-space coroutines completely dissociated from the kernel threads. Go spawns a thread pool (with kernel threads, similar to Rust Tokio) and then the runtime schedules the green threads accordingly. This is an entirely new concept only brought by modern languages.
Sapiogram@reddit
This is a common misconception, but completely wrong. Goroutines are fully pre-emptive, i.e. any goroutine can be interrupted by the go runtime at any time. That makes it by definition not a coroutine.
Rust tasks are coroutines, because they use cooperative multitasking, and must manually yield to the runtime with the
await
keyword.Again, the semantics of goroutines are indistinguishable from threads. Yes, the implementations are different, but that doesn't matter in 99.99% of cases. Try finding a counterexample.
zackel_flac@reddit
Last time I checked Goroutines were not pre-emptive and had await points inserted by the compiler (at every function calls IIRC). Maybe the implementation has changed or the information was wrong from the start, I have not looked at the code gen part myself.
Assuming there are indeed not stackful coroutines, they are still not kernel threads. They have the same job steal mechanism as Tokio and operate at the user space level. People complain (with reasons) at kernel threads because of context switches which are huge and are not user space logic aware, meaning they cannot yield before the OS decides so. The only information the OS has is linked to syscalls, which are themselves expensive as well.
Sapiogram@reddit
Goroutines have been pre-emptible on most platforms since 1.14, though notably not on webassembly.
I don't think the change made much a difference to code that was already correct according to the language spec, but a lot of people used (and still use) cooperative scheduling as an argument to justify code patterns that were always unsound, like sharing mutable data.
zackel_flac@reddit
Thanks for sharing the info! It's interesting to read why they changed that behavior.
There are always people trying to optimize needlessly, unfortunately.
elwinar_@reddit
Not sure what you're talking about, but this seems like a "I've read something about a bug or a way to write bad code that I'm going to generalise to the whole language". That or "I'm just bad", your choice, but I'll be assuming the first.
Sapiogram@reddit
Go was my main language professionally for two years, thank you very much. >80% of occurrences of channels in our code base had bugs, and many of them caused serious problems. Containers running out of memory due to leaks, errors silently being ignored, deadlocks, CLIs suddenly using 100% of all CPU cores until they were killed... and that's just the ones off the top of my head.
brutal_seizure@reddit
Skill issue.
Sapiogram@reddit
Yes, the skill issue was griefing myself by using a terrible programming language.
Maybe-monad@reddit
Do you remember why
append
works like this?zackel_flac@reddit
No need to "remember", that's how arrays in memory are aligned up. If someone does not understand this code, it just means you need to go back to array 101.
Maybe-monad@reddit
It's not about understandinghow it works it's about how many issues it will cause because the behavior is inconsistent.
zackel_flac@reddit
The behavior is extremely consistent here. You are modifying a slice which is just 1 pointer and 1 size. There is no undefined behavior at play here.
Maybe-monad@reddit
The append function sometimes returns the same slice (or pointer, how ~you~ your Lordship, Keeper Of Knowledge How Things Work In Programming, would like to call it) depending on the capacity, property which is calculated in an opaque way in the runtime without any guarantee that the way it is computed won't change in the future which is by definition inconsistent.
Consistent behavior for append would be always returning a new slice or always modifying in place.
syklemil@reddit
It's also amazing how quickly the heel-turn from "Go is easy for beginners" to "skill issue" goes
zackel_flac@reddit
If you can't reason around arrays, you probably should not be near code anyway. Can't expect a monkey to write golang code, even if it's easy, there is a base knowledge to have.
syklemil@reddit
We absolutely can reason around arrays, which is why we're able to conclude that the API Go provides is bad.
The behaviour Go's
append
exerts is simply not the behaviour anappend
operation should exert. When you perform multipleappend
operations, you should be able to expect that all the elements youappend
ed are still present.And worse, this is all implicit. If you're doing something funky with arrays, pointer math and dereferencing in a language like C, you'll have it shoved right in your face that you're writing to the same memory location repeatedly. In Go, this is hidden, and it maybe happens, depending on whether or not it needed to grow the capacity. This is exactly the kind of bullshit Go claims it doesn't pull.
Yeah, that is about the level of seriousness we can expect when Gophers try to join a technical discussion, isn't it?
zackel_flac@reddit
I don't see how you are saying that. "append" was coded the way it is for a reason. It's not a randomly generated algorithm someone typed in and said: here, this is maybe what "append" should be doing.
Slices are just size bounded pointers, if you copy the slice header in two separate locations, and modify the two at the same time, without doing a deep copy with the "copy" operation, the result is completely logical. Shallow copy and deep copy are still programming 101.
Do you think in C++ your object tells you when it's doing SBO and when it's doing heap allocation? You have to read the code for that, and the fact Golang forces the code to be present helps you answer those questions. Nothing is hidden in idiomatic Go since the source is fully available. No shared object to link against.
syklemil@reddit
[citation needed]
Seriously,
append
should eitherfunc append(slice []Type, elems ...Type)
, like.append()
in Python or.push()
in Rust, or else it shouldappend
ed element, like the+
operation in Python or<>
in Haskell.The API they made is a fuckup that couldn't decide which of the two it wanted to be, and clearly mislabeled; it is not an acceptable
append
, and there are plenty of other languages to learn from.Oh right, so when people in the Go github issues are yelling about how they can't understand
?
because it doesn't sayreturn
right there on their screen, your response to them is "go read the Go source code"? That's a rather novel interpretation of the intent, there.zackel_flac@reddit
Nothing prevents you from writing your own struct that implements push/append. Personally I like the clean use of
append
, it takes a slice and adds an element to it, it might increase capacity and this is why "append" returns a slice instead of changing it inplace. It is simple, but that never means it's easy.You are mixing many things here. My complaint about ? is not the sugar syntax itself. It's having 7 ways to achieve the same damn thing.
I have algorithms to design, test and ship to production. I am not here to contemplate code and masturbate my brain with all the ways I could optimize away 3 lines of if+return.
syklemil@reddit
JFC. So much for the "good stdlib", I guess.
No, this is not simple, nor is it clean. A clean and simple implementation would do the same thing every time. The fact that you are habituated to it does neither make it simple nor clean.
Threads like these are why I wind up concluding that the "go is simple" statement is a case of an informed attribute, as in, it isn't true, it's just something Gophers go around telling each other until they believe it. The rest of us can see that the emperor has no clothes.
Look, when I refer to "people on the Go github issues" as "them" rather than "you", I am not talking about you personally.
Yeah, thanks, I think we've reach the PHP end of this thread. You can enjoy your anti-intellectualism all you like, but if you want to be better at it, don't respond to people when they start talking technical details, or as you apparently call it "masturbating their brains".
zackel_flac@reddit
But it does, it does exactly the same dumb thing. From your POV a capacity growth should be hidden away from the caller, and pointers should magically not alias each other. Well, again, I disagree with you here, it's not a real problem in practice because most dev will know about arrays by that stage.
When I say programming 101, I am not saying I know better and everyone is shit. I mean when comes the time of writing code for production purposes, you will know about slices. You are simply creating a strawman here. You can't seriously tell me the code shared on the playground is something people would write in real life.
Ah, I got mixed up with other threads. FYI I am also part of those ? haters, for the reasons given above.
You are completely missing the point here. Masturbating is good, it's pleasing. And I did it for years working on Rust professionally. My point is, it's a huge waste of time in real life applications. If you can't accept other people having different POVs, I am sorry to burst your world view, but that's life.
syklemil@reddit
No, it does different things, based on runtime properties. If the code were simpler and didn't check the capacity it would be less magic. As it is, you've gotten accustomed to a complex API and think that's simple; for the rest of us that should be an indicator that you're not trustworthy around the word "simple".
Not quite:
The
append
API is just muddled in Go, and thus worse than any other language I know, and it all seems to be because the original Go authors were too intimately familiar with C and wound up copying bad ideas from there. Half the time when someone says "Go is simple" they seem to mean "Go resembles C", and a whole lot of us just don't consider C a simple language.And you talk about straw men. :) I more get the impression here that you've fallen into a culture where if you sense that someone knows less than you, you're expected to ridicule them, but if someone knows more than you, then you need to attack them before they behave the way you would. I would recommend that you go and touch grass.
syklemil@reddit
It really is a weird piece of API design. Most other languages seem to have one function for mutating the underlying collection and another for returning a new collection with the element inserted. Go smushed them together, and did so in a manner where it's rather unpredictable what'll actually happen.
IIRC there's a C function that works much the same way, can't recall the name of it, but I wouldn't be surprised if that was the inspiration.
zackel_flac@reddit
That's just how arrays work though. Being able to play with capacity and reuse buffers without extra allocations is one of the great strengths of Go. If a programmer can't handle arrays, there is little we can do here.
You can have the same "surprise" when using C++ and Rust with structs that use SBO (small buffer optimization). All of a sudden your array has moved to heap and you don't know why. Well it's by design, that's it.
syklemil@reddit
No, that's basically Go stockholm syndrome talking. To repeat myself, other languages separate the "mutate the underlying collection" function from the "return a new collection containing the inserted element" function. The simplest way probably is to refer to Python:
zs = xs + [y]
means thatzs
contains bothxs
andy
, butxs
is unchangedxs.append(y)
means thatxs
now containsy
append
s the data never gets lostSimilar story in Rust, where you'd do
xs.push(y)
to makexs
containy
, and depending on the ownership, might movey
—the compiler will tell you if if you try to reuse it when you couldn't.The bit where repeated
append
in Go might make it just lose data is bad API design.hissing-noise@reddit
Dminik@reddit
It feels like a weird choice for a company that doesn't use git to make git a first class citizen in their language. Not to mention that originally the golang repo was in mercurial, not git.
zackel_flac@reddit
Not sure how weird this is. They went with what most people use. They did not create the language for internal usage.
jl2352@reddit
You make a good point adding to the discussion, however looking back I feel that quote is a big cop out.
When you look at the complaints of say Rust, Python, C#, TypeScript, or modern Java. It tends to be specific things. No one says broadly the languages are broken at their core. For example package management in Python can be dire, and can be great.
But Go, and C++, have issues that go broad and deep across the languages. Ones that aren’t fixed by moving to a new tool, like say uv with Python.
I also think Bjarne said that ultimately to hand wave the issues of C++ to one side and not care. Not intentionally, but because at the time C++ had the trump card that there wasn’t really a proper alternative. So he says people are just whining, and buries his head.
zackel_flac@reddit
I feel people misunderstand what he truly meant. I don't think he uses that as a trump card, he is just being realistic: all decisions in engineering come with pros and cons. There is no silver bullet out there that makes everything perfect.
So it's not really about whining, it's just that whatever the language you end up with, there will always be issues with it. And to be fair the C++ community has been addressing them for years now. The process is slow, but it exists.
You mention Python, but there are people who hate its tab based syntax. This can't be fixed, it's part of its identity. The same applies with Go, it's engineered towards simplicity and efficiency, and you cannot just change those core things to please everyone on earth.
Personally I see Go as the right fit for junior and senior people. It's simple enough for juniors to get started quickly. And perfect for old asses who are tired of playing with new toys and just want the job to be done right and efficiently.
Ok-Scheme-913@reddit
Except package management breaks down the moment you touch anything not 100% go, written in a very go-ish way.
Code readability has a subjective component of course, but a) it is objectively a very verbose language with a lot of noise (if errs at every second line), b) imo not using the age old c/java type notion, and neither using the ML-one, the two which are pretty much used everywhere is just.. wtf is wrong with you? And imo it reads worse than any of them, with no technical nor human benefit (ident: type has a parser benefit, plus type can be omitted).
Async.. goroutines are cool I guess, but the language itself has very lackluster tools to manage concurrency, like basic data structures are missing, and those for a long time couldn't really be nicely implemented in go due to lack of generics/special-casing. So you only get channels which have many problems and are not a good primitive for everything.
Cross compilation - see my first sentence. Also, the moment you touch C interop, many of these advantages fly away.
yawaramin@reddit
Look friend we use Go because of its tooling (eg trivial cross-compilation and great supply-chain security story), compilation speed, and convenient runtime (I/O that's automatically async without having to jump through async/await syntax hoops). We don't use it because of the stellar language design.
xFallow@reddit
I love the language because it means my coworkers aren’t allowed to write OOP abstractions
SweetBabyAlaska@reddit
they certainly do try though...
aflashyrhetoric@reddit
Hahah, I remember as a junior dev like a decade ago, my first day working in the Go codebase, I proudly presented my "errCheck()" helper function to "do away with the pesky error checks." The lead dev gave me a big smile as he rejected my PR ☺️.
SweetBabyAlaska@reddit
haha its definitely a mildly annoying aspect of Go, but its really not that bad. Its like a poor-mans optional with an extremely verbose way of unwrapping because usually when an error is returned you dont use the other return value.
aflashyrhetoric@reddit
Definitely yeah. I've come to appreciate the verbosity and the reduced indirection (less jump-to-definitions necessary) that comes with working in Go.
exploradorobservador@reddit
I will take the DX of Go over TS and its ever shifting tools. I actually find its simplicity to be the stellar aspect.
codemuncher@reddit
I use it because the alternative was typescript nodejs.
That’s the most minimal bar it met.
ajr901@reddit
I used to write Go all day for a couple years.
I’ve been writing nothing but typescript for the last year or so.
I don’t miss Go at all. Typescript is actually pretty nice and node has come a long way. Typescript is even nicer with Bun.
LucasVanOstrea@reddit
Call me when they make typescript a static language until then I would take go any time
Syliann@reddit
It's nice to read. It runs pretty fast. It's simple to get set up and just start coding, with or without libraries.
I don't know of any other language that fits. Maybe they beat Go in language design, but they fall short in one of those three wants.
yawaramin@reddit
For me, OCaml comes close in some ways, especially compile speed https://dev.to/yawaramin/practical-ocaml-314j
yes_u_suckk@reddit
Pretty much this. The only reason I use Go is due to its cross compilation, but I hate it as a language.
atlasc1@reddit
The more experienced you become as a software engineer, the more you come to hate syntactic sugar and "magic".
I love Go, because what you see is what you get. You don't need to dig into multiple layers of operator overloading, weird meta-programming annotations, magical state variables introduced from god-knows-where, and there aren't 500 different ways to filter a list. Errors are explicitly handled, and you don't rely on them bubbling up in hope that they'll be caught somewhere.
It might be boring, and it might feel slightly repetitive, but I much prefer that than trying to decipher what some junior engineer thought was very clever at the time.
Hacnar@reddit
I'd argue it depends on the scale of your projects. Small projects tend to prefer simple languages. Bigger projects tend to prefer languages with better abstractions, because they become very helpful when trying to handle the inherent complexity in a reasonable manner.
exploradorobservador@reddit
Yet over 75% of projects within the Cloud Native Computing Foundation (CNCF) are written in Go.
Hacnar@reddit
So much code was written in C++, when it could've been written in better languages, avoiding many memory and security issues.
The language choices made by the devs aren't necessarily the best ones.
exploradorobservador@reddit
valid, but this fact is to emphasize that the statement
> Bigger projects tend to prefer languages with better abstractions
is vague, not necessarily insightful
Budget_Bar2294@reddit
Golang hate bandwagon was not in my 2025 bingo card
exploradorobservador@reddit
Name a better PL than Go for backend services if you can't say TS or JS.
divad1196@reddit
The article starts by "shaming" people that blame the author's knowledges. Yet, the author can be wrong and sadly it's often the case when people complain.
To this first thing "don't immediately assume the author is an idiot", I would respond "the author shouldn't consider himself smarter".
There are many things that we might not like, but operator overloading isn't necessarily a good thing. I am personnaly happy with Go's choice of NOT having overload. Overload are "nice" but they fo cause issues. Just do a bit of C++.
That's the same for the rest of the article. So again, yes, the author can just be wrong.
exploradorobservador@reddit
A big red flag in tech is being contrarian for the sake of appearing smarter than
florinp@reddit
It is. the moment you understand that an operator is nothing more than a different function names all objections disappears.
I am tired of the shitty way to add matrices in Java. So let's impose this in a new language (Go).
And what's the crap with no function overload ?
func Run1()
func TRun2()
???
divad1196@reddit
Operator overloading isn't a good thing outside of the "programmer feel". That's a huge topic with many pain points. Again, C++ demonstrate it well, if you don't know what I am talking about then you should dig this topic a bit more before your claim.
Run1 and Run2 is a complete different issue. Rust does not have function overload either and yet it doesn't have this "problem". Again, if you just complain but don't know why it was done this way, then you have some research to do before we can have a discussion here.
Maybe-monad@reddit
Kotlin has operator overloading, so do Rust and Dart. Go is not modern, is Newsqeak rebranded and sold as a new shiny thing.
divad1196@reddit
That's not the point. I am perfectly aware that some other languages have it. Your username is "monad", if that's related to FP you could have mentionned haskell. The wikipedia link I sent contains a list of language that supports it. That's proof that you didn't even open the link
The point is: None of you even took 2 seconds to search. No, you all just think that because you like it that there are no issues with it. That's the behavior of an inexperienced junior. A good developer is able to put aside is opinion and search for the pros AND cons objectively, not ignore one side because he doesn't like it.
There are other languages like C, Java, Javascript, that don't have it and people don't complain when using it.
Again: instead of just blindly complaining, do a search and open your mind. It's not even just about operator overloading, it's about being able to grow as a dev. You might agree or disagree afterward.
Papapa_555@reddit
The article is a big load of BS.
Either one of the authors of golang killed his parents, or he's one of those Rust maniacs that hates Go because it's more successful.
florinp@reddit
Yes. Every person in the world that complains about something is jealous.
There is never a valid complain in the world (even in the cases like this when the author explains the reasons).
BenchEmbarrassed7316@reddit
I think this is what the introduction is about. When the author goes on a long description of the flaws (which you can agree with or not) and then someone comments on it like:
Papapa_555@reddit
who can possibly argue that a language is inferior because it doesn't have sum types or operator overloading?
As in this very particular syntactic sugar or this dangerous optimization are the most important language features, for developing microservices nonetheless!
divad1196@reddit
I will rejoin on that. We don't have the motives being the article. But the critic being wrong doesn't make the author right.
neopointer@reddit
And there's no decent debugger for golang yet in 2025.
lilB0bbyTables@reddit
I mean … delve works absolutely fine …
lalaland4711@reddit
The problem with critiquing Go is that it's a language completely built up out of "the first obvious thing that a smart person could think of".
It takes quite a while to show and explain why it adds up to something terrible.
And I say that as someone who's been coding Go for over a decade. It's really bad. It's like someone built the safest car that 1920 could bring. But it's the 21st century. We have seat belts. And anti lock brakes. Why do I need anti lock brakes when I can just pump-and-steer? Sure… you can. Why do I need crumple zones when I can just add a stronger grill? Well… no see that… it's not that it doesn't work, it's that we have so much better.
hissing-noise@reddit
This, and then you also need to overcome some peoples' superstitious beliefs of Google being some cutting edge tech provider instead of some glorified advertisement service provider.
syklemil@reddit
Hey now, they do other stuff than provide ads! Like Google+. And Google Reader. And …
hissing-noise@reddit
You're right. I also forgot all of their libraries and frameworks that were clearly developed for in-house usage and come with funny build systems and considerate release cycles.
syklemil@reddit
Heheh yeah, I think crubit is a pretty funny example of that. Lots of people have been wanting better C++/Rust interop, and here Google is working on it! Let's see …
Oh.
Kinda similarly, I wouldn't be entirely surprised if Carbon turned into something that really only works on Google's monorepo.
PabloZissou@reddit
What's with all the hate for Go lately? Every language makes compromises in different areas. It's childish to complain about it specially since it is used in some very critical projects.
syklemil@reddit
This blog post is a few years old now, but likely more people have been exposed to Go and found it lacking, rather than just having heard about it as some new shiny language from Google.
That doesn't mean that they make an equal amount of compromises, or that every compromise is equally good or bad. If I compromise as a baker and wind up burning my bread, that still makes my bread bad and inedible.
No, critiquing critical projects is a very adult thing to do. If we cannot criticise important projects, the important project will wind up flawed rather than fixed. The more important something is, the more it must be scrutinised.
Acting as if something is beyond reproach is honestly somewhat cultish, which would track with the members of the Go community that seem to want to excommunicate everyone who dares utter anything but total devotion.
When other languages are criticised the answers tend more in the direction of "yes we know lol" or "yes but it's being worked on" or "yes and here's why it wound up being like that". With Go the responses seem to trend more towards deflection, then "stop using Go" or "I bet you're some kind of heretic who prefers another language!"
PabloZissou@reddit
Yeah it could be, I just think different and that's why I have a hard time understanding what's the point of posts like this. If I don't like a language, I simply don't use it and focus on the ones I enjoy working with.
The criticisms are usually always the same "error handling is horrible, Go should have exceptions" the language designers made a deliberate decision there. What’s the point in complaining? It likely won’t change
Personally, I don’t like exceptions either (they often end up driving control flow rather than handling actual exceptions), but I don’t see any value in criticizing Java or JS for using them. It’s part of the language’s identity, and it’s unlikely to change.
Top-Coyote-1832@reddit
I must admit that using Erlang / BEAM has me looking at Golang completely different. The abstractions for distributed, fault tolerable programs already exist but ever Go program rewrites them.
I'm no BEAM wizard though, so I'll never get a job with it. That's the only reason I'm still using Go
latkde@reddit
Yeah Go's concurrency story is weird. Go makes concurrency easy in the same sense that a chainsaw makes surgery easy – literally invented for that specific purpose, but if you slip up then the consequences can be disastrous.
“But Go implements CSP!” No it doesn't, it offers channels as a language primitive, but also offers shared mutable state, so you cannot use CSP to reason about Go programs. It is a frigging wonder any concurrent Go program works good enough, given that you have basically no tools for managing concurrency. The amount of infra tooling built on Go (k8s…) is scary.
In the article, Amos mentions an anecdote that the early Go team was asked at a conference: “why did you choose to ignore any research about type systems since the 1970s”? The same could be asked about research on concurrency models.
(Though admittedly, exposure to the horrors of pthreads and goroutines eventually led to the formulation of the structured concurrency model in 2016–2018, so maybe something good came out of it after all.)
zellyman@reddit
This is such a goofy statement lmao.
Maybe-monad@reddit
Goofy applies to Go's type system
karmiccloud@reddit
This is an side from your point, but today I learned that the chainsaw was a medical invention.
starlevel01@reddit
It's not the big chainsaw you're thinking of.
syklemil@reddit
Yeah, and not just any medical invention. The body part it's intended for is likely a surprise for … oh, at least half of us?
dweymouth@reddit
> given that you have basically no tools for managing concurrency
Alongside channels, Go gives you standard mutexes, atomic primitives, semaphores, condition variables, wait groups, and a runtime race detector that's pretty good at detecting potential race conditions. Among languages with true multi-thread parallelism, maybe only Rust is "safer"
latkde@reddit
Things like mutexes are completely standard in any shared-memory concurrency implementation. Pthreads has them. Java has them. My issue is that a shared-memory model is fundamentally unsafe because it is prone to data races. You can write correct code if you know what you're doing, but it needs conscious effort. Similarly, it is possible to write memory-safe code in C, it's just unlikely.
So I am confused that Go, a language that is focused on concurrency, a language focused on ease of use, picked one of the worst and most difficult concurrency models known.
Some languages have a shared-nothing concurrency model where sending data between threads requires intentional effort. Usually, these are historical accidents due to implementation constraints. An exception might be Erlang, which is built around isolated “processes” that only communicate via messages. This makes it easier to reason about the data flows in the program, and makes it easier to build fault-tolerant systems at scale. Similarly, Rust has the same shared memory data model as C, Java, or Go, but uses its type system to prove the absence of certain data races – similar in effect to a shared-nothing approach.
Not gonna lie, Go's tooling is quite good. You mention the data race detector. It is really good that this is built-in, but under the hood
go run -race
is built on the same ThreadSanitizier tooling that we can use in C/C++ via-fsanitize=thread
in Clang and GCC. Sanitizers are very good (especially when combined with fuzzing), but a concurrency model that is safe by default is even better.syklemil@reddit
Ah, Notes on structured concurrency, or: Go statement considered harmful? I'm pretty intrigued by the idea, but I haven't really seen it a lot of places either. Then again, I was introduced to the post sometime in the past year, so there might have been lots of stuff that I just didn't register.
imscaredalot@reddit
At least it's not as bad as rust. https://blogsystem5.substack.com/p/crowdstrike-and-rust
Rust community is not only the most toxic but just all about culture wars.
https://x.com/rustlang/status/1267519582505512960
https://users.rust-lang.org/t/rust-says-tech-will-always-be-political/43627
https://www.youtube.com/watch?v=_DwaZj3gPYY
https://www.youtube.com/watch?v=KlQ3Ej7unE8&t=944s
https://hackmd.io/@XAMPPRocky/r1HT-Z6_t
And don't get me started on that language creating hidden folders on root and all.
steveklabnik1@reddit
You didn't elaborate on this last time you copy-pasted this comment. Could you explain what you mean? I'm curious.
Dminik@reddit
I don't think you're going to get a reply. For some reason I seemed to remember the comment. And it turns out it's from the same reply to this article from a few days ago which I found today.
Someone asked the same question and didn't get a reply: https://www.reddit.com/r/theprimeagen/comments/1lnb3d3/the_lies_we_tell_ourselves_to_keep_using_go/n0guxe1/?context=3
And on r/linux earlier. No clarification either: https://www.reddit.com/r/programming/comments/1lm85b9/rust_in_the_linux_kernel_part_2/n0ae9ah/?context=3
And an earlier variation from 17 days ago. Though no folder thing. https://www.reddit.com/r/programming/comments/1la3xxl/identity_and_access_management_failure_in_google/mxmts8b/?context=3
imscaredalot@reddit
Yeah I keep asking for a repo in rust where there is collaboration of actual commits of code not readme or configs and I can't seem to ever get one..... That is weird
Dminik@reddit
Oh wait, your also the guy who doesn't know how GitHub works from 3 months ago. Good to see you're still on that.
https://www.reddit.com/r/golang/comments/1jykb8t/comment/mn3zey4/
imscaredalot@reddit
One guy made most of those and the rest are configs. Thank you for proving my point further. https://github.com/pop-os/cosmic-applets/pulse/monthly
And wasting my time further.
Block...
Plasma_000@reddit
Not sure why I'm bothering to engage with a troll but here I'll shoot: tokio https://github.com/tokio-rs/tokio plenty of commits by many people there. I'm guessing at this point you shift your goalposts because you clearly have already made up your mind for whatever reason...
Ranger207@reddit
https://github.com/torvalds/linux/tree/master/rust
imscaredalot@reddit
Those are mostly c contributions or readmes ...... https://github.com/torvalds/linux/pulse/monthly
steveklabnik1@reddit
My best guess is that they're upset at
~/.cargo
being used instead of XDG, but yeah, I doubt I will either.Halkcyon@reddit
Oh, so it's another form of those comment-stealing bots. Lovely.
Speculator_98@reddit
Rust is a much better language than Go. At least there’s no err != nil. Did you know the recent Google cloud outage is because they missed null pointer checking? Rust would have prevented that. At least learn the language before you shit on it.
imscaredalot@reddit
No I read the rust book and very clearly seen it's not meant for collaboration unless the company has an endless amount of foot shot gun money
Halkcyon@reddit
¿Qué?
sludgefrog@reddit
Quietly shipping Go code into production for eight years while other people blog about how the language has issues. I could add to ftl's gripe list, would rather code.
syklemil@reddit
Not to yuck your yum or anything, but I'm reminded of how people used to say the exact same thing about PHP back in the day.
(PHP doesn't get a lot of attention these days, but I think the activity levels in absolute numbers at Github have remained pretty stable.)
sludgefrog@reddit
That's a fair point. I'd say the issues that Go has limits what domains you want to use it in, whereas the issues PHP has limits the size of the codebase you can use it on before you start running into trouble.
In this way, Go is fine in the areas where it's fine, but PHP code begs for a rewrite at some point.
e-tron@reddit
> PHP code begs for a rewrite at some point.
Well, usually not because of PHP problem. By that point domain will be just too huge with n edgecases and clueless managers think that this should be a language problem and asks for a rewrite.
Ameisen@reddit
What?
syklemil@reddit
The long form, which I couldn't remember, appears to be not to disparage someone's tastes or preferences. I don't particularly know where the phrase comes from either, and English isn't my first language, but I found it intuitive and easy enough to remember.
Cachesmr@reddit
PHP actually has a lot of attention these days. It's still the main language to use in a lot of places, and they've been steadily adding types to keep up with TS. Laravel is probably a huge reason why.
florinp@reddit
so your point is not make anything better ? let's use the tools with flaws and never complain ?
"In the time that other doctors complains about missing anesthesia I already done 10 surgeries. I am lucky that I am deaf"
sludgefrog@reddit
I'm getting on with it. Show me what you have shipped.
RunicWhim@reddit
Reminds me of Java.
5p4n911@reddit
RemindMe! tomorrow
SlovenianTherapist@reddit
Writing microservices in Go is painful, a lot of problems that are usually easy to handle become impossible due to the lack of sum types, lack of exhaustion checks, and the way packages work.
This is my personal experience with it after 6 years.
Halkcyon@reddit
Even Python has emulated sum types and exhaustive checks now. Packaging with native dependencies remains a headache, but the experience in the ecosystem keeps improving. It's sad to see Golang stay stagnate in its ideas.
Asyx@reddit
Also Python has Astral.sh. Ruff and UV will bring salvation to us all.
Halkcyon@reddit
Sadly the verdict is still out on the ideal type checker with there being FOUR now that all choose different behaviors of the spec.
syklemil@reddit
Isn't it more like three released and in use, two in the works and available for preview, and one of them likely to deprecate one of the already-released one? As in
And even with all of those I feel like I've forgotten some
Maybe-monad@reddit
Too me it feels like someone doesn't want to do compiler work anymore and yells at people that the language has to be simple in order to avoid it.
aksdb@reddit
I still love creating microservices in Go. But I have a template I just copy over which already brings the necessary setup (github actions, dockerfile, instrumentation, logging, ...).
Exhaustion checks would indeed be nice, though. It's not a huge issue, due to linters you can throw at the problem (for example: https://golangci-lint.run/usage/linters/#exhaustive)
Kept_@reddit
Care to share the template?
aksdb@reddit
That's company internal, sorry. The github actions uses internal workflows, and the instrumentation / logging setup uses internal libraries. So it wouldn't be of a lot value outside the company.
syklemil@reddit
Yeah, I would expect companies that don't have everything in a monorepo to grow some
skel
eton repos for setting up new repos, and some internal libraries (calledtoolshed
here) to unify some common ongoing stuff, like having structured logging with some common fields. But the actual contents of all that will vary by company.Also always fun when someone doesn't build off that and winds up with an app that doesn't work right and doesn't log correctly. Though that should be catchable early with standardized tests.
teslas_love_pigeon@reddit
Convince your company to open source the template if there is no proprietary info. You'd be surprise how this can easily turn into a recruiting tool 24/7 for your company, also you know having a company contribute to open source is a massive win.
aksdb@reddit
It's not so much about secrets, but about usability outside of our specific setup. The templates contains configs for SonarCloud, Backstage, our deployment pipeline, and so on.
teslas_love_pigeon@reddit
Well yeah, if you're going to open source something you strip it out and provide it as is. The point is, you can easily release something like this while building up a lot of good will for your company.
aksdb@reddit
Yeah but then the template is a main func that initializes kong, zap and chi. That's super trivial.
seanamos-1@reddit
I think what you are interested in is project structure, but most of the value of these templates is the working builds/pipelines, observability and deployment. They often do come bundled with some starting structure and a little boilerplate, but that’s not the main value.
codemuncher@reddit
The interesting thing is this is an admission that you ultimately can’t generalize enough go code, and you just end up copying and pasting a lot.
Which is absolutely true.
How do you patch a bug in 50 repos?
aksdb@reddit
The bug would likely be in the dependencies, which are covered by dependabot. So after tagging the library with the fix, I approve 50 autogenerated PRs.
The thing I copy is the glue code and precisely that automation setup for dependency management and CI/CD.
seanamos-1@reddit
This isn’t something Go specific either.
We have templates for our most used languages, C#, Python and Go.
It’s hard to see how you wouldn’t need these “just works out of the box” templates for your common stacks at a certain point.
syklemil@reddit
And yet that seems to be its primary usecase, microservices in Kubernetes, with all the rest as a sort of "well, I guess you could use it for that".
Yeah, the Go creators were kinda too familiar with C and C++ (they were working in C++ at the time they started discussing creating a new language), and Pike himself considers himself "a philistine about types":
So it kinda seems like Go has a very rudimentary type system because C has a very rudimentary type system. I believe I've seen some Pike quote about thinking casting to
void*
, or in Go terms,interface{}
, and back is acceptable. I just wind up wondering why they bothered having a type system at all at that point—the compiler could be even simpler if they didn't do any typechecking, and the language too could be simpler if it didn't have any way to specify type information.This seems to be a side effect of being designed at Google for Google. They have a huge monorepo, and in Pike's own words:
balefrost@reddit
It would need to be offset either by runtime type checking, hurting performance, or runtime undefined behavior, which almost everybody agrees is undesirable.
syklemil@reddit
Eh, there are a bunch of people who think types are overrated and that dynamic languages are the bee's knees, and languages like untyped PHP and Javascript have been massively successful. For all I know, Go would have had even quicker adoption if it had had a typesystem like theirs.
I mean, I don't think I would like it very much, and from the sounds of it neither would you, but it seems like a whole lot of people would.
balefrost@reddit
Sorry, my wording was ambiguous. I meant that it would need to be offset by one of:
I didn't mean that everybody hates runtime type checking.
codemuncher@reddit
Today I ran into the problem that private go modules don’t have first class support.
You can use GOPRIVATE but every person will need to remember to set that variable. Every build script. Everywhere. All the time.
Basically you should only do mono repo with private go code.
What a pile.
Cruuncher@reddit
golang to me just feels like the language you use if you need to write a kubernetes operator
Don't see any real point of it other than that
GuyWithLag@reddit
go
is uniquely suited to FAANG-scale companies, where the junior developers implement code that has been tasked and will be reviewed by mid-level engineers that follow the low-level design that a senior wrote who follows the high-level design of a staff engineer.With go, juniors have a hard abstraction ceiling, the code they produce is first-level readable to mid/senior engineers, memory management is done for them, and they can use nicely-protected concurrency primitives without having to break their fragile little minds.
It's a pharaohs' language.
Halkcyon@reddit
In that its users are treated as slaves?
GuyWithLag@reddit
In that you build huge systems by throwing people at it.
syklemil@reddit
There's also writing Terraform plugins, where Go is allegedly your only choice¹. I've written one for an internal system and my main memory of it was that it was surprisingly frustrating for something that was essentially just doing some REST CRUD.
¹ Terraform describes them as «executable binaries written in Go that communicate with Terraform Core over an RPC interface»; if there's an RPC interface I don't quite see why they have to be in Go.
Maybe-monad@reddit
Because the parsers found in Go have weird and non-intuitive behaviors not found in ones written in other languages.
Halkcyon@reddit
Like Kubernetes and its YAML story, anything not in Golang is just an approximation for integration. Non-Go parsers exist for HCL, for example, but they all seem to have subtle bugs you run headfirst into.
zellyman@reddit
I like how you wrote writing microservices is difficult and then listed a bunch of stuff that has nothing to do with microservices.
You just don't know how to use Contexts properly if you're running into this.
Aaron1924@reddit
For a moment I though fasterthanlime did yet another takedown blog post about go, but no, the article is from April 2022
syklemil@reddit
Yeah, it's been posted here three years ago with a lot of discussion, and two years ago.
I guess last year we had a hiatus?
tj-horner@reddit
It’s ok, I’ll be the designated reposter next year so we don’t miss it again
Neirchill@reddit
!RemindMe 1 year
tj-horner@reddit
Oh no
syklemil@reddit
No problem, just put up a !RemindMe 364 days B-)
RemindMeBot@reddit
I will be messaging you in 1 year on 2026-07-02 02:26:57 UTC to remind you of this link
CLICK THIS LINK to send a PM to also be reminded and to reduce spam.
^(Parent commenter can ) ^(delete this message to hide from others.)
FoleyDiver@reddit
I like the hackernews norm of appending the year to the submission title when the article more than a year old. And the mods will even correct titles when OP forgets.
HoushouCoder@reddit
They also provide links to the other times something was posted previously to rediscover the discussions during then, and they limit such reposts to once per year IIRC
yawaramin@reddit
Would be nice if Reddit did this automatically.
ioneska@reddit
Would be nice if people did this as well, until Reddit learns to do it automatically.
codemuncher@reddit
My golang annoyance of the day is that time.Duration isn’t serializable. There’s a useful parse from string, but you have to basically write your own wrapper types to get useful deserialization into a duration.
And everyone has to do this. Because go either doesn’t support typedefs of primitive - like int64 - as valid interface targets, or the time library authors decided that people should do it themselves.
Yet time.Time has a string serialization.
Sigh wtf go. Writing go makes vibe coding make sense, there’s so much crap you have to boilerplate write, it’s stupid.
mailed@reddit
oh god not this shit again
just don't use the language
shevy-java@reddit
I found the article actually quite entertaining.
Some things are a bit awkward though.
For instance:
That's a fair point. I am also not very interested in a "better C" per se, because I don't like C.
But, C is a successful language. So many other langues tried to replace it and failed.
Go's promise is that it is simpler than C but very fast and effective still. I actually think it has succeeded on that promise too. Now you may say that Go has numerous quirks - fair enough. Most languages do. There isn't a "perfect" language. Every language has trade-offs. Are the trade-offs offered by Go acceptable? I have no idea; TIOBE lists Go at rank #7 right now (https://www.tiobe.com/tiobe-index/). TIOBE has numerous issues, but as a very rough estimate, I think it has some value, so Go is somewhat successful right now. How this may change in 5 years ... who knows, but right now I think Go is in a good spot.
But that is a very specific complaint. What if the language design is counter to this?
A language is not necessarily a tool that is so flexible that it can be adjusted to every possible use case. You can't e. g. get rid of types in Haskell; it would kind of defeat the whole point of it. Or turn Haskell into an OOP language with mutable state. Some things can not be done.
I am not saying this is the case in Go here, but ANY language design requires trade-offs. You can end up with a billion features such as in C++. Go went another route. How successful that is or not, well ... but the specific complaint "does not have sum types so it sucks", is very strange. It seems to me as if people are more vocal about critisizing Go.
I don't know why Go went that route, but is the assumption that operator overloading is a must-have? I don't think so. Often I found operator overloading just a workaround for a very inflexible programming language, in particular after having used ruby for so many years, I can't help but feel that languages that go the "operator overloading" route are languages whose intrinsic design is simply broken; or less flexible, but then try to sell it as a "feature" to you.
Quite frankly, as a hobbyist I would much prefer ruby and python without type madness. And if more speed is necessary, then I may throw in, say, java, C, C++, Go. For me the combination ruby + java was best, but probably C or C++ would be better, and python due to more people using it. To each their own. (Or perhaps Go rather than C or C++, I can't judge. I know some python devs who went the Go route, so Go can not be totally bad.)
pkgconfig is fairly simple - you have your information stored in the .pc file. That's about it.
Autotools are crap. The sooner this dies, the better. cmake is somewhat ok but awkward. Meson/ninja I like the most. I don't feel this is necessarily the fault of the languages though. Rust was quite successful with crates, to the point of forcing C++ to adjust. C of course is the sleeping dinosaur. It does not change much at all, so ... you have to handle dependencies on your own. After having installed many crates, I have to say that I feel C is losing out here. crates are simple and easy to use, from a user's perspective. Probably also for rust devs.
That's a weird comment. Clearly Go was designed. You may not like their design, but the claim "didn't want to design a language", is simply factually incorrect.
Well, they tried to do something different. I live much more in the C world than in the Go world, but I think it is perfectly fine to try things differently. My biggest concern with Go always was - and still is - Google. Mega-corporations already control WAY too much in general. I much preferred the design-style offered by Guido or Matz, even if they in turn may be influenced by companies. It just felt different still; there was more interaction with them from the communities' point of view. I can't really interact with Google, also because Google pisses me off almost daily (just like they killed ublock origin, and do other fancy moves that should not be allowed - I don't want to use Go and make Google stronger).
Ok but ... C + UNIX (or Linux) were a huge success. And still are.
I feel that neither Go or Rust manage to break that success story.
It's funny to me in that so many try to replace C, and they just fail. It's like we can not get rid of C. C is for eternity. C is love - and life (well ...).
Linguistic-mystic@reddit
This is a brilliant thought. I've never looked at it this way but, come to think about it, Go is really a terrible language for beginners (even though it's touted as the opposite). It's ok for C or C++ veterans who are hard to surprise but it's totally unsuitable for beginners because they let them get away with so much. "Check for error results? I don't have to." Nil? Leaking channels? Mutating every field of every struct? Having access to all the privates if they are in the same folder? You bet I can! God, teaching Go as a first language is one of the worst offenses one can commit in software (though not worse than Python or Jokescript, of course).
d33pnull@reddit
rust fanboi spotted, opinion discarded
jnhwdwd343@reddit
“La La La I Can't Hear You”
d33pnull@reddit
lmfao 🤣🤣
MokoshHydro@reddit
I don't understand what this guy is complaining about.
Halkcyon@reddit
You could try reading the article.
CobaltVale@reddit
It doesn't actually say much.
GregBahm@reddit
Yeah. The post starts with a bunch of high-concept meta-arguments against his future detractors, which don't actually have anything to do with Go itself. Then he complains about the Go ecosystem, which isn't a very interesting problem to me. Then he lists good things about Go.
Then finally he gets to a real complaint. If I understand correctly, it's that the compiler lets you create a struct with an array, which will default to null, potentially leading to a null ref error later.
Then he goes back to high concept meta-arguments against his future detractors.
Are language design arguments all like this? I guess these language design decisions are very important, but gosh that seemed like a lot of fluff for a little hard argument.
balefrost@reddit
I believe this is a bunch of arguments against their earlier detractors. The linked article is a follow-up to their earlier post.
New_York_Rhymes@reddit
An enormous amount of complaining with very little substance. We got a few mild pain points and zero ideas on ways to keep solving the original problem without introducing the pain points, as if trade offs don’t exist.
I must admit, I really enjoy Go. In particular, because of its simplicity which is unrivalled. It appears the author doesn’t like go because of a few issues and because they can’t break the rules that Go was designed to enforce. Like complaining that your hammer can’t tighten a screw.
RunicWhim@reddit
I feel like go enters this area where, ironically, keeping the language simple just pushes complexity into your own code.
Instead of sum types and pattern matching, Go makes you reimplement those ourselves. You end up writing more boilerplate to manually track state, errors, and branching logic that other languages let you express directly in the type system.
I respect their hard decision to keep the language as it is. But wanting to express state and error flows clearly and safely isn’t "using Go wrong", it’s asking for better tools to write correct, maintainable software.
fungussa@reddit
These types of aricles are bad for the programming community, they help spawn toxic attitudes - and about a language that many 100s of thousands of programmers have used to build successful large scale applications. Articles like these need to be removed.
iga666@reddit
i think am too old to care about authors skill issues. go lang is a simple language with some interesting concepts and they perfectly work with each other, plus blazing fast compile time and I choose go lang for my future career. because for me waiting for hours for compiler to say you your new extremely smart line of code does not compile because you forgot a bunch of keywords - just a waste of time.
RunicWhim@reddit
Learn programming, not languages.
UnmaintainedDonkey@reddit
The blog author is a classical rust crazed fanboy.
Halkcyon@reddit
The author spent several years authoring production Golang and Nodejs codebases before discovering Rust.
UnmaintainedDonkey@reddit
Maybe, then he fell for the "rewrite in rust" crap.
GurRevolutionary8650@reddit
Every time I complain about Golang, the Go gopher quietly adds another Goroutine to my codebase in retaliation
aksdb@reddit
go funcYourself()
NaBrO-Barium@reddit
May the func() be with you
loewenheim@reddit
By the time you hear the next pop(), the func will be within you
calmingchaos@reddit
Play that func(y) music white boy?
NaBrO-Barium@reddit
Get the func() outa here!
LIEUTENANT__CRUNCH@reddit
*Goroutine intensifies*
teo-tsirpanis@reddit
That's not true either. The goroutine model is the main reason for Go's poor interop capabilities, and the GC is pretty bad actually (ref).
Cachesmr@reddit
The new Green Tea GC is a pretty huge performance boost so far.
merry_go_byebye@reddit
Not this shit again