Go Kind Of Sucks
Vložit
- čas přidán 15. 06. 2024
- Recorded live on twitch, GET IN
Reddit Thread
/ what_sucks_about_golang
My Stream
/ theprimeagen
Best Way To Support Me
Become a backend engineer. Its my favorite site
boot.dev/?promo=PRIMEYT
This is also the best way to support me is to support yourself becoming a better backend engineer.
MY MAIN YT CHANNEL: Has well edited engineering videos
/ theprimeagen
Discord
/ discord
Have something for me to read or react to?: / theprimeagenreact
Kinesis Advantage 360: bit.ly/Prime-Kinesis
Hey I am sponsored by Turso, an edge database. I think they are pretty neet. Give them a try for free and if you want you can get a decent amount off (the free tier is the best (better than planetscale or any other))
turso.tech/deeznuts - Věda a technologie
Factorio mention; the factory must grow
This should really have been Java's tagline.
@@T33K3SS3LCH3N 😂
Oh no, we arrived at „reacting to Reddit threads“ low of content creation 😂
" "*
@@JorgetePanete Some other languages/counties do quotation marks differently. For instance France uses « and » and Germany uses „ and ”
We will be dissecting random 4chan slide threads before long.
@@judef yeah, my stupid German keyboard does this autocorrect automatically, sorry!
Full time and already ran out content.
we need to see prime building something with python since he hates it.
And Ruby as well. Ruby gets so much undeserved superficial hate.
Ruby is the peak of scripting languages
i'd say python is leagues better than js in therms of coding experience. all you have to do is write struct-like classes (via NamedTuple/dataclass) and not touch stupid stuff, like bidirectional generators, metaclasses, multiple inheritance, accessors, (most people don't use all that anyway). maybe it's because i haven't done much js, but i trip over it's mad type coercion rules every time. also, js syntax is just not great, but the only problem with python's syntax is indentation significance (that's definitely a big L).
@@SlammerSimming Word
@@Daniel_Zhu_a6f I recently ended up using multiple inheritance in python and I wasn't prepared for how fundamentally stupid it is. It's like impressive how poor the design is, to the point where it's hard to believe anyone actually tried using it before it went into production.
r/golang moderators are a bunch of snowflakes, I'm surprised they didn't ban this poster permanently for saying "sucks".
It is the same for all reddit forums, nothing surprising here.
@@youtubeenjoyer1743 true
@@youtubeenjoyer1743 it applies to most big subreddits, yeah. But it depends on the community, tho. r/fulbo is funny af
@@youtubeenjoyer1743 "same for all reddit". I've seen plenty of subreddits where antisocial behavior is the whole point.
was there some mass scrub of that, or are you just exaggerating for effect? asking truthfully.
@@blarghblargh any place with unpaid volunteer moderators accrues petty people with lust for power or some stupid agenda. Eventually you get banned for le bad word. They do it with freedom from any form of remuneration or monetary compensation.
Depending on how you use defer, it functions similarly to destructors. Whenever you push a defer, then another, the second goes onto a stack and unwinds at the end of a function first. I do not like to do mutex + defer raw, you need to account for deadlocking when using defer. Mutex around the smallest amount of code you can and call the unlock manually at the end. Defer will just add too much bloat if you dont want a deadlock.
Definitely been caught out by defering a mutex unlock
You rarely want to defer a mutex Unlock until the very end of the function anyway, as it restricts your function to operating sequentially until Unlock is called (removing any performance gains from possible concurrency). Generally best to use Lock and Unlock to clearly mark where the critical section starts and ends.
21:00 I frickin' love the Go context package! It's easily top 5 favorite parts of Go!
4:14 *spits coffee out laughing* Sudden Top chat message:
"poor garbage collection performance reminds me of Dubai"
*lol*
"Mutex in a struct seems like a design smell" - Wut.
Io reader to channel is done via std lib Pipe. I use it in my custom TCP messaging library to have a common interface between websocket services and raw tcp, and encrypt on send between them all.
Hub?
Also a popular pattern is a single writer on a persistent ds accessed from an "atom" with many readers. Because a write updates the path to the root of the tree (atom), a reader always sees a consistent view of the world. Rich Hickey has a demo of an ant colony sim that scales up to > 200 threads. Because it doesn't use locks, that blocked time is essentially exchanged for more gc (due to persistent ds path copying).
Blazingly Fast.
It sounds a number of these issues are to do realtime stuff. In that world you're going to be a lot more worried about heap allocations, thread prioritisation, constraining memory allocations. Go is great, but if you're doing that kind of stuff, Go is not the tool. Like I wouldn't use Go for audio DSP unless it was really basic stuff just for messing around. It would click and pop city.
I still like the idea to add a state to the assertions. I'm taking that idea...
17:31 I think he's talking about the band Panic! At The Disco
this is really good, thanks man!
>when you use a go library, you always know it will err in a certain way
oh how I wish this was true. even the go stdlib has places where it panics instead of returning an error, e.g. when you try to parse an int from a buffer if the buffer isn't large enough.
this forces you to have to understand the implementations of stuff you're using and add a bunch of preemptive checks or else live in fear of random crashes.
what language doesn't have panics?
do you know any more examples of this? I'm relatively new to go but from what i've seen, panics should never really escape your code so perhaps you run into a bug worth reporting? do you have any links to discussions about that buffer size issue?
Don't worry, it mostly happened when dealing with primitive data type (+ channel but in go Channel IS a primitive type so 🤷@@DMSBrian24
Date/Time formatting is a goddamn clownshow in Go
terminalshop doesn't resolve for me on quad9. Is it perhaps missing DNSSEC stuff or something?
Would Go's new Pinner prevent large object graphs from being walked by the already efficient mark-and-sweep collector?
"Go feels verbose"
COBOL has entered the chat.
Who the fuck whould consider Go verbose?
It's weird nobody mentioned crappy typesystem
Mike stand creaking is on an all time high.
in try/catch world you should switch to errors as values and then used exception throwing as panics
Random thing I hate: named return values are instantiated at the start of the function
That's why I like them. If you don't want that, why use named return values?
@@snorman1911 cos you want to make explicit what you're returning and you don't want to use a struct?
@gusryan ah I see. I'm somewhat new to Go but it seems like more than three return values should use a struct. And two of those three are error and a bool for say, record found or not.
wtf, i had no idea, that's really odd
everybody loves gofmt, Prime.
My first go job had 'init's everywhere, guess how that went.
Useful when it’s useful, and a horrific mess everywhere else.
The primeagen full cycle
is there a language that doesn't suck?
Ts
No, they do all suck, for a reason or another. But some, like Go, suck much more than others.
English sucks along with every other language. I prefer Sanskrit if I wanted ultra pedantic language lawyering.
Esperanto, Haskell and Holy C . Languages so pure and radiant that most mortals are found too unworthy to wield them 😄.
There are two types of languages: languages that suck and languages that no one use.
13:06 Ok, I have to mention C#. It allows you to manually dispose of managed or unmanaged objects in your code. Managed objects are things like the List, which is an inbuilt class built into the language which functions like the Array in Javascript, except it's typed and is a list of ONE type (you defined the type).
Unmanaged objects are usually things like custom classes you create which hold lots of memory. These are not immediately freed up by the garbage collector when they leave scope, unless you make them inherit the IDisposable interface, which tells the GC to call the inherited Dispose() method (which you will override to manage and dereference all the memory you just allocated).
So, yes, there ARE other languages that let you constrain how much memory you're using. You can limit how large an array or a List of objects can be in C#. You can control disposal. You can even scope the lifetime of a custom memory-managed class that inherits IDisposable by utilizing the `using` keyword (which automatically calls your custom GC code for you).
I could see someone like Primagen figuring out how to leverage C# to do exactly whatever memory allocation voodoo he wants to happen (not sure why mem allocation is a big deal, and why people are so transfixed by Golang and Rust; maybe y'all got burned by Java and JS, idk).
You should even be able to mess with pointers and other low-level stuff in C# using the Dispose pattern. Why you would want to apart from games, I don't know. But then again, I just rest on the default GC and don't really do any memory management unless I absolutely have to.
The same with allocations. I basically just say "forget it, I'm going to use my filter-map-reduce skills and just avoid allocating a shit ton of classes". If I'm allocating a bunch of memory in a web application or any kind of business application, then I have failed as a developer.
YMMV.
13:50 ish. One more thing. A million objects. I can spawn a million class objects in a C# collection class I write as a wrapper and implement the IDispose interface to handle garbage collection manually if it's such a big deal.
Or maybe have each object in the collection be disposable and have a reference to parent objects, or some random 'node' object that it's responsible for disposing. That way, if one goes, all of them go (if not already disposed; gotta have that check!). It should be possible. Maybe a variant that has loops like the 100 prisoner problem where the GC gets called on each loop of object nodes, but in sequential order, not all 1 million at once. The disposal could then be put on a thread and awaited (worst case).
And now I have to go code this. Thanks Primagen.
"Unmanaged objects are usually things like custom classes you create which hold lots of memory. These are not immediately freed up by the garbage collector when they leave scope, unless you make them inherit the IDisposable interface, which tells the GC to call the inherited Dispose() method (which you will override to manage and dereference all the memory you just allocated)."
I don't think that you have much experience in C# or object oriented programming.
"inherit the IDisposable interface" : you implement an interface, you don't "inherit" an interface
"These are not immediately freed up by the garbage collector when they leave scope, unless you make them inherit the IDisposable interface," => making something implement IDisposable does not change the behaviour of the GC.
Nothing in C# is immediately freed up by the GC.
You NEVER know when the GC will run.
@@fsharplove "Nothing in C# is immediately freed up by the GC."
Never said or implied that. The memory queued on the GC for deletion.
And even if I get something technically wrong here, who cares? My point was that C# has the ability to leverage the GC. A second (hidden) point or implication I was trying to make was that there is (probably) some way to do allocations similar to these trendy languages but in C#. I say this because I know I've seen some pointer code in C#, so maybe it's possible.
Take a chill pill, fella.
@@nicholaspreston9586 "These are not immediately freed up by the garbage collector when they leave scope, unless ...": Yes you implied that the GC immediately freed up some memory in some cases because of the proposition built with unless.
I didn't mean to be rude.
My understanding:
Dispose is explicit : you call it to free up memory, even though you don't know when it happens. By using IDisposable the Dispose method will be called for you when you use some "scoped using".
You need to dispose handle on file, database connectio, ect... Stuff that are not "GC managed".
Finalize : is like of dispose but is implicit. Called (not by you) when there is no ref to your object.
The principle of the GC is that you never know when it will run. You can know when an object is marked "as garbage" but never know when the memory it uses will be released.
Java, C# and any other GC language works roughly the same way.
anyone knows if Prime will make a glove80 review video?
If I want to close a server, I usually use an atexit library for those kind of things.
Or just forget(), if you don't need to gracefully shut down connections
Receiving over a nil channel blocks forever.
Destructors are bad, because when they fail you either ignore or panic
A lot of these complaints seem like they are from devs who havent dealt with much systems programming before.
Like people who have mostly done TS, Ruby, Python, etc before or something.
Just like prime said, if you are dealing with resource issues, you build a configurable and shared pool to work from rather than just dumping everything into a go routine immediately.
it just comes down to custom malloc. It's the best you can do, other than pooling, is to reduce unused tail space, but it needs to get performance tested. I read how to do it in Rust, not bad. Haven't tried in Go. It's gc. I wouldn't expect much. With C#, it had these options for garbage, but manual calling costs a new managing thread basically, so if you do that, you grind.... so usually don't mess with aggressive collection. You pack your pud. Wouldn't make a game with it.
I have to learn Go for my new job - (C,C#,JS,Python) coder.
Nim, all in white, comes and does both exceptions and errors as values. 8-)
CGO is a GO's way to access/load native C/C++ Libs. And it becomes is a nightmare if you want to distribute your Build for any platform, other than the one you are programming on.
That entirely depends on dependencies and platform dependencies of the library used. SQLite would be quite easy. Also, there are docker containers that makes this easier.
Nonono that only a small part of the problem.
One of my biggest problem is that go module does NOT resolve C header file dependency!
If you're using library that uses cgo and ues c header file somewhere, you need to resolve that file yourself and go get won't do that for you 😅
Next is error has different behavior, now it essentially fancy errno
@@muhwyndham You use build and linking parameters in the go files for finding things as per usual. Things like:
#cgo CFLAGS:
#cgo LDFLAGS: -lm
It's not an nightmare. You ever used another language?
It's the "C" in "CGO", that makes cross-compiling a nightmare not the "Go". 😉
lol the thumbnail pic haha
8 years ago i learnt Python, around that time I was also forced to learn C, 3 years later I was forced to learn JavaScript at work now I am learning Go because of peer pressure. I am loving it, I don't know if it is worth it though.
If you are loving it, it is worth it
@@andreffrosa Thanks man, I don't know when I will be able to lend a job as a Golang developer. I work in St Petersburg as a Python developer I feel under paid so I thought maybe a new language could help.
why does this dude think you have to wrap entire structs in mutexes w/ rust, I have no idea where he has gotten this idea, you can have an individual field that has sync
This is often worse if you have to access multiple fields and not all of them
@@ThePrimeTimeagen Sound like a library problem, not Go.
For me, it's when you define a global variable and instantiate it, but use it in another file, which causes 'declared and not used'. I absolutely despise '_ = my_var'. It hurts my soul. I guess my real beef is with the fact that there is no such thing as a 'warning' in GO; There are only errors.
sorry mutex in struct makes very less sense, don;t really think there are alot of use cases that a Read/Write locks won;t solve in these situations
1 minute ago is crazy
GLEAM LANG
everything
kind of sucks, kind of doesn't
Prime, I really enjoy your content and I know you’re a smart guy, but how are you months into your Go journey and still don’t even know what CGo is?
I have verbosity issues.
I am mostly a JS dev on the front-end, and I had to make a project that was related to min-max and alpha-beta pruning, for a school project.
I chose Go because it is performant but not overly complex.
When I started writing the code, I appreciated the explicit error handling of if err != nil, and I also like receiver methods as they are decoupled from classes.
However, my first difficulty was in importing code from other modules. I could not figure out how to import my struct with reciever methods to other modules!
Import did not "just work" like it does in JS. I had to go into the go mod and do something weird and unintuitive to make it work.
Stupid. Stupid as fuck.
Anyways, this limitation severely crippled my code-reuse because they made it unnecessarily difficult to re-use modules.
Since I was on a strict time limit, I ended up doing the unthinkable.. I literally copied code from other modules and manually adjusted them.
My biggest complaint with Go is it makes code re-use extremely hard.
Not only that, but I am not sure if it has any support for FP. I often foumd myself writing essentially the same function, but in slightly different ways. I could not really abstract out to a higher order function as you do in JS.
I found that limited FP support infuriating.
But what do I know? That is just my first experience with Go. Leave a comment if there are solutions to my frustrations. I feel Go has potential.
for the game take, i feel like Go would be good for most genres until you start doing heavy 3D rendering. Casey and Jonathan have said the usual hot part of games is just the render loop, rather than the logic. i'm sure simple 3d graphic games or just 2d Go can be real great.
Won't garbage collection cause drop of frames from time to time? Or is it actually not that big of a problem considering all Java games out there?
@@infastin3795 maybe in a massive game, where you are pushing for as much performance as possible. However, usually it's up to the game developer to hide those bottlenecks well. At least a recent lecture i watched from casey he even states that it's up to the developer to hide such flaws as best as you can. so maybe when you clean up the garbage you're in a cutscene and the user doesn't notice the drop in FPS. but yeah you see other games not really have that problem unless you're doing something you weren't supposed to like spawn 1000s of entities in one location. and even then, it's mostly the rendering struggling to render all entities rather than keep up with their logic.
@@kenneth_romeronot how GC issues show up: they don't drop the FPS, they stop anything happening for anything from 10ms to 10s which the player *will* notice no matter what, and you generally don't have much or any control over when that happens, nor is there a good time for it if you do.
That said, you *can* and many major commercial games *have* used garbage collected languages. The problem is when GC issues do happen, the solution is generally to avoid allocating, which twists your code into horrible unreadable messes.
@SimonBuchanNz Go's GC does not take 10ms to 10s. Where do you get this info? It usually takes about 1ms, and you can avoid making heap allocations to reduce GC load.
@@TheQxY that's how GC *issues* show up. As in, when it's good it's good. When it's not good, it's not something you can work around. You can get just about any GC into a pathological state, and games are quite good at doing so.
As a JS programmer I will learn Go, remember my words😂
Once I try to date a Go developer. But when she said that was a error, I panicked
21:03 There is something called channels in Go. You know, some core part of the language that you use with gorountes to communicate things. Easy to miss when you lack skills in programming.
For me the most annoying thing is the LSP that is kinda dumb (compared to rust or ts). The other one is about the functions of basic data structures (like 'append') are not 'methods'.
Errors as values don't feel verbose compared to try catch
Both are verbose in their own way but at least errors as values are easy to manage and document, with try catch there is most likely to be a separare page in the docs for the exceptions and I don't know If any LSP in any language will help you with that, Some exceptions are abvious and you know upfront what you're gonna get hit with but some are just nonsensical and are a pain in the ass because they are more of an unexpected thing at runtime and that's why they really suck
Ya this article screams of skill issue and junior Go dev but senior rust dev
panic = throw, recover = catch
no
@@Davidlavierithats literally how panics work, they use the same stack unwinding mechanism that exceptions do. its just a single "panic exception" type
"Rust doesn't have exceptions"
std::panic: am I invisible to you?
@@SimonBuchanNz Rust does have unwinding because of RAII but it is not meant to be used as a try-catch, you can't even reason on panicking values because they are opaque + you can compile with panic = "abort". I guess it's the same in Golang because of defers.
@@shurizzle well, you *can*, as catch_unwind() gives you a Box if it panics, which you can downcast. But yes, don't actually do this for program logic!
Damn, GC problems because of complex reference graph. And they say Java is bad, when it's GC chews through complex reference graphs in every application with no problem.
defer makes cleanup explicit while drop() hides it
By that logic you should be mallocing and freeing for every single variable used, stack based memory just hides it
Assuming you mean the free function drop, it just moves where the Drop cleanup happens.
If you're talking about the Drop trait, ehhh... in practice there's a paired "clean up this thing I made" you don't want to forget 99% of the time. I would like something like defer that 1% of the time, sure, but I wouldn't trade Drop for it.
The real answer is: why not both? ;)
@@SimonBuchanNz yes correct, hiding isn’t necessarily a bad thing, in fact it’s good in language like Rust. But for Golang semantics, which is readability and explicitness, defer is a good compromise.
@TurtleKwitty initializing a variable is explicitly memory allocating it, and there is no cleanup for the variable as it’s a garbage collected language. No need to get your panties in a bunch dude.
@@massy-3961 your pointer gets thrown out at the end of the function scope, you should explicitly free your claim to it not hide it
There is no union type in Go. This makes its error handling worse than Zig and Rust.
42 seconds is wild
If you don’t like errors in go. Then ignore them.
I just want Go to have Zig's `try val := something()` as syntax around `val, err := something(); if err != nil { return empty_obj, err }`, where val either becomes the intended value or it returns the error and an empty value of the correct type. You won't be able to use this to log errors and stuff (so not super useful in a server environment), but it would make functions communicating errors feel a lot less cumbersome.
JS developer hate go error handling, because they don't handle errors.
They compare handling error and not handling error, because when I build a system that has great error messages and try to handle all error cases, typescript becomes so ugly.
I love watching all these reaction videos but if they r taking away from ur main channel videos that I subscribed to ur brand for idk if I wanna spend time just watching u react to things that I should be just going reading and building my own opinions
Stream is the place to go for technical chat and building
I'm buying prime some WD-40 for his chair. I got you!
wtf is a bugbear
Sucking was the main design principle, so of course it sucks. By design.
but I like data race
13:50 I actually slightly disagree with the idea that calling a function on nil is bad. I think if this is criticism you consider valid, then you must also consider it just as valid for it to be considered bad to call a function with a nil argument. That's all receiver syntax is, a way of providing an argument to a function in a (hopefully) more readable way. I think this leads to the actual issue, that types can be nil by default. Everything is an Option, and I think it shouldn't be this way.
the spaz moment when struggling with git, undoing changes, trying to get back to a good known state, is probably the most honest and relatable part. fuck go, it was behind the 8-ball when it landed
People who complain about golang or any language: comments - over 9000, projects - 0.5
Adon mad guy in yt pissed me off for entire video
Just PLS SHUT IT NOONE CARES
Go sits in that awkward place where it doesn't solve any problems that developers have, so why take the time to invest.
Comparing Go threads to Tokio is silly, they are different things. Go threads are a basic language feature. Tokio is a threading library written in Rust.
most of go langs issues sound like skill issues
“You do have to rely on the programmer to be very very very consistent in its error wrapping” - oh really? I thought Go was designed to be super reliable so it doesn’t have to assume programmers always remember to do stuff? Isn’t the error returned by value the only way? Mr “I hate exceptions, but I do like to always have a nice stacktrace”
10:45 No, there are other alternatives to green threads than OS threads. Having “lightweight” threads can lead to an overreliance on threads when encapsulating the task appropriately and processing it in a thread pool would lead to better and more predictable performance. Is “thread” even the right abstraction?
Pretty much any task system is eventually just green threads eventually: continuation passing is just manually constructing your on-heap return stack, for example.
If your unit of abstraction is calling procedures, then you inherently get something like a thread.
4:20 Doesn't unreal engine have a garbage collector?
Not in the Java sense of collecting language objects. There's a bunch of things which are gc-like, for assets and when switching levels, etc., but so do many programs we wouldn't consider to "have a GC"
unreal engine offers a very high level gc but unreal itself couldn't have been written in a gc language
@@DMSBrian24 that's true, but the question here is about games in general, not game engines in specific
I mentioned unreal engine because your game on top of it makes use of one
btw.
effective_go IS considered as defecto standard.
if you are asking about formatting code - even imports matter a lot to different people or different tools -
- does he heavily depend on stdlib?
-- fine, he makes many aliases/templates
-- hmmm... some human should take a look.
- does he havely depend on other libs in this project?
-- ough, new functionality.
-- ough, important - new logic.
and so on...
Hey @ThePrimeTime, Changing the scaling factor from 1x1 to solve your mouse flickering in linux: “xrandr --output eDP-1 --scale 0.9999x0.9999”
Go coroutines are less efficient than tokio tasks, since go can switch the tasks without an await point, which means it will have lower throughput.
Python world: make it break
If you are using Rust you are in a safe place, stay there!
i love go its really difficult to hate it when you try and understand every line you read its so easy to read programs in go and the validation and structs are good to
There are those that recognize Go's superiority and then there are those that are wrong. It's okay to be wrong. Joking aside, it all comes down to trade-offs of the language and people's preferences or experience.
Just use 5 different languages and then Python to glue it all together. That is the true Way
The fuck!? Is the floating chat using Comic Sans?
That was a poor argument re-edit post
This is not news. But exactly because this is not news, this is news
I about cracked my screen I pressed dislike so hard
@@TheOriginalBlueKirbywhy
@@user-fu4ps9eb2v You are news
Errors as values is also function coloring.
defer > try/finally
of course doing this:
class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message){
super(message);
}
}
again and again for each error that you have in your application + the exception handler is less verbose than:
if err != nil{
return err
}
most people that complaint about go error handling, usually don't use try/catch/except statements at all.
You have no idea you're talking about. Exception definition has nothing to do with error handling. And who said that Java's error handling is superior in any way?
The big advantage with exceptions is that you don't need to deal with errors every time they could happen. In many situations, all that's needed is a top-level handler.
How about "?" then?
what's this comparison even
defining an exception vs returning an error are not equivalent
should've been returning an error vs throwing an exception - and guess what: if you don't catch an exception it bubbles to the caller for free, so you don't even need to write it. Go requires if err != nil checks all over the place even when you're not handling it.
*to return an error is not HANDLING it, btw*
pre-watch:
- Error handling if err != nil {
- No truthy ifs: if myStr != "" {
- Nil maps/arrays cause panics (can we really not just allocate one then)
- error + stack trace not in standard lib (instead in some archived errors package -- we should never be importing an archived package)
- sync.Map is not drop in replacement for map
these are the most annoying daily/weekly ones for me
sync.Map is never been drop in replacement for map, it's only better in 2 cases than map+ mutex
@@nurayatbeltaev9072 Which is the problem. It would be really nice to have a drop in replacement for maps that is thread safe.
Sounds like the author needs to break up the flow. Even cpp will blow up if you try to write an operating system in one file lol panick is waaay better than setting breakpoints using expressions imho
I feel like most issues can be solved by understanding what the fuck you’re doing and how the language gets from point a to point b as opposed to throwing your hands up and crying every time it doesn’t react the way you, naively, expected.
I don't like defer. It is just like a try-catch/finally. It dynamically modifies the execution flow since it does not execute where you call it and has a hidden cost because it implicitly creates a dynamic stack.
Also, you need tooling and an ecosystem. IMO it’s better and easier to use something like Go or Rust, despite annoyances, vs something like [redacted] that might be fun but has a super-limited ecosystem.
"You have to rely on the programmer to be really really really consistent w/ the error wrapping."
If golangs so bad, you're probably writing something it is not designed for.
Just put your entire python program ina try except and then set the error value and boom its as verbose as go
errors as values is nice if you care about the errors.
otherwise it's not.
If you don't care, you don't care.. just try catch the entry of the app, catch the error you like to know about, discard the rest, and everything still executes or bubbles up the error for some1 else to care about...
Exceptions were fine if you only used them for exceptional errors (ie, you shouldn't have been using exceptions in cases where it's okay for a function to fail), but Rust's ? operator works well for both exceptional and non-exceptional errors *chef's kiss*.