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.
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.
@@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.
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).
@@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.
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.
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.
>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.
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?
@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.
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
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.
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.
Removing spaces in expressions like 1 + 2*2 by gofmt perfectly makes sense. Imagine writing mathematical expression on paper: 1 + 2a You write 2a without spaces. It is much more readable: one plus two As. The same applies to your source code. I learned it from Python's PEP8 standard.
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).
"Poor interoperabilty with other code" - Basically the support for C binding is bad. That means that things like shared object libraries can't be done easily, and that hampers items where plugins would be sensible approaches. This means that on the items where you need plugins, you have to either guarantee someone else builds them with the same exact go release (bad for when the product updates, but the plugin doesn't), you have to "wrap" the plugin in a service and call it through network calls (bad performance, lots of extra complexity), or you have to use cgo and manually integrate in a .so/.dll loader that just gets uglier the more you work it (and compiling goes from fast to lethargically slow).
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
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.
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.
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
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.
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.
@@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.
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.
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.
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
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.
@@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.
@@michaeldjango It's okay. They are both important languages from a mainstream industry perspective. Each language will offer a different perspective and you can decide what you prefer professionally.
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'.
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.
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"
@@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
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.
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.
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 }
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.
@@squishy-tomato that's why Rust's version is superior because you can wrap your return type in Result and add ? in code that can error, so it's not verbose at all. The problem with exceptions is that you just don't know when a function will throw an exception unless they tell you in their documentation, whereas with errors as values, you always know.
“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”
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.
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*.
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.
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
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.
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
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...
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.
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
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.
18:40 Is this user not naming things properly? Hard time to write code that makes sense? If you have not idea what the mutex in a struct is for, you need to name it better.
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.
@@Davidlavierithats literally how panics work, they use the same stack unwinding mechanism that exceptions do. its just a single "panic exception" type
@@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!
Why is this guy focusing on these things instead of using it to build something useful? Also, poor interoperability with other code? It's dead simple to get C code in Go.
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
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...
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.
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.
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.
Factorio mention; the factory must grow
This should really have been Java's tagline.
@@T33K3SS3LCH3N 😂
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).
@@swiss_eng 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.
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.
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.
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?
It's weird nobody mentioned crappy typesystem
21:00 I frickin' love the Go context package! It's easily top 5 favorite parts of Go!
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.
>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
"Panic" when the world has stopped making sense, before you convert your database into a smouldering ruin.
The Primeagean: Hold on. HOLD ON!
TH-cam: Plays ad.
Well played, algorithm. Well played.
17:31 I think he's talking about the band Panic! At The Disco
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
terminalshop doesn't resolve for me on quad9. Is it perhaps missing DNSSEC stuff or something?
My first go job had 'init's everywhere, guess how that went.
Useful when it’s useful, and a horrific mess everywhere else.
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.
Date/Time formatting is a goddamn clownshow in Go
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.
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.
Removing spaces in expressions like 1 + 2*2 by gofmt perfectly makes sense.
Imagine writing mathematical expression on paper:
1 + 2a
You write 2a without spaces. It is much more readable: one plus two As. The same applies to your source code.
I learned it from Python's PEP8 standard.
Blazingly Fast.
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).
"Poor interoperabilty with other code" - Basically the support for C binding is bad. That means that things like shared object libraries can't be done easily, and that hampers items where plugins would be sensible approaches. This means that on the items where you need plugins, you have to either guarantee someone else builds them with the same exact go release (bad for when the product updates, but the plugin doesn't), you have to "wrap" the plugin in a service and call it through network calls (bad performance, lots of extra complexity), or you have to use cgo and manually integrate in a .so/.dll loader that just gets uglier the more you work it (and compiling goes from fast to lethargically slow).
Would Go's new Pinner prevent large object graphs from being walked by the already efficient mark-and-sweep collector?
"You have to rely on the programmer to be really really really consistent w/ the error wrapping."
"Go feels verbose"
COBOL has entered the chat.
Who the fuck whould consider Go verbose?
anyone knows if Prime will make a glove80 review video?
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". 😉
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
The flickering cursor in your full-size chat window view gives me PTSD but excellent content
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.
I still like the idea to add a state to the assertions. I'm taking that idea...
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.
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.
this is really good, thanks man!
in try/catch world you should switch to errors as values and then used exception throwing as panics
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.
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.
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.
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
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
People who complain about golang or any language: comments - over 9000, projects - 0.5
Ya this article screams of skill issue and junior Go dev but senior rust dev
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.
@@michaeldjango Everything you learn is good. 🙂
@@vncstudio hey, thanks, the story continues, now i am being forced to learn Kotlin and c++ at school, shame
@@michaeldjango It's okay. They are both important languages from a mainstream industry perspective. Each language will offer a different perspective and you can decide what you prefer professionally.
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'.
There is no union type in Go. This makes its error handling worse than Zig and Rust.
Destructors are bad, because when they fail you either ignore or panic
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.
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
Mike stand creaking is on an all time high.
Nim, all in white, comes and does both exceptions and errors as values. 8-)
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.
everybody loves gofmt, Prime.
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.
The primeagen full cycle
Once I try to date a Go developer. But when she said that was a error, I panicked
Receiving over a nil channel blocks forever.
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?
@@squishy-tomato that's why Rust's version is superior because you can wrap your return type in Result and add ? in code that can error, so it's not verbose at all. The problem with exceptions is that you just don't know when a function will throw an exception unless they tell you in their documentation, whereas with errors as values, you always know.
“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”
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 to learn Go for my new job - (C,C#,JS,Python) coder.
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.
Go sits in that awkward place where it doesn't solve any problems that developers have, so why take the time to invest.
If you don’t like errors in go. Then ignore them.
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*.
Sucking was the main design principle, so of course it sucks. By design.
but I like data race
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!
lol the thumbnail pic haha
As a JS programmer I will learn Go, remember my words😂
most of go langs issues sound like skill issues
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
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 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.
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
kind of sucks, kind of doesn't
I have verbosity issues.
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...
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.
Just put your entire python program ina try except and then set the error value and boom its as verbose as go
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
Adon mad guy in yt pissed me off for entire video
Just PLS SHUT IT NOONE CARES
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
18:40 Is this user not naming things properly? Hard time to write code that makes sense? If you have not idea what the mutex in a struct is for, you need to name it better.
GLEAM LANG
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.
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!
Why is this guy focusing on these things instead of using it to build something useful?
Also, poor interoperability with other code? It's dead simple to get C code in Go.
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
42 seconds is wild
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...
That was a poor argument re-edit post
Hey @ThePrimeTime, Changing the scaling factor from 1x1 to solve your mouse flickering in linux: “xrandr --output eDP-1 --scale 0.9999x0.9999”
wtf is a bugbear
Haskell
everything