6 ms·
> I’d be much more excited about that promise [memory safety in Rust] if the compiler provided that safety, rather than asking the programmer to do an extraordi
by pcwalton 1y ago
> I’d be much more excited about that promise [memory safety in Rust] if the compiler provided that safety, rather than asking the programmer to do an extraordinary amount of extra work to conform to syntactically enforced safety rules. Put the complexity in the compiler, dudes.
That exists; it's called garbage collection.
If you don't want the performance characteristics of garbage collection, something has to give. Either you sacrifice memory safety or you accept a more restrictive paradigm than GC'd languages give you. For some reason, programming language enthusiasts think that if you think really hard, every issue has some solution out there without any drawbacks at all just waiting to be found. But in fact, creating a system that has zero runtime overhead and unlimited aliasing with a mutable heap is as impossible as finding two even numbers whose sum is odd.
- sph 1y agoThe faster computers get, the more the GC problem is way overblown apart from super-low-latency niches. Even AAA games these days happily run on GC languages. There is a prominent contributor to HN whose profile says they dream of a world where all languages offer automatic memory management and I think about that a lot, as a low-level backend engineer. Unless I find myself writing an HFT bot or a kernel, I have zero need to care about memory allocation, cycles, and who owns what. Productivity >> worrying about memory.
- lifthrasiir 1y agoGC doesn't exactly solve your memory problem; it typically means that your memory problem gets deferred quite far until you can't ignore that. Of course it is also quite likely that your program will never grow to that point, which is why GC works in general, but also why there exists a desire to avoid it when makes sense.
- sph 1y agoThat’s fair, no resource is unlimited. My point is that memory is usually the least of one’s problem, even on average machines. Productivity and CPU usage tend to be the bottleneck as a developer and a user. GC is mostly a performance problem rather than a memory one, and well-designed language can minimize the impact of it. (I am working on a message-passing language, and only allowing GC after a reply greatly simplifies the design and performance characteristics)
- charleslmunger 1y ago>My point is that memory is usually the least of one’s problem, even on average machines. The average machine a person directly interacts with is a phone or TV at this point, both of which have major BoM restrictions and high pixel density displays. Memory is the primary determination of performance in such environments. On desktops and servers, CPU performance is bottlenecked on memory - garbage collection isn't necessarily a problem there, but the nature of separate allocations and pointer chasing is. On battery, garbage collection costs significant power and so it gets deferred (at least for full collections) until it's unavoidable. In practice this means that a large amount of heap space is "dead", which costs memory. Your language sounds interesting - I've always thought that it would be cool to have a language where generational GC was exposed to the programmer. If you have a server, you can have one new generation arena per request with a write barrier for incoming references from the old generation to the new. Then you could perform young GC after every request, only paying for traversal+move of objects that survived.
- mjburgess 1y agoNot sure why you're down-voted, this is correct. In games you have 16ms to draw billion+ triangles (etc.). In web, you have 100ms to round-trip a request under abitarily high load (etc.) Cases where you cannot "stop the world" at random and just "clean up garbage" are quite common in programming. And when they happen in GC'd languages, you're much worse off.
- immibis 1y agoJava's ZGC claims O(1) pause time of 0.05ms. (As with any low-pause collector, the rest of your code is uniformly slower by some percentage because it has to make sure not to step on the toes of the concurrently-running collector.)
- Ygg2 1y ago> Java's ZGC claims O(1) pause time of 0.05ms In practice it's actually closer to 10ms for large heaps. Large being around 220 GB.
- riku_iki 1y agoWith Java, the issue is that each allocated object carries significant memory footprint, as result total memory consumption is much higher compared to C++: https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/javavm-gpp.html https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
- igouy 1y agoThe benchmarks game shows memory use with default GC settings (as a way to uncover space-time tradeoffs), mostly for tiny tiny programs that hardly use memory. Less difference — mandelbrot, k-nucleotide, reverse-complement, regex-redux — when the task requires memory to be used. Less with GraalVM native-image: https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/java.html https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
- 1y ago
- throwawaymaths 1y agoeh, there are GC languages famous for high uptimes and deployed in places where it "basically runs forever with no intervention", so in practice with the right GC and application scope, "deferring the concern till the heat death of the universe" (or until a CVE forces a soft update) is possible.
- lifthrasiir 1y agoThat's exactly why I said "it is also quite likely that your program will never grow to that point". Of course you need non-trivial knowledge to determine whether your application and GC satisfy that criteria.
- withoutboats3 1y agoThis is exactly the attitude this blog post spends its first section pretty passionately railing against.
- deleted 1y ago[deleted]
- jplusequalt 1y ago>Even AAA games these days happily run on GC languages. Which games are these? Are you referring to games written in Unity where the game logic is scripted in C#? Or are you referring to Minecraft Java Edition? I seriously doubt you would get close to the same performance in a modern AAA title running in a Java/C# based engine.
- Jasper_ 1y agoUnreal Engine has a C++-based GC. https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-object-handling-in-unreal-engine#garbagecollection https://dev.epicgames.com/documentation/en-us/unreal-engine/...
- steveklabnik 1y agoUnreal Engine has a GC. You're right that there is a difference between "engine written largely in C++ and some parts are GC'd" vs "game written in Java/C#", but it's certainly not unheard of to use a GC in games, pervasively in simpler ones (Heck, Balatro is written in Lua!) and sparingly in even more advanced titles.
- jplusequalt 1y agoThanks for the Rust book!
- steveklabnik 1y agoYou're welcome!
- tuveson 1y agoI think Balatro uses the Love2d engine which is in C/C++.
- steveklabnik 1y agoSure, but you write games in it in Lua. That Love2d is implemented in C++ (GitHub says like 80% C++ and 10% C) doesn't mean that you're writing the game in it. In my understanding, Love2d uses reference counting (which is still GC) for its own stuff, and integrates those into Lua's tracing GC.
- Narishma 1y ago> Even AAA games these days happily run on GC languages. You can recognize them by their poor performance.
- mjburgess 1y agoWell, 1) the temporary allocator strategy; and 2) `defer` kinda go against the spirit of this observation. With (1) you get the benefits of GC with, in many cases, a single line of code. This handles a lot of use cases. Of those it doesn't, `defer` is that "other single line". I think the issue being raised is the "convenience payoff for the syntax/semantics burden". The payoff for temp-alloc and defer is enormous: you make the memory management explicit so you can easily see-and-reason-about the code; and it's a trivial amount of code. There feels something deeply wrong with RAII-style langauges.. you're having the burden to reason about implicit behaviour, all the while this behaviour saves you nothing. It's the worst of both worlds: hiddenness and burdensomeness.
- hmry 1y agoNeither of those gives memory safety, which is what the parent comment is about. If you release the temporary allocator while a pointer to some data is live, you get use after free. If you defer freeing a resource, and a pointer to the resource lives on after the scope exit, you get use after free.
- francasso 1y agoWhile technically true, it still simplifies memory management a lot. The tradeoff in fact is good enough that I would pick that over a borrowchecker.
- junon 1y agoI don't understand this take at all. The borrow checker is automatic and works across all variables. Defer et al requires you remember to use it, and use it correctly. It takes more effort to use defer correctly whereas Rust's borrow checker works for you without needing to do much extra at all! What am I missing?
- vouwfietsman 1y ago> The borrow checker is automatic and works across all variables. Not that I'm such a Rust hater, but this is also a simplification of the reality. The term "fighting the borrow checker" is these days a pretty normal saying, and it implies that the borrow checker may be automatic, but 90% of its work is telling you: no, try again. That is hardly "without needing to do much extra at all". That's what you're missing.
- ksec 1y ago>as impossible as finding two even numbers whose sum is odd. That is a great line worth remembering.
- deleted 1y ago[deleted]
- pcwalton 1y agoStolen from one of the mathematician Underwood Dudley's essays on cranks :)
- pphysch 1y ago> Either you sacrifice memory safety or you accept a more restrictive paradigm than GC'd languages give you. This is true but there is a middle ground. You use a reasonably fast (i.e. compiled) GC lang, and write your own allocator(s) inside of it for performance-critical stuff. Ironically, this is usually the right pattern even in non-GC langs: you typically want to minimize unnecessary allocations during runtime, and leverage techniques like object pooling to do that. IOW I don't think raw performance is a good argument for not using GC (e.g. gamedev or scientific computing). Not being able to afford the GC runtime overhead is a good argument (e.g. embedded programs, HFT).
- fleabitdev 1y agoIt's difficult to design a language which has good usability both with and without a GC. Can users create a reference which points to the interior of an object? Does the standard library allocate? Can the language implement useful features like move semantics and destructors, when GCed objects have an indefinite lifetime? You'd almost end up with two languages in one. It would be interesting to see a language fully embrace that, with fast/slow language dialects which have very good interoperability. The complexity cost would be high, but if the alternative is learning two languages rather than one...
- pphysch 1y agoI'm not saying you design a language with an optional GC, I'm saying the user can implement their own allocators i.e. large object pools nested in the GC-managed memory system. And then they get to avoid most of the allocation and deallocation overhead during runtime.
- fleabitdev 1y agoSorry, I wasn't very clear - I think that using an object pool in a GCed language is like writing code in a dialect of that language which has no allocator.
- 1y ago