Is Ada safer than Rust?
old.reddit.com
old.reddit.com
Rust has a great story with memory safety though it’s worth noting that SPARK is adding pointer ownership analysis (inspired heavily by the borrow checker, which really is a big deal). In practice, as others mentioned, heap allocation isn’t needed that much with Ada, and passing by reference without needing pointers is common using “in out”.
Ada’s contracts and strong type system make it easier to design correct programs - is that “safer”? I don’t know. I wish _both_ languages were in wider use. I really enjoy Ada programming but envy the excitement and community being built around Rust. Hopefully Rust’s popularity leads to more enthusiasm for Ada and the unique correctness and safety advantages it brings.
Maybe the next GNAT release will have a “Rust” FFI import mechanism (like it does now for C and Fortran) so Ada code can more easily take advantage of all the great Rust libraries being written.
The novelty is doing the above at near C and C++ performance levels, not the protection offered.
Rust is for the move fast and break things mainstream, where such “safety” is good enough.
Ada and SPARK are for safety-critical systems. In other words, it’s playing in a different league.
Rust code to assert a runtime precondition or postcondition a > b then handle it as you wish:
assert_gt_as_result!(a, b) -> Result
https://crates.io/crates/assertablesFor what you're asking, the assertables crate has a macro that will handle any condition:
assert_as_result!(condition) -> Result
And you can alias it as you wish such as: use assertables::assert_as_result as precondition;
And now you can write what you're suggesting: precondition(a == b)The most typical example, in C, output arguments, passed by pointer, a pattern that I also use in C++ because I find passing by non-const reference error-prone since it is not obvious looking at the calling code that an argument may be modified.
But what about NULL? Sometimes it is a good thing that NULL is allowed, sometimes, it doesn't make sense. So again, not obvious. So what to we do? You can document it of course, but the problem is that compilers don't read the docs, and therefore can't tell you if you are doing it wrong. You can play it safe, and design your API so that NULL is always an option, and avoid NULL when using others APIs, but it leads to unnecessary and performance-impacting checks. Preconditions and postconditions would solve that problem: if you pass an argument that can be NULL to a function that doesn't accept NULL, the compiler can warn you. Plus, there is optimization potential, in the same way that C/C++ does with undefined behavior, but this is explicit. You also can also get the choice between safe (runtime checks) or fast (undefined behavior) at compile time.
Making it a core feature of the language rather than an extension (like your rust crate) will help compilers and other tools to take full advantage of what it brings.
https://learn.microsoft.com/en-us/cpp/code-quality/using-sal...
I don't think there's all that much that a typical compiler will do with them however sophisticated enough type system I can see some wins.
VS code makes it pretty obvious by adding a visual & prefix to the argument. I hope that kind of visual help becomes widely adopted.
https://www.google.com/url?sa=t&source=web&rct=j&opi=8997844...
We have a linter that will try to catch cases where you didn't null check but the field is nullable
https://learn.microsoft.com/en-us/dotnet/framework/debug-tra...
https://old.reddit.com/r/rust/comments/17miqiu/is_ada_safer_...
In the design by contract case, there's a lot of experimentation (I linked this https://old.reddit.com/r/rust/comments/17miqiu/is_ada_safer_... in another comment) and while all of them are converging to the same syntax, they all have wildly different implementations.
Perhaps the stdlib could provide a base syntax for contracts, with extensibility APIs so that libraries or compiler plugins or external tooling can determine whether the contract is checked at runtime or at compile time, and by which method. But that demands a lot of design, because once something is in the stdlib and stabilized, it's here forever.
Which you have to prove, which is absolutely non-trivial. I guess it could be made into a runtime check as well where static analysis is not possible, but that seems to be a quite hard to reason about language regarding performance.
He's not, he would respect your opinion, but design by contract was on of the key foundations of Eiffel, and I have a soft spot for Eiffel.
Also: Maybe not everything goes in the compiler?
assert_gt!(value1, value2); // value1 ≥ value2
That should be ">" rather than "≥". (Or "assert_ge" rather than "assert_gt".)At the same time: there’s a reasonable practical argument that both have essentially safe semantics, and that “safer” one is really just the more successful (easier to integrate into existing codebases, more online resources, &c.) one. Rust is (thus far) winning at that.
when the dust settles and hindley-milner types, rank-n types, substructural types, etc, all complete their respective journeys from "weird thing the academics came up with" to "state of the art in hip new language that managed to compellingly package it" to "fact of life", it is my hope that dependent types will follow suit -- something that bridges the ux gap between theorem prover and general-purpose language where anything from ownership and borrowing to refinement types lives under one HOL umbrella and lets you make just about any guarantee you like. i recommend anyone reading follows the f* project
(Yeah, I know about temperature, but AIs are dumb as hell especially at logical inference stuff, so I just went with the comment in a satirical way)
If AI wrote the proof, this would be no different than having Copilot fill in some code, it's just code you check into the repo.
These proofs often involve writing code, any code, that will pass the type checker. If you can write code, no matter what that code is, and it passes the type checker, the assertion is proved. It's such a well structured problem, "just write code that satisfies these type constraints, any code will do, as long as it type checks", that I think AI might be able to do it quite well.
I've commented on this before and it wasn't well received then either. I think most people have never coded in dependently type language and don't appreciate how often you simply want to fill in the holes and connect the dots with any code that type checks. It's been several years since I experimented with dependent types, so I forgot a lot of the details, but I do remember often wanting to just "fill in the gaps", and indeed, there are IDE tools that can often fill in the gaps for you.
(Another thing I was surprised to realize about languages with strong type systems is how often there is literally only one possible implementation of a function.)
And you are probably right that many of the trivial cases can perhaps be guessed by some AI — but I think in these cases a simple, more deterministic algorithm could also find a match, iterating through a few proving strategies (I believe this is how the aforementioned idris demo worked). What might have resulted in your downvote (I didn’t downvote your comment, I think it adds to the discussion!) is that many people are tired of the over-hype of LLMs, and taken your comment blindly as support of that.
With that said, I do think that you overestimate the capabilities of LLMs, as my go to example: they can’t solve even Sudokus. And any other similar, “recursive” thought is simply fundamentally impossible by LLMs in a single step.
It is also the barrier in the popularity of dependently types languages - it is easy to give a proof of List::head. Database::connect on the other hand goes through multiple layers of the whole stack, and function proofs do not compose — two trivial to prove functions composition might be impossible to prove, e.g. I can compose 2 such functions and get some unsolved math problem of your choice.
Seems like ChatGPT-4 can? And that's not the advanced data analysis model, either.
https://chat.openai.com/share/3126e737-3ae5-4f63-996b-b5a768...
https://en.m.wikipedia.org/wiki/Eiffel_(programming_language...
https://en.m.wikipedia.org/wiki/Design_by_contract
Unfortunately it suffered from some of the same issues as Ada:
For a long time, only expensive implementations available, and a somewhat verbose syntax.
https://ferrous-systems.com/blog/officially-qualified-ferroc...
This naming convention avoids acronym capitalization ambiguities and reads more like natural written language. For example, instead of normalizing the inconsistently-capitalized identifier XMLHttpRequest as XMLHTTPRequest, XmlHttpRequest, or xml_http_request, you would use XML_HTTP_Request.
In my .vimrc, I mapped space to ; to enter VIM command mode:
noremap <Space> :The safest language would be something like Elm or Datalog, where the type system ensures crashes aren't even possible. But then you just make up your own idea of failure, where instead of crashing the program produces unexpected output, almost like UB.
Safe Rust can't segfault, unless you're using unsafe code that is buggy, which isn't that much different from using buggy JNI.
Beyond just memory safety, Rust has a stronger type system than Java — tracks mutability, ownership, and thread safety that Java doesn't.
Search the gnat bug tracker for stack overflow: 14 bugs https://gcc.gnu.org/bugzilla/buglist.cgi?quicksearch=Ada%20s...
Rust: 243 (plus 830 closed) https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Ao...
Choose by yourself which seems safer
Edit: Part of the problem is your search term is `stack overflow` not `"stack overflow"`. Many of your results are issues where the reporter included a stack trace and someone mentioned the word "overflow".
It's odd. Why advocate for a language you don't use?
Here are some common giveaways:
- "Ada has a garbage collector" - It's optional part of the specification, in practice most compilers don't implement it.
- Confusing SPARK (the formal verifier) with Ada, or even claiming that SPARK is now part of the Ada spec. This is simply not true.
- Not knowing that contracts are enforced at runtime and they're typically disabled in release builds.
- Claiming that Ada is memory safe. Ada doesn't have a borrow checker. Ada doesn't have smart pointers out of the box (unique_ptr is actually unimplementable due to lack of move semantics). Typical non-embedded codebase is full of "new" and "Unchecked_Deallocation", usually wrapped with controlled types, much like C++ RAII.
I am a novice-intermediate Ada user (and I started with SPARK before moving to just Ada), but a lot of the arguments in favor of Rust mention that "there is a crate for that". I would say you need to compare vanilla Rust "out-of-the-box" with Ada for a fair comparison.
Another reason I prefer Ada is because I find it boringly simple like Pascal even though it is verbose, whereas I find Rust very obtuse, and I have a personal bias for array languages and ML languages. I wish Rust were more F#-like.
Smart pointers are vanilla rust shrug.
But also, it's pretty fair to mention the availability of crates, because they're easy to integrate, liberally used by the project itself (go browse https://github.com/rust-lang and you'll see a number of projects for libraries distributed as crates rather than part of the stdlib), and there's a large breadth of available packages.
The internet tells me Alire is a (the?) package manager for Ada, its listing has 373 entries right now (https://alire.ada.dev/crates.html).
Simple odds say you're more likely to find a crate for that than an ada package.
Yes
This is a strength and a weakness in Rust
The crate ecosystem is broad an deep. It is seemless to integrate crates if you are connected to the internet. That is a strength
But it is also a weaknesses. "seemless to integrate crates if you are connected to the internet" but of unknown provenance and varying quality.
There are steps you can take, tools you can use to ameliorate the issue, but it is a real danger
It depends what you are working on. For systems which must be secure and reliable -weapons, flight control, banking, maybe Ada is a better choice
For me I make musical instruments, and I will stick with Rust for that
I know Rust, not Ada. A very interesting discussion for me to
More regular and verbose syntax is easier to learn, but requires more actual reading when you use it.
More concise but complex syntax takes longer to internalize, but then you can see more at a glance, so it lets you do more visual pattern matching and puts less strain on working memory.
-Spark do verify contract using static analysis and proof. -While Ada is not as memory safe as Rust it's a lot more memory safe than popular languages. -Its one of the easiest languages to get compliance with safety standard DO-178C or DO-333 ...
Having worked on several Ada projects professionally I can tell you that this is definitely not true.
DO-178C applies to the process and does not make assumptions about programming languages.
Popular languages typically have garbage collectors and are memory safe. If a language is not memory safe, like Ada, then it's automatically one of the least memory safe languages, measured by amount of use.
Yes
And those languages are unsuitable for real time systems
Where Rust, and it seems Ada, excell
Soft real-time is absolutely doable with a GC, depending on the required targets. Java’s low-lat GC (ZGC) has <1ms max pause times - you might not make the latest AAA game with it, but for the vast majority of popular games that is more than good enough.
[0]:https://learn.adacore.com/courses/Ada_For_The_Embedded_C_Dev...
Really? Expand on that please. I did not think so
> Soft real-time is absolutely doable with a GC
Some slippery definitions here. Clearly there is a middle ground (where I live) where rust works. GC languages do not
One GC pause, ever, is too many
Regarding the non-normal language: with hard real-time you wouldn’t want to allocate willy-nilly and rust doesn’t yet have generics for allocators (correct me if I’m wrong on this, I am not up-to-date here), so careless usage of the standard lib, or other crates is a no-go. For illustrative purposes, this is the same with C++ and `noexcept`.
> Some slippery definitions here
I don’t see the slippery part - it is a slope, though. Depending on what’s the latency requirements and to what percentile should it happen, you can use Rust (and other low-level languages) on the lower end (audio processing), some managed languages in the middle (many kind of games are absolutely fine with that - a single drop of frame is more than fine, hence the soft rt), and pretty much any managed language on the high end.
It is routine for Rust code to run without an OS (e.g., on microcontrollers).
1: https://docs.rust-embedded.org/book/collections/index.html
Not seen that anywhere, on Reddit or HN. I mean Ada is rarely even mentioned. On HN, Ada sometimes is hated by many. And this is speaking as someone who gets all the fingers for bringing up Ada whenever someone said Rust is the only PL for safety critical applications.
I am actually rather surprised this Submission gets some many people commenting.
And to be honest I think most of those point aren't because they dont know the language, it seems to be more like lacking in context. ( Which is often the case in any online discussions )
https://docs.adacore.com/spark2014-docs/html/ug/en/usage_sce...
For example: "SPARK builds on the strengths of Ada to provide even more guarantees statically rather than dynamically."
---
For people who want to read more about pointers in Ada:
https://www.adaic.org/resources/add_content/docs/craft/html/...
http://archive.adaic.com/tools/CKWG/Reference_Counting_Point...
https://learn.adacore.com/courses/intro-to-ada/chapters/acce...
https://www.adacore.com/uploads_gems/03_safe_secure_ada_2005...
https://blog.adacore.com/using-pointers-in-spark
---
Memory safety in Ada / SPARK:
https://www.adacore.com/uploads/techPapers/Safe-Dynamic-Memo...
Still, not all languages can assert having 7 commercial vendors in business, lasting 40 years and counting.
(but perhaps the earlier stuff wasn't practical: "Early Ada compilers struggled to implement the large, complex language, and both compile-time and run-time performance tended to be slow and tools primitive" ... "By the late 1980s and early 1990s, Ada compilers had improved in performance")
A safer language is one in which the probability of a competent person making a mistake (that makes it into production) is lower.