7 ms·
Ada doesn't have compile-time-safe dynamic memory allocation and deallocation (i.e., tracking a pointer so that you know statically that it's no longer used els
by geofft 6y ago
Ada doesn't have compile-time-safe dynamic memory allocation and deallocation (i.e., tracking a pointer so that you know statically that it's no longer used elsewhere in the function that frees it). Rust does it through the lifetime system, which is based on Cyclone, which long postdates Ada.
The usual alternatives are to statically allocate all your memory, to convince yourself it's safe to use Unchecked_Deallocation, or to use a GC/refcounting library. Static allocation is usually not a problem for special-purpose embedded control applications: e.g., your airplane has two wings and one set of landing gear and its position is described by three coordinates, and you'll never need more of those. You probably want to avoid malloc anyway for both predictable performance and not having to worry about whether your allocation will succeed. But if you're writing, say, a CSS engine or a grep replacement or a terminal emulator, that approach won't work.
GC works for those use cases, but there are a number of excellent memory-safe GC'd languages already in wide use for many things, like Python and Java. You can get very good steady-state performance with Java, sometimes higher than equivalently-complex C, but it's still not a language you'd want to implement loadable libraries or OS kernels in.
Rust solves the problem of making writing high-performance, C-drop-in-replacement code feel much like (definitely not exactly like :) ) working in a higher-level language like Python or Java, including the memory-safety parts of that experience. Ada addresses memory safety, but for most of the use cases people are excited about Rust for, they want the combination of those features. For things like flight control software, picking something extremely mature (usually the companies in these press releases have existing Ada code from previous projects dating back decades) is valuable and having safe dynamic allocation isn't really a requirement.
- Rochus 6y agoAs described in another post Ada has features to avoid the problem Rust want's to solve in most cases. You can e.g. allocate varable length arrays on the stack.
- kqr 6y agoAda also lets you create ad hoc local reference types and disallows references escaping beyond the scope of their type. This is an insanely powerful combination for ensuring references do not leak beyond where they are supposed to.
- Rochus 6y agoYes, thanks. There are a lot more examples. I wish someone with deep knowledge and real experience in both Ada and Rust would write a side-by-side comparison covering all relevant aspects, including more recent developments like https://www.adacore.com/papers/safe-dynamic-memory-management-in-ada-and-spark https://www.adacore.com/papers/safe-dynamic-memory-managemen....
- geofft 6y agoI've seen that before - is there an implementation, and also, how do the usual users of Ada feel about it? I feel like one of the attractions to Ada for this sort of use case is its maturity, and "here's a proposal for a complicated feature, inspired by Rust, a language which young and rapidly evolving and in particular switched to a new borrow checker implementation less than two years ago and shipped it with known unsoundnesses and is working on a new borrow checker implementation as we speak" may not be attractive to Ada's usual users. :) (To be clear, I'm fine with the risk profile of Rust's borrow checker, but in part that's because I'm fine with the risk profile of using the latest stable Rust and picking up any fixes every six weeks. I'm fine with a more powerful feature that lets me develop code quickly and I'm fine with upgrading my compiler every six weeks to pick up any bug fixes; I imagine that people writing airplane control software are probably going to prefer something less powerful that hasn't changed in decades.) Honestly, I think one of the questions here is community. I don't really know who the Ada community is, beyond press releases from Adacore about planes and trains. I suspect that community simply does not care about safe dynamic allocation, even if it were available as a supported option, so they aren't going to be excited about testing out this feature. Is there a user community who would use this, in production (doesn't have to be a company, the "serious hobbyist" open source dev is fine and probably even preferable here), within the next five years or so? Are there folks writing stuff like high-performance grep replacements in Ada or hardened HTML 5 implementations in Ada? I'd love to see (or help with!) such a comparison, but I get the sense that Ada's and Rust's use cases are so different that writing a fair apples-to-apples comparison is hard and even finding someone to do it would be hard.
- 6y ago
- pjmlp 6y agoAnd if the allocation fails (stack overflow) one can re-execute the same function with a smaller allocation size.
- foerbert 6y agoI'm not super knowledgeable about Rust, but I have tried poking at it a few times, so... you know. Rust seems to be extremely focused on memory safety. Meanwhile Ada is much more focused on correctness in general. Restricting the discussion to simply memory safety ignores, well, most of anything that might be programmed. Ada also has more memory safety options than people tend to talk about. As others have mentioned, it's possible to allocate quite a bit on the stack. Other rules also prevent some reference issues. One thing I rarely see mentioned are memory pools and subpools. It is possible to ensure whole types are allocated in a particular subpool, and deallocation can be left for when the subpool falls out of scope.
- Jtsummers 6y agoI like Rust, but my interest in it dwindled when I realized the safety/correctness focus was almost exclusively on memory safety, with regard to its "value add". Ada's type system offering things like custom, incompatible, integer ranges (even if they cover the same range, cross-type assignment requires explicit conversion) was the safety I needed for work. Memory safety is great, and a worthwhile goal, but was not the thing holding back (most) of the projects I've participated in (that said, memory safety was a notable issue in one adjacent project, I was not on it but memory safety and concurrency was the primary source of bugs for them).
- geofft 6y agoI actually wouldn't say that Rust's safety/correctness focus is exclusively on memory safety. I think it's an easy and clear thing to point to, but compared to C, you've got the following features: - Nullable types (Option<T>), maybe-error results (Result<T. E>) etc. that force you to check whether you're looking at the right variant. You can't have bugs where you fail to check the error value and you use invalid/meaningless data, because you syntactically cannot express access to the data. This does often manifest as avoiding NULL pointer dereferences, which is technically a form of memory unsafety, but it's really preventing a logic bug. (For instance, this would have made the "goto fail" bug unnatural to write; that one was returning err = 0 as if it were an error, which you can't really do in the Result model.) - More generally, sum types / tagged enums and the match and if let constructs, which enforce at compile time that you're accessing data from the right variant. - Locked data that enforces that you hold the lock when you access the data, using similar means. You can enforce that there's no direct access to the data except through the lock wrapper, and more importantly, you can enforce that the lock stays locked as long as someone holds a direct reference to the data (i.e., that you can't leak a reference to that data and use it after you've released the lock). - Safe threading/concurrency via labeling which types can be moved between or shared across threads. Again, this is technically a form of memory unsafety (data races) but it's more about logic. - Typestate. You can avoid bugs where you use some logical resource when it's in the wrong state (read/write a closed file handle, send protocol data while you're still handshaking, etc.) if your API consumes ownership of the object in one state and returns the object in another state, and you don't have methods on objects of the wrong state. Rust pre-1.0 had typestate as a language-level feature, but it's straightforward to implement using the typesystem and the ownership model. Really, I would say the core feature of Rust is a richer type system and the system of ownership and shared/mutable references. The most obvious thing to do with it is to prevent buffer overflows and use-after-frees, but it's not the only thing. (And that's also why I mentioned safe dynamic allocations, which rely heavily on the ownership system; without it, it's still pretty easy to prevent buffer overflows for static allocations.) I don't have a sense of where Ada lines up on these. I know it has a much richer type system than C too, so it's possible it answers many of the goals besides safe dynamic allocations. I just personally see the benefit of Rust as more than just memory safety.
- MaxBarraclough 6y agoNot exactly what you're after but I asked HN about memory-management in Ada recently, and got a response from one of the AdaCore guys. https://news.ycombinator.com/item?id=24361992 https://news.ycombinator.com/item?id=24361992