Maybe I'm misunderstanding something but non-GC language doesn't mean you have to do memory management manually? I mean, for example, in Rust (or modern C++), it's basically automatic. There is no mental tax or catastrophic mistakes as far as I know.
I'm not saying Rust is worse than Go. It obviously isn't. But this argument that Rust's memory management isn't more cognitively demanding than Go's memory management --- that isn't true.
> But this argument that Rust's memory management isn't more cognitively demanding than Go's memory management --- that isn't true.
It's not far from true. The fights you get into with the borrow checker can be legendary, but lifetimes serve more as gentle reminders. If you get stuck, you can always just use Rc, which is pretty close to opt-in GC. But it's rare to have to resort to Rc, because ownership is just not that much of a problem. In fact, I very rarely use Box either. All heap memory allocation is done by containers, not manually by me. I guess the main friction point for lifetimes is Rust's closures and async, but if you avoid them life is pretty simple.
In return for wearing this almost not a problem, you almost don't have to think about releasing a whole pile of other things - like closing files, sockets, and locks. They are guaranteed to be released by the same mechanism.
On balance, I would not be surprised if the cognitive balance tips Rust's way once you allow for the fact that Rust's memory management also gives you robust resource management for free.
Certainly you pay a price for lifetimes but you buy compile time race condition detection via the borrow checker's aliasing-xor-mutability enforcement. So all that is happening is the complexity of concurrency is being made explicit and therefore easier to reason about. Many applications can be architected in a way that wouldn't ever trigger a race, so for people working on that it isn't something they would need to reason about and they can call it unneeded complexity. This is the simpler vs. simplistic distinction also made in the article. If you can be simplistic, garbage collection is less cognitively demanding, but if you are designing race free algorithms with shared memory then rust will be. I do believe more developers and applications live in the former.
The better example actually comes from the article: returning a struct and an iterator over that struct isn't possible in rust. Heck, initializing a struct to return an iterator might lead to issues. Most people will encounter this before needing a linked list and the lesson it teaches will help out with the linked list.
Rust doesn't promise that your safe Rust doesn't have race conditions only specifically that it doesn't have the one very weird kind of race condition from computers with no analogue to the real world, a Data Race.
An ordinary race condition would be e.g. you put the cat out of the front door, then you walk to the kitchen and close that door - well, the cat might race around the outside of the house and get in first. Our world has race conditions, Rust doesn't solve them, take appropriate care.
A data race is much stranger, it's caused by a difference between how humans think about programming ("Sequential consistency" ie time's arrow X causes Y, therefore Y happens after X) and how the machine works (a modern multi-core computer does not exhibit this consistency) maybe you and your house mate both pick up the cat and she tries to put it out the kitchen door, you try to put it out the front door, this seems to work fine mostly but then on Tuesday the cat explodes, everything is covered in cat fur, messy. Rust actually has a whole layer of extra stuff beyond the aliasing-XOR-mutability to prevent this mistake because humans struggle to reason properly about software which loses sequential consistency so it almost doesn't matter what it "means" if this is lost.
> In logic, equivocation ("calling two different things by the same name") is an informal fallacy resulting from [...] knowingly and deliberately using words in a different sense than the one the audience will understand.
Of course I mean data race, most people in such a thread will implicitly understand that is the race meant. Nobody building a webshop with limited supplies wants to prevent "first come first served", it barely makes sense to think about preventing that kind of race
Data races have obvious real world analogues, they are just so obvious people naturally synchronize. You can look over someone's shoulder while they update a paper master copy and observe data tearing as they erase a field and start writing in another value while that is inconsistent with the rest of the form. It is easy to see that data is being modified and wait until the writer is complete instead of memorizing a partial update and walking away to make decisions on the basis of the incomplete information. A good mutex/rwlock is like having a private separate room to go into to make the update so that no overeager person can even observe the partial update (some languages have non callback style mutexes so there the mutex/lock is the analogue of the visual cue that someone is performing the update). I don't find this at all strange to consider. In a concurrent system it is just all too easy to forget that there are other threads (analogue of people) reading/modifying at the same time. So rust makes that manifest through the borrow checker and it becomes obvious.
Rust prevents more than just data races. Even in single threaded code, if you have a reference to a struct (without explicitly choosing interior mutability), you are guaranteed that its value has not changed since the last time you read it, despite other parts of the code having a reference to it. You don't need to make defensive copies. Some people may find this useful, but generally it won't be enough to convince someone to drop their current language in favor of rust. This transfers into multi-threaded code as well: only a single thread can make modifications to a struct through a reference xor as many threads as you want can read from the struct with references. You can easily write go/java/python programs that have these features and so don't feature data races, but they are difficult to reason about: how do you know that there is only a single reference featuring mutation or many threads only reading? The answer requires non-local knowledge which is difficult to reason about and this is enough for some people to consider rust where the answer is local (defined by the variable).
No they don't, as you handily illustrated by offering no actual data race analogies but instead managing to confuse loss of atomicity with a data race. It's OK though, so long as you write only safe Rust you can't blow your own foot off even though you didn't understand how the explosives work.
And actually people write other race conditions all the time, particularly ToCToU races are very common, and as I explained Rust doesn't prevent those - although a Rust library you're using might go out of its way to be friendly by directing you away from them as Rust's own file system stdlib functions do.
How is Aria's linked list document relevant on this topic? Go is the kind of language where they'd call their growable array type "List" because why not. C# did that in fact, when it gained generics they named their generic growable array List<T>
So the linked list is a thing Go doesn't have at all, in Go the equivalent document probably just reminds you of Go's rule "Don't be clever". Thanks Go, I'll keep it in mind.
Generally the argument is that non-GC languages require you to worry about memory management because of Use-after-free, but of course safe Rust just won't compile if you wrote a typical use-after-free so that's not really extra cognitive demand.
That's true. GC and manual are the two ends of the spectrum with other options in between like Rust. By catastrophic mistakes I mean security vulnerabilities created by memory safety related mistakes.
Maybe it's just me but I cannot write a huge program in rust as easily as I can in Java or Python. I have to spend more effort bending my program to fit the language and it's semantics. I get safety and speed but it feel like I'm wearing a straitjacket for those gains paying in my time and productivity.
Sometimes that tradeoff makes sense, but if I'm writing a backend webserver or some other application why would I bother with all this effort. Just doesn't make sense to me.
You seem to imply that it doesn’t have any cost. It does. You have to make decisions and, in the case of C++: sometimes you have to deal with a lot of really ugly code to make it “automatic”. And if you really have to count bytes and carefully manage stack sizes because you are writing code for a constrained device, you have to pay even more attention than you would in C.
GC’ed languages have memory related challenges too. But it simply isn’t true that these are on the same order of difficulty as the difficulties that do arise in C++.
If not using any esoteric features, it's more human readable (imo), easier to write, can have comments and has some useful features like different kind of multi-line values. JSON is valid YAML, by the way.
You just use aged accounts to engage and make it look like they're promoting a certain business through either new posts or comments or combination. And you can use tools or just Google to see which Reddit threads are already ranking for a certain keywords and then you would go to those pages and leave comments recommending your business etc
> It’s really sad to see how quickly Hacker News, of all places, is jumping head first into welcoming age restrictions and bans with barely a passing thought to what it means.
I'd avoid such generalizations. It's a divisive topic, but from what I've seen here, there's always lots of criticism (regarding implementation at the minimum) in the comments and it definitely isn't clear that most would be jumping head first into anything.
1. The pipeline is simple to split or cut entirely, though. No reason to grow it into a monstrosity, but many reasons to not do it. This problem sounds similar to growing a function too much.
2. I agree in general when talking about more complex operations. Simple transformation and filtering rarely needs intermediate variables for readability or debugging. And the naming of result variable already describes the final collection.
3. Never had to deal with this kind of code but I haven't used Kotlin.
1. Yes, you hit the nail on the head. It basically requires people to be more cognisant of this. However, I think telling people to break stuff out into intermediary variables is much easier to argue for than whether the function is getting a bit too long.
2. Yes, easy filterings usually don't need to be broken down/named, but it really depends. At the very least, if the culture is to name intermediary values, you might accidentally get useful information from the variable names even if people weren't diligently writing explanatory why comments.
3. This isn't Kotlin related, it is just that if you do not have a language/codebase with branded types (or some type system property I don't know the name of), the type system might only infer the base primitives of the result, ending up with stuff like the type I mentioned.
> Yeah, it’s more lines. But each step is just sitting there. No decoding required.
I actually think the first code block is easier to read. It's a familiar (to me) and simple pattern that is quick to read. I don't get how it would require more "decoding" than the second example which is more disjointed and needs more "parsing" for such a trivial case. Maybe it's about what you're used to?
I agree there are downsides to chaining. With more complex operations it can complicate debugging, and readability can suffer, so chaining is not a good fit there.
> Especially small and independent artists should absolutely avoid any software that introduces additional risk of project failure as one such crash scenario at an advanced project state has a high potential of total destruction.
I can't really comment on kdenlive, but this sounds kind of overly dramatic to me. I mean, I hope you save and take regular snapshots/backups in case your disk, RAM or just human error destroys anything substantial.
> Desktop Linux is not useless, but it is really just sub-par compared to Windows.
Each to their own. My experience is the opposite (I use KDE). I have to use Windows at work and it's always such a pain. At least Windows 10/11 finally has multiple workspaces natively and some keyboard shortcuts for managing windows (ironic), but I would have preferred to stay in Windows 10.
Now Windows doesn't even support proper suspend anymore and it won't stay in the "modern standby" either. Constantly waking up and doing god knows what with fans screaming. When I take a look what it's doing, task manager claims that nothing resource intensive is going on. I'm guessing it's hiding some internal processes. It calms down when I put it to sleep again. Sorry for the rant, I better stop before I start.
yes the flaky sleep is what did it for me - laptop would randomly boot up at 2am, bright lights and whirring fans. Thought it was a virus! Seems like Fedora has cracked the hibernate/sleep issue, possibly due to good intel driver support for my Dell and finally Linux has better hibernate, sleep and wake than Windows 11 (ymmv!)
I actually have been lucky since even my laptop from 15 years ago already worked well with Linux and suspend while Windows didn't (wasn't OEM Windows anymore). I have also had multiple desktops that have _mostly_ had no issues with suspend either: only nvidia has given me grief on some setups when sometimes the screen would be blank when waking up, but I figured out workarounds for that.
reply