9 ms·
How Memory safety approaches speed up and slow down development velocity
- revskill 4y agoTo me, my productive development process is like this: - Experimentation on the idea, algorithm, data structure,..., everything that actually produces some result. - Improve and finalize the specification of input, output, resource constraint, and eventually the high level architecture (modularity). - Refactoring, with best practices and patterns. - Benchmark usage and eventually swap out the implementation into safe languages.
- roca 4y agoI agree that GC languages are faster for prototyping, but this article downplays the disadvantages of GC. E.g. "deterministic destruction" is listed as a benefit of reference counting, but it really should be listed as a disadvantage of GC, since all the other memory-management methods have it. The "leaky abstractions" argument doesn't work for me. E.g. in a Java API you don't commit (at the language level) to the ownership of passed-in or returned mutable objects. In Rust, you do, and the author claims this is a problem. I say that in fact you depend on the ownership of the referenced object either way; Rust forces you to write down what it is and enforce that the callers honor it, while in Java you cannot. Arguably therefore Rust is less leaky in that hidden assumptions are documented and enforced at the API layer. I've had lots of good experiences refactoring Rust code. It's probably more typing than other languages but the increased assurance that you didn't break the code (especially in the presence of parallelism) more than makes up for it.
- masklinn 4y ago> The "leaky abstractions" argument doesn't work for me. E.g. in a Java API you don't commit (at the language level) to the ownership of passed-in or returned mutable objects. Yep, and so you get all sorts of bugs or defensive code everywhere. For that reason I also have a hard time with one section being > GC'd code can be more correct But apparently issues like iterator invalidation and other mutability conflicts don’t rate.
- pornel 4y agoI get it about Rust, because Rust really won't let you hide the fact that you're holding on to a temporary reference (GC is an abstraction over lifetime of objects). Borrow checking is also intentionally less flexible about getters (allowing library author to do anything in the getter, but that makes exclusive-mutable getters exclusive over the whole object not just one field). So Java programmers are in for a shock — public fields are encouraged, and APIs have to commit to a particular memory management strategy. But OTOH not having to worry about defensive programming is so great. Nothing is NULL. Nothing will unexpectedly mutate. Thread-safety is explicit. It's always clear when vectors and objects are passed, copied, or only briefly inspected.
- pjmlp 4y agoWelcome to ML derived languages with tracing GC, specially pure ones. Java isn't the be all end all of GC based languages.
- moonchrome 4y agoI'd think that if you're dealing with immutable data/pure functions GC becomes transparent even in Java ?
- pjmlp 4y agoYeah, however even with using Scala/Clojure, there is the possibility to touch parts of the standard library that fail to uphold such expectactions. So then one ends up with the usual issue of guest languages, where one needs to create wrappers for the platform APIs to keep the code idiomatic and language invariants.
- roca 4y agoControlling mutation by completely abolishing it is one way to go, but often inefficient. Rust gives you a nice third way.
- brabel 4y ago
- pjmlp 4y agoBecause no two languages are implemented the same, and there are plenty languages with tracing GC that also support deterministic destruction. Unfortunely people keep reading only about Java and then they think they know something about GC based languages. Modula-3 and Mesa/Cedar are two examples from the past, D one from modern times, with many others in between.
- ben-schaaf 4y agoProbably the same for the others; in D you have RAII but destruction is only deterministic for stack/static variables. There isn't deterministic destruction for heap allocated stuff unless you count manually freeing.
- pjmlp 4y agoExcept the little detail that manual heap allocation with RAII is also a thing.
- gumby 4y agoThat case isn't completely deterministic the way stack is: for the stack you just shift the SP which is constant time, while heap allocation and deallocation require manipulation of a small database, possibly including a system call. This is a bit of hair splitting I admit.
- pjmlp 4y agoIt is as deterministic as RC algorithms, which is usually the point being discussed. Yep, splitting hairs. :)
- ben-schaaf 4y agoIn which case you're no longer using the GC. You don't have GC & deterministic destruction, you have GC xor determinism.
- WalterBright 4y ago
- anonymoushn 4y ago> The "leaky abstractions" argument doesn't work for me. E.g. in a Java API you don't commit (at the language level) to the ownership of passed-in or returned mutable objects. In Rust, you do, and the author claims this is a problem. I say that in fact you depend on the ownership of the referenced object either way; Rust forces you to write down what it is and enforce that the callers honor it, while in Java you cannot. Arguably therefore Rust is less leaky in that hidden assumptions are documented and enforced at the API layer. A lot of programs and large parts of a lot more programs just don't need these concepts at all and would run correctly with a GC that did not collect any garbage, memory permitting. Most Python code I write is in this genre. On the flip side, at work we mainly work on a low-latency networked application that has per-coroutine arenas created once at startup and long-term state created once at startup. The arenas are used mostly for deserializing messages into native format to apply to the long-term state and serializing messages to wire format. There's not much benefit to be had from writing all the time that everything that isn't on the stack belongs to the per-coroutine arena, except for all instances of like 3 structs, which belong to the long-term state.
- UltraViolence 4y agoI disagree. It depends on the type of project you're working on. If you're writing a public facing high-performance application it MAY be more beneficial to use deterministic memory management. Most tools, even very technical tools like assemblers, debuggers and compilers, don't need deterministic memory management. Only operating systems, device drivers and some time-critical applications (like video/audio encoding/decoding) need deterministic memory management.
- pkolaczk 4y agoThe trick is, when you have deterministic destruction you can use it for many more things than just memory management. E.g. need to add a metric to measure how many "somethings" are active - just attach a tracker to the struct representing that "something" and the tracker can count itself because it knows exactly when it is created and destroyed. We tried to add such metrics system to a Java app another day, and it turned out to be virtually impossible because due to GC nondeterminism we couldn't tell when most of the objects die.
- UltraViolence 4y agoDo you really need to know? All that matters is that the GC will eventually clean up the used memory. When you're interested in that sort of info you're using the wrong language or asking the wrong kind of questions.
- pkolaczk 4y agoYes, of course I need to know. An important part of production grade software is observability. And that "something" doesn't have to be memory. It can be a connection, file handle, semaphore permit or one of many other things. But even for memory, typically there is not just one global type of memory. Users want to know how much memory is dedicated to X, Y and Z components, they might also want to constrain memory use by logical function. E.g separate buffer pools. This is where automatic memory management with GC falls apart very quickly - even the Java apps I work on actually use a memory/resource abstraction layer on top and manage everything manually, leaving just the last bit of releasing the objects to GC. Which is the worst of both worlds - we get all the disadvantages of MMM and all disadvantages of tracing (pauses, cache thrashing, etc).
- galangalalgol 4y agoIt is more typing than julia or numpy maybe, but probably not more than c#, maybe not more than go, and most certainly not more than java. I think even within GC languages developer velocity varies a lot based on things like typing system, reflection, repl, and maybe interpreted vs compiled. My experience is that this variance is greater than what can be put at the feet of memory management
- kaba0 4y agoJava is much much less verbose than Go, and contrary to popular opinion, it really is not particularly verbose, especially modern Java.
- TylerE 4y agoMy beef with Java has always the extremelyLongMethodNamesInTheStdLibraryFactoryFactory.
- galangalalgol 4y agoI haven't written much go or much java (in this millennium anyway). The little go I wrote didn't have many error checks, is that what usually makes it verbose? The modern java I wrote was a little more functional than 1999 java, but it utilised reflection heavily, and it was a test harness for a black box, so not idiomatic probably, but there was still a lot of boilerplate. C# seems about normal verbosity, and so does rust. Both are less verbose than a lot of c++98 I run into because of lambdas and iterators etc. Julia on the other hand is quite possibly the least verbose language I have ever seen, apart from matlab (which isn't truly general purpose) , and python/numpy/pytorch close behind.
- jcparkyn 4y ago> least verbose language I have ever seen You'd love APL.
- deleted 4y ago[deleted]
- kaba0 4y agoManual memory management does close-couple memory layout/ownership with the public API, and that will objectively make refactors regarding that layout breaking changes, causing many downstream changes required. A quote from the GC Handbook: “modules should not have to know the rules of the memory management game played by other modules” While Rust does make these refactors safe, it is nonetheless work that simply doesn’t have to be done in case of Java for example.
- zozbot234 4y ago> in a Java API you don't commit (at the language level) to the ownership of passed-in or returned mutable objects. In Rust, you do[.] That's only the default, of course. Rc is commonly used in Rust to decouple ownership management from the simple use or passing of objects throughout the program, much like in any GC language. (Of course Rc on its own does not collect reference cycles; thus, "proper" tracing GC is now becoming available, with projects like Samsara https://redvice.org/2023/samsara-garbage-collector/ https://redvice.org/2023/samsara-garbage-collector/ that try to leverage Rc for the most part, while efficiently tracing possibly-cyclical references.)
- georgeecollins 4y agoAs an older dev who spent a lot of time with C on applications where performance and timing was key, I have found the timing of the overhead of GC hard to predict. So I tend to pre-allocate a lot of variables and structures in advance and hold them, so I don't have to worry about GC in a loop. If someone knows a good tutorial of how to predict when garbage collection will happen in my program, I would love to read it and learn more.
- za3faran 4y agoEven if you use a non-GC language, you are not guaranteed deterministic destruction (e.g. in data structures with loops or a highly variable number of nodes).
- pkolaczk 4y agoDeterministic is not the same as bounded. Deterministic means you can determine the moment the destruction happens and you can estimate its upper bound (knowing how much you want to release), not that it always happens in 100 ns. You also get a guarantee that when a certain point in code has been reached, then a resource has been freed. As for the cost it takes to release the resources, in MMM/borrow checking/refcounting this is typically bounded by the amount of stuff to release. In tracing GC it is bounded by the total amount of stuff on the heap, which is typically several orders of magnitude larger value.
- CGamesPlay 4y agoOne of the interesting things about MMM and borrow checking is that it enables you to implement GC and RC. Rust has RC built in of course, but the general consensus seems to be that it's "not idiomatic". There's also crates for GC. Would a Rust project that relied heavily on GC be able to sustain the sort of velocity that a project in a native-GC language had? Would it even be close? I love Rust's developer experience, frankly. The macros and build system are the main reason I like the language. I hate the borrow checker most of the time, for exactly the reasons listed in the article. It's probably a terrible choice for a 7DRL project, unless it was some sort of Rust core with content that was primarily orchestrated from another language (possibly DSL).
- kaba0 4y agoI’m not sure regarding the benefits of adding such a library-GC (that effectively does RC with cycle detection) to Rust. RC is just very slow and there is a very good reason that no performant managed runtime uses it. They are good in that they need no explicit support from the runtime, but that only makes them possible, not performant. I would wager introducing a small rust hot loop via FFI into a managed language is a much saner route, using the respective languages to the best of their abilities.
- zozbot234 4y agoObligate ARC is slow. RC/ARC as used in Rust (ARC separately marked, only used when required for thread safety; RC in general only for objects that may need to be kept around by multiple parts of the program, with no fixed "owner"; with simple RAII used for everything else) is very fast, comparable to manual memory management.
- kaba0 4y agoIt can remove a few increments/decrements (more like a single pair at inlining a function), but that’s not what makes it problematic. If you do have a bigger object graph, not using it anymore will recursively go on and decrement the counters, removing potentially many objects from memory, totally killing the given thread’s cache/performance. All that is amortized with a tracing GC. On top, atomic counters are very expensive. Of course you can probably get away with using (A)RC at few places at most with Rust, but if you decide to track object lifetimes with RC for loads of objects, it will have a price (which may or may not be worthy. In my opinion, it is better to stick to Rust for low-level programs)
- fuklief 4y ago> In other words, CHERI can reduce memory-unsafety related slowdowns by two thirds, which is pretty incredible. AMD CPUs are even starting to have hardware support for it, bringing its run-time overhead down to 6.8%. Source on AMD CPUs having support for CHERI-style capabilities ? Afaik, there is only the Arm Morello prototype out right now and FPGAs.
- deleted 4y ago[deleted]
- littlestymaar 4y agoI don't think this article is that interesting because it's really biased, and doesn't even try to catch any kind of nuance, especially regarding Rust. Developer velocity in Rust is a complex topic, and yes sometimes Rust will slow you down, but sometimes also it makes you move much faster. You can find a lots of testimonial in all directions, the majority of Rust users having a good opinion on Rust on that topic (but we're biased too). But somehow this article only chose to quote people complaining about developer velocity with the language and completely ignore the other (and larger) group of developers, praising the language user experience and development velocity. I don't think Rust is perfect, and I think that people talking about how “Rust is the most loved language on Stack overflow for the past N years” isn't really constructive. But a collection of cherry-picked quotes showing how Rust is in fact a disaster isn't bringing anything interesting to the discussion either…
- pjmlp 4y agoIs biased and incorrent in a few places, like disregarding system programming languages with GC that also support deterministic destruction of resources.
- littlestymaar 4y agoI'm not surprised: when you read something and the part you know about is bullshit, there's a good chance that the part you don't know about is also bullshit even you can't see it. What language have both GC and deterministic destructors, and how does it works? I'd guess it couldn't be tracing GC (because the GC runs whenever it wants, so you don't have determinism, or at least that's my understanding). Or maybe it's something like RAII for non-memory resources (with a destructor that doesn't free memory), and a GC for memory management?
- pjmlp 4y agoMesa/Cedar, Modula-3, Active Oberon, D, Nim, for example, not to make an exhaustive list. C# also does provide some mechanisms to dive into it, since version 7, although not as easy. Basically you can use GC heap as usual, or native heap with untraced references, stack or global memory segments. Value types with constructors/destructors pairs are also supported. So you have all the building blocks to do C++ style RAII when needed, otherwise relax and enjoy the GC.
- phkahler 4y ago>> As you can see, software development can be much more expensive than power usage, so it makes sense to primarily optimize for development velocity. No? Those developers can take time off, but the electricity can not. I think he showed how important optimizing software performance is at scale. When you electric bill is $3Billion, you gotta write efficient code, not write more code as fast as possible.
- manholio 4y agoThat example threw me off too because both the numbers and the perspective are non-nonsensical. 90% of the energy draw of those data-centers goes into things like inner video encoding loops, SSD/memcache storage and retrieval, ML algorithms etc. But the vast majority of those 27.000 engineers do not work on such low level routines, but on things like millions of lines of crufty Python that power Adsense analytics, which are essential for maintaining a revenue stream. Yes, development speed is very important but it's mostly orthogonal to other operational costs if the right tools and architectures are employed.
- verdagon 4y agoAuthor here, that might actually make the comparison stronger: not all energy in a data center is wasted by the memory safety approach's drawbacks, meaning it makes less sense to optimize for memory safety overhead. But if I'm being pro-Rust, I would also say that not all coding is affected by a memory safety approach's downsides; there are some domains where the borrow checker doesn't slow development velocity down at all. Either way, I definitely agree that its orthogonal to many operational costs. I'll mention this line of thought in the article. Thanks!
- zozbot234 4y agoDeveloper velocity is a crock. You want to write code that actually works over the entire software lifecycle, not just crank out piles of utterly broken sh!t that you'll have to fix later at huge cost. Rust has it right, and Ada/SPARK even more so.
- galangalalgol 4y agoIf you know algorithmically what will work sure, but if you don't, and you need to throw multiple approaches at a problem until one sticks, then a prototyping language is extremely helpful. The problem comes when management notices the prototype mostly works, they want you to ship it rather than make something sane now that you know which direction to head. I find using matlab is useful for this. Managers seem to understand that you don't ship matlab, where if I used numpy or julia...
- thefaux 4y agoThis is interesting. It strikes me that if you think that you know a better language for writing a program than whatever your organization uses that there is nothing stopping you from writing your prototypes in that language and then porting them back to whatever the org uses when you're done. This is similar to the technique of writing a grammar with a parser generator and when you're happy with it writing a custom parser by hand.
- FpUser 4y agoI like how automatic memory management / safety in general implemented in Cone language.
- Ygg2 4y agoWhat does Cone do? First time hearing about it?
- FpUser 4y agogoogle cone programmer language. Short answer - your general computer language that is not ready for any practical use.
- verdagon 4y agoAuthor here, Cone is a pretty fascinating language. It builds a borrow checker on top of any user-specified allocator, whether that be single ownership, reference counting, arenas, garbage collection, or any other user-specified strategy. A user can even code their own. It's a very promising approach, because it preserves the borrow checker's strengths while addressing its the borrow checker's development velocity downsides. GC and RC often make a program's overall architecture looser and more flexible, but by offering borrow checking for everything else, it allows a program to much more cut down on its memory safety overhead. What Cone does differently than other languages is that it decouples the allocation strategy from the type of data you're working with. This makes it much easier to change your code to use different memory safety styles. In a way, it's like Rust but allows for more flexibility on memory management. It's still in progress, but I encourage anyone interested in languages and memory safety to take a look: https://cone.jondgoodwin.com/ https://cone.jondgoodwin.com/
- zozbot234 4y agoUser-specified local allocators are planned for Rust too. Among other things, they're needed for feature parity with C++.
- 4y ago
- snovv_crash 4y agoMemory isn't the only resource that needs management. File handles, network sockets, locks, security codes and more, all need to have deterministic lifetimes. If you language doesn't support lifetime management via some mechanism then all of these things are the next part that will bite, even if you have GC for memory.
- galangalalgol 4y agoThis gets missed a lot. Rust isn't memory safe, it is resource safe.
- hoseja 4y agoIsn't it the other way around?
- vlovich123 4y agoHow so?
- galangalalgol 4y agoMy point is that it is both. The borrow-checker protects every resource, not just memory.
- snovv_crash 4y agoIt's funny that people are assuming I was talking about Rust when I was actually referring to modern C++. RAII is a powerful concept.
- galangalalgol 4y agoIt is, I've written c++ as my primary language for 30 years. I skipped c++14 and I'm still using 17, but staying up to date other than that. But RAII doesn't come anywhere close to the borrow checker in the number of mistakes it prevents.
- pjmlp 4y ago
- UltraViolence 4y ago"Rust has made the decision that safety is more important than developer productivity. This is the right tradeoff to make in many situations — like building code in an OS kernel, or for memory-constrained embedded systems — but I don’t think it’s the right tradeoff in all cases, especially not in startups where velocity is crucial." I completely disagree with this statement. If a Rust developer takes longer to code some feature this time will eventually be saved fixing memory bugs later on. And don't forget the immaterial cost of losing customer confidence if the product crashes or glitches because of memory instability. And then I'm even glossing over the enormous benefit of Rust when writing correct multi-threaded code, which is almost always a minefield in C/C++. Code that looks and seems to work OK might in production suddenly crash after a year or so. A complete nightmare! Memory safety is ALWAYS a good thing to have.
- Tade0 4y agoMy take is that it was always about expanding the pool of people capable of writing safe code, thus making it cheaper. I spent most of my career in front-end, where such considerations are way down the priority list, but even I was able to produce something in Rust that compiles. That being said I never understood why would anyone want to use this language for web development - most problems are solved in that space, so if you're not out to tackle tje unsolved ones, it might not be worth it.
- allochthon 4y ago> That being said I never understood why would anyone want to use this language for web development On the backend, at least, Rust would be a significant improvement over Ruby, for example, once a business has gotten past the initial prototyping phase. I've spent years in Ruby development, and the duck typing makes refactoring a production system scary and drama-prone. No matter how carefully you proceed, there will be gaps in test coverage, and you'll regularly see new bugs in production from the refactoring work that would never happen in a typed language. I would gladly work in Rust over Ruby in a web development context. (Although my preferences lean towards Rust, there are no doubt many other typed languages that could do a good job here as well.)
- IshKebab 4y agoInteresting (though clearly biased) article. I suppose we shouldn't be too surprised about the bias given the source. My main issue with it is the focus on short term developer velocity. Fine if you are writing a game in a week and then stopping. Most people are not doing that. It has a great list of interesting new languages to look at!
- neonsunset 4y agoThis article is biased in more than one way and misses a lot of nuance and aspects of GC-based languages which are not limited to pure GC and employ a lot of techniques for deterministic and semi-deterministic memory management, and various trade-offs to optimize for single/many-core and throughput/latency scenarios. In fact, many modern garbage collectors are not dissimilar to arena allocators making most of the allocations very cheap and efficient. In addition, Rust is difficult to use for iOS as it stands today but you can for sure make it support a variety of scenarios with delegates aka callbacks/function pointers/etc. Also RAII can be supported with .drop() and more. Half of the cons are incorrect and misrepresent current state of affairs. It also recommends defaulting to Go over C# for making a web server which my religious views compel me to publicly object to :)
- verdagon 4y agoAuthor here, you're correct that there are a lot of performance tradeoffs involved with various GC'd languages, and also correct that GC'd languages do have some support for deterministic destruction (especially with defer). The article was trying to focus on the general approach of GC more than the GC'd languages themselves, and the article was already pretty long so I tried to keep it scoped to just developer velocity implications of the memory safety approaches themselves. I did mention some of those aspects, for example how C# is more than just a GC'd language (it has value types to help avoid GC), and Rust is more than just borrow checking (it has RefCell). But I couldn't get as deeply into these other aspects as I would like. (It's also pretty funny that the article's been called biased by both sides, in both directions now! Such is life.) I also don't mean to specifically recommend Go over C#, and I see the line that gives that impression, fixing now.
- jmyeet 4y agoSo this particular problem is severely time-constrained. Performance doesn't relaly matter. In those situations you tend to use the highest level language you can. This isn't surprising. The author argues it's similar for startups. I agree to a point. For GC in particular I think the costs are underestimated. Processes blowing up because of memory leaks (which can still happen), dealing with stop-the-world ("STW") pauses and inconsistent performance are all real problems. So much of this is situational. For example, I think Objective-C/Swift was so successful on iOS (vs Java on Android) in part because it opts for reference counting instead of GC. This is predictable performance and less complicated. But RC isn't necessarily appropriate for a server as you may create hot spots and degrade performance that way. Rust by virtue of borrow checking isn't a panacea. It does however greatly reduce the chances of making a whole class of really important bugs (ie memory safety and all the entails like buffer overruns). Comparing it to Python, Go or Java doesn't necessarily make sense. Rust lives in the same domain as C/C++. One funny side note: > Google used 15.5 terawatt hours of electricity in 2020 Bitcoin used 200 TWh in 2022 [1]. Think about that. [1]: https://www.cnet.com/personal-finance/crypto/bitcoin-mining-how-much-electricity-it-takes-and-why-people-are-worried/ https://www.cnet.com/personal-finance/crypto/bitcoin-mining-...
- mprovost 4y agoThis is a really interesting observation: "Stateless programs like command line tools or low-abstraction domains like embedded programming will have less friction with the borrow checker than domains with a lot of interconnected state like apps, stateful programs, or complex turn-based games." In my book [0] teaching Rust, I manage to completely avoid using lifetimes. Perhaps this is because it reimplements a command line utility (head, wc, cat, ...) from the original BSD sources in each chapter and none of them are stateful. Most of the classic Unix utilities just process streams of bytes and barely use data structures at all. Many don't even call malloc(). It feels like Rust is a good match for the problem domain but I never made the connection with the stateless nature of these tools before. This bodes well for eventually replacing the coreutils with modern Rust implementations. [0] https://rftgu.rs/ https://rftgu.rs/
- verdagon 4y agoThis was a particularly fascinating realization of mine a few years ago. I realized that for certain domains, the borrow checker was a dream to use (command line tools and scripts, ECS games), and in others it wasn't so much (GUI, turn-based games). I dove a little deeper, and the stateful/stateless distinction seemed to be the best rule-of-thumb for predicting how much one would be in conflict with the borrow checker's preferred styles. It was also reminiscent of functional programming languages, in a way. I suspect this is why most discussion comparing Rust to other languages devolves so quickly, and has become so polarized: it depends on the domain. Users who try to use it for some domains will hate it, and users who try it on other domains will love it. This is also why I recommend newer Rust programmers to not be afraid of using Rc/RefCell in certain domains. Some domains don't agree as much with the borrow checker, and Rc/RefCell can make the architecture a lot looser and easier to work with.
- Jensson 4y ago> I suspect this is why most discussion comparing Rust to other languages devolves so quickly, and has become so polarized: it depends on the domain. The problem is that Rust proponents argues that Rust is better for all domains. I don't think anyone says that Rust doesn't have a place, the source of controversy is whether every low level programming task is best done in Rust or not.
- amai 4y ago„MMM (manual memory management) isn't really advisable for something exposed to the network.“ Nowadays basically everything is exposed to the network.
- warangal 4y agoI write most of my code in Nim language, and it generally involves wrapping up some C codebase, or calling DLLs routines and working with raw pointers. Although Nim has it own GC or ARC to handle memory management for its native data-structures, i find it really helpful to define a `destructor` for any arbitrary objects/structs. Since language can track lifetime of any object/struct during compilation and can call corresponding `destructor` for that object, which generally is just a `free()` or `some dll exposed routine`. I end up using language to handle all the manual memory management even for existing C codebase. With new ARC, all destructor calls are inserted with compilation and hence no extra GC based runtime to deal with, and even works flawlessly with GPU programming stuff too ! I haven't used many programming languages, but personally find it really useful to use any language as an assistant to help solve issues outside of their intended context. I also have written about patterns i find useful when dealing with existing C codebases at https://ramanlabs.in/static/blog/raw_memory_management_with_hooks_and_arc_in_nim_language.html https://ramanlabs.in/static/blog/raw_memory_management_with_...
- intelVISA 4y agoNim is a sleeper, plenty of GC options from ORC to manual and great C FFI. Wish the big corps had backed it, or Zig, over drab stuff like Go.
- planetis 4y ago> Lobster is using borrowing and other static analysis techniques under the hood to eliminate a lot of reference counting overhead. Nim is one of the first languages to use borrow checking to prevent copies and ref counts, and it's done both explicitly with the experimental 'views' feature and when permitted implicitly.
- zamalek 4y ago> Unsupported Patterns > Graphs; it generally only thrives with a strict tree hierarchy of data. This is actually now supported: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.new_cyclic https://doc.rust-lang.org/std/rc/struct.Rc.html#method.new_c... That being said, Rust has taught me that I was vastly overusing graphs (structurally, not algorithmically) in my code. Graphs are extremely difficult to reason about; a fact that I learned after approaching an unfamiliar Rust codebase for the first time. It was the brain equivalent of putting down a screwdriver and picking up a powertool, my mind just relaxed. That alone is one reason I think that every developer should try and "suffer" under that constraint for at least one or two real problems (whether with Rust, or some other language). You'll end up writing better code in your preferred language. The removal of a feature is sometimes a feature. While roads limit where you can drive, they also mean you don't have to figure out how to traverse a mountain in a Lambo.
- Jensson 4y agoThat is how you write programs in competitive programming, just put all the data you need in a nice table structure and use indexes instead of references. It is very readable and easy to reason about for simple programs and is extremely fast to write and performant, that is how you are able to implement novel algorithms in minutes. But it doesn't scale, indexes aren't type checked nor do they tell you which collection they point towards. But yeah, knowing how to program like that is useful, learning new style will never hurt, but being forced to code like you code in competitive programming isn't a good thing for a language.
- H4ZB7 4y ago[flagged]
- comex 4y ago> In an average Google Earth quarter, only 3-5% of bug reports were traceable to memory safety problems, and Address Sanitizer made them trivial to reproduce in development mode. Bug reports, sure. But as for security vulnerabilities, both Microsoft and Google have reported that roughly 70% of them were memory safety issues. Personally, as a Rust fan, I fully agree that the borrow checker limits developer velocity, and I'd be happy to toss it if I could. But verdagon has been promising memory safety with no overhead for years; I'll believe it when I see it. Edit: Okay, that was unfair to say without further context, so let me add two things. First, although Vale is open source, the design has changed over time and the implementation was described as a "work-in-progress" as of two months ago. [1] Second, a month before that, verdagon described the design as providing "statistical safety", meaning use-after-frees may fail to be caught but are caught "99.9999999999996% of the time". Now, stochastic exploit mitigations such as ASLR and PAC are valid defenses, as long as that 99...% also applies in the presence of an active attacker. But the specific design described (allowing generation counters to wrap) sounds like, in many scenarios, an attacker could manipulate it to provide no protection at all. There may be ways to mitigate this, but in context it does sound like it's designed under the assumption that memory safety violations will occur at random, rather than being designed to defend against attacks. This might be good enough for (some) games, but not for most Rust use cases. [1] https://verdagon.dev/blog/zero-cost-memory-safety-regions-overview https://verdagon.dev/blog/zero-cost-memory-safety-regions-ov... [2] https://verdagon.dev/blog/generational-references https://verdagon.dev/blog/generational-references
- henry_viii 4y agoSurprised to see no mention of V. I assumed it was using a model similar to Lobster?
- oconnor663 4y ago> Aliasability-xor-mutability is just a rough approximation of the real rule, dereference-xor-destroyed. This is true in a single-threaded context, but in a multithreaded (or interruptible) context, aliasing-xor-mutability is the real rule for everything other than atomics. Breaking that rule is a data race, which is per se UB in C/C++/Rust/Zig/Go/Swift.