This is a really good writeup! Thanks @marin for taking your time to create it.
Ada really seems to be an overlooked gem. Especially if you’re interested in Rust, you should definitely consider Ada for the same purposes (and more beyond that).
Three very strong points are that Ada is standardized and, in my opinion, much more readable and that it has built-in concurrency. It’s much easier to do contract-based-programming and it’s overall a much more solid foundation to build you projects upon than Rust.
Admittedly, Ada doesn’t have such a vocal “following” like Rust, but its usage alone in nuclear power plants, planes, etc. speaks volumes.
That makes a lot of sense, since readability is an explicit design goal of Ada. (Ada Reference Manual, “Design Goals”) Readability is not a design goal of Rust.
First, “much more readable” is very subjective. Second, yes, rust has more momentum outside of nuclear power plants, which means there’s a lot more crates for everyday programming (e.g. zstd bindings, an AWS client, etc.). Seems like more Ada crates are GPL (looking at “ada web server”) which also restricts the scope in which they can be used.
It’s fine to compare the technical merits (what’s that with the builtin concurrency btw?! Have you seen that rust’s stdlib has a bunch of things too?), but just saying that you can swap one for the other is a bit optimistic.
Readability is very subjective. The argument (not trying to get into one) would probably be that Ada uses much less symbology (but 70+ keywords!) and also has a required principle called “linear elaboration of declarations”. This roughly means programs must be unambiguous when read from start to finish. There are mechanisms like limited with to help break circular references.
It’s fine to compare the technical merits (what’s that with the builtin concurrency btw?!
Ada supports types with mutual exclusion (controlled types) and also one-shot and instantiable task types as part of the language itself, which support queueing (called entries, also look up rendezvous).
Have you seen that rust’s stdlib has a bunch of things too?
Rust has a very good stdlib. My point isn’t a denigration of Rust or any other language, or to be an Ada super fan, I’m going for as objective viewpoint and objective comparisons so people understand what it can do, since it doesn’t seem very well known.
You’re not who I was replying to, but yes, these are good points. I’m also used to the linear order of declarations (as in OCaml), and it’s clear Alire is very young.
I’m curious to see what the future holds for Ada. There are things I find personally ugly (mostly that it’s not expression based), but hopefully it will eat some of the space C has held for a long time. I also wonder if someone could implement something like Ada’s rendez-vous in rust…
much more solid foundation to build you projects upon than Rust
One of my favorite features of Rust is Cargo. I used Ada a decade ago, and I don’t recall anything similar. I certainly don’t recall such a wide universe of packages so easily accessible.
its usage alone in nuclear power plants, planes, etc. speaks volumes.
Does it? Wasn’t Ada mandated from on-high for use in these domains? How many nuclear power plants and aeroplanes were developed since Rust was conceived? Why would a language whose mainstay is mission-critical systems be appropriate for domains where iteration velocity is far more important than correctness? I’m not trying to shoot Ada down–I had a really fun time writing some microcontroller software with it, but these are the sort of baseline questions I’m interested in before seriously considering Ada for a project.
I used Ada a decade ago, and I don’t recall anything similar.
There’s something called Alire which has reached 1.0 and is now available. There’s not much there, but there’s a lot of batteries included in the GNAT community install, so I haven’t needed to manually grab anything else yet.
Ada mandated from on-high for use in these domains
Ada comes from a time when defense contractors used over 100 languages and some didn’t even include basic support for basic things like “ensure the correct number of parameters are passed.” Imagine how untenable your current project would be if it included C, C++, C#, Rust, Haskell, Ocaml, Bash, Powershell, Lua, Python, Ruby, Tcl, Java, Clojure, Beanshell, Groovy, COBOL, ALGOL, etc.
How many nuclear power plants and aeroplanes were developed since Rust was conceived?
Ada offers things Rust doesn’t with regard to high-level controls and checks, like the Ravenscar profile, which makes the compiler ensure deterministic behavior of your program, which is super important to real-time systems.
Why would a language whose mainstay is mission-critical systems be appropriate for domains where iteration velocity is far more important than correctness?
Correctness works with iteration time because iterating on incorrect code is unwieldy and you end up carrying hard-to-fix bugs forward. I think you’re assuming correctness is bulky and heavyweight, which I haven’t found in Ada. In my experience, Ada iterates exceptionally well because of short compile times, better cohesion by using packages instead of types for subprogram (function/procedure) namespacing, and centralized checks which the compiler inserts via integrated design-by-contract and constraints on types. They have made it much faster to iterate on the project I’m working on, since I end up writing small cohesive modules with often automated checks in one place instead of rolling a lot of unit tests or distributing manual checks throughout my codebase which need to be modified on every major refactor.
Ada comes from a time when defense contractors used over 100 languages and some didn’t even include basic support for basic things like “ensure the correct number of parameters are passed.” Imagine how untenable your current project would be if it included C, C++, C#, Rust, Haskell, Ocaml, Bash, Powershell, Lua, Python, Ruby, Tcl, Java, Clojure, Beanshell, Groovy, COBOL, ALGOL, etc.
I think this misses the point, which is that Ada didn’t out-compete other languages for these mission-critical domains; rather, it was mandated from on-high. So we can’t infer that Ada was simply a better fit. Notably, I believe once the mandate was lifted, much of the industry returned to C and C++. To be clear, I’m not advocating for C or C++ or even advocating against Ada. I just don’t buy the “Ada must be good because it’s used in domains in which its use was mandated” argument.
Ada offers things Rust doesn’t with regard to high-level controls and checks, like the Ravenscar profile, which makes the compiler ensure deterministic behavior of your program, which is super important to real-time systems.
Yeah, this seems pretty cool, absent more information.
Correctness works with iteration time because iterating on incorrect code is unwieldy and you end up carrying hard-to-fix bugs forward. I think you’re assuming correctness is bulky and heavyweight, which I haven’t found in Ada.
To be clear, I understand the “correctness and rapid iteration go hand-in-hand” theoretical argument, and it may even have been true in the days of waterfall, but I don’t think it’s true in the days of continuous deployment. Much of software development is done with languages that are nowhere near as rigorous as Rust or Ada, and if correctness were indeed so very profitable, I think we would see a lot more of these languages. It is interesting that you say that Ada is just as productive as other languages, and I’m sure one could be quite productive in Ada, but I reserve my skepticism about Ada’s application beyond mission-critical systems until I see a few well-known, successful SaaS projects in Ada.
To be fair, I’ve had (and to an extent, I still have) similar reservations about Rust, but while there aren’t many SaaS applications of Rust, it is featuring prominently in lots of important technology that is cloud-adjacent (SSL libraries, hypervisors, networking infrastructure, etc). Given its relative youth, that puts it on the right trajectory to become a mainstream application language in not a lot of time.
That said, I want to reiterate that I’m not anti-Ada; I would really like to see Ada as a mainstream language, throwing its hat in the ring with Rust and Go for high-level application development. I just can’t believe that it’s a good fit until I see some movement.
Move is different than borrowing, iirc move is just the default behavior in Rust for non-copyable types. In C++ it’s done via r-value references and the type system, std::move doesn’t have behavior other than to force something to be perceived as an r-value reference so the overload system dispatches the right behavior. The “move” concept is used to transfer resources efficiently in well-defined ways, such as in move assignment/constructor, and is a complicated subject.
If Ada implemented “move” the same way, A := B (or some equivalent A := Move(B)) would transfer the contents of B into A and would work even for limited (uncopyable) types. E.g. for std::vector in C++, move transfers the ownership of the internal contents without a copy, but it looks like Ada.Containers.Vectors.Move is just an array assign and hence a copy.
The main idea used to enforce single ownership for pointers is the move semantics of assignments. When a pointer is copied through an assignment statement, the ownership of the pointer is transferred to the left hand side of the assignment. As a result, the right hand side loses the ownership of the object, and therefore loses the right to access it, both for writing and reading.
That works for the trivial case. At least in C++, the idea of move semantics is to handle the general case. For (a fairly simple) example, moving one string to another means that the new string takes ownership of the internal buffer and the old string is left in an undefined state. Ideally, you wold have static verification that no uses of the old object other than deallocation occur.
Linear ownership of pointers is one of the key building blocks for implementing move semantics (when you move from object A to object B, you must transfer ownership of all pointers in A to B), but it’s not sufficient by itself.
C++ actually implements these the other way around: std::unique_ptr provides linear ownership for pointers (with an unsafe escape hatch via get()) and is built on top of move semantics by defining move constructors and move-assignment operators. An object whose fields are all move-constructible gets a default move constructor that move constructs all of its fields, so if an object has only std::unique_ptr and primitive value types as fields then it will get a default move constructor that works in the same way as the string example above. One of the biggest gotchas in C++ is that bare pointers are move constructible as a copy operation. You need to be very careful to avoid having bare pointers that need explicit memory management held by anything other than a smart pointer class that does the right thing.
I believe Rust has something similar. In Rust, the use of traits to advertise (and infer) compliance with specific properties makes this kind of thing easier.
I’ve been playing with Rust for a few years seeing if it could replace C++ for me, and after the initial enthusiasm I’m losing interest on it, so your comparison with these two is very relevant to me.
I read a bit about Ada years ago, but there was always some little obstacle when trying it out and when I could not get it rolling my free time slot was over and I moved on.
Just a couple of days ago I started again, going through the tutorial in learn.adacore.com, and now reading this overview is exactly what I need.
I don’t have any substantive feedback yet, just started reading it, but I did notice the word “pregenitor” under “Terminology” and wanted to file an issue in Github asking whether it was correct (neither “progenitor” nor “pregenitor” appear anywhere else in the document) but I did not see any link. I did of course rearrange the URL to find it, but it would be easier to report typos if you put it there: https://github.com/pyjarrett/programming-with-ada
Edit: got into those small papercuts again, which is that my distro’s Emacs package does not include ada-mode, so I installed it with Melpa as instructed, but then it does not work at all because it needs that gpr project manager, which is not packaged for my distro, etc.
And it does not degrade gracefully, it’s worse than plain text or fundamental mode because it actively mis-indents your code as you type.
Anyway, pascal-mode seems to work fine for simple programs so I’m continuing with it.
I primarily work on open source CLI tooling and related libraries. If I were going to use Ada, that’s what I would try to use it for.
Do there exist any well used and portable CLI tools written in Ada? (“well used” meaning, “there is actually some non-trivial portion of users using it, such that whoever built it had to think about environments other than their own.”) Perhaps I’m using one of them and didn’t know it? If so, I’d love to be pointed to one of them so that I could see how they handle dependencies, deal with portability (especially Windows), test things, document things, build releases and so on.
When I built ripgrep, there were already established Rust tools that were shipping to end users on Linux, macOS and Windows. I learned a lot from them and was able to see how such tools were built and organized. Are there equivalent examples for Ada? If not, why not?
I tried doing some searches myself, but couldn’t find much more than things like this and this.
Why? This is my perception based on what I’ve read. Ada suffered major PR issues due to slow and costly compilers losing to C. By the time GNAT came out in the mid 90s, that was during the Java fever, followed by Python/Ruby used for tools and scripting. Ada usage is apparently also purposely not advertised. Its reputation as a bureaucratic cumbersome language seems to have mostly shed because so few people know about it anymore.
Thanks for those links. I’ll check them out when I get a chance.
I think my main thought here is whether it has suffered PR issues because of what you say, or because there are legitimate reasons why people don’t use it. It looks like the only way to find out at this point is to go and actually try to build something with it and ship to end users. But that’s very costly to do.
It looks like they have nice docs for working with the ports system they developed, but I don’t see any build instructions… There’s build/Makefile, but…
[andrew@krusty build]$ make
Makefile:21: *** missing separator. Stop.
[andrew@krusty build]$ cd ..
[andrew@krusty ravenadm]$ make -f build/Makefile
build/Makefile:21: *** missing separator. Stop.
The Makefile says it’s a “BSD” Makefile, but I have GNU make. But it’s not too big. So I just ran the commands manually after installing gcc-ada. (That dependency is listed nowhere that I can see.) And I was able to get a working executable:
$ ./ravenadm help
No configuration file found.
Please switch to root permissions and retry the command.
Thanks for the link. This definitely helps a bit. If I wanted to go write a CLI tool, this example would likely be quite useful in helping me get started. There’s still a lot more I’d like to see though.
Reading that is like listening to a carpenter promise a building is safe because all his tools are so blunt they can’t cut a finger off. And doing it in the most condescending and patronizing way possible, then never mentioning guard rails on stairwells.
Congratulations, your program is unlikely to have buffer overflows. Now you merely have every other type of bug to worry about.
They found 70% of security bugs were memory safety issues. That was likely what you meant, but just to make sure nobody thinks we can fix 70% of all software bugs by using Rust/Ada :-)
From the comparison page of the linked compiler it looks like the free edition can only be used to create GPL licensed software. Is there a good free Ada compiler that does not restrict how you license what you write?
Edit: Explanation of how this works with GPL’s “no further restrictions”. GNAT standard library is copyrighted by FSF and distributed under GPL with linking exception. Thanks to linking exception, there is no restriction to linking standard library. AdaCore redistributes FSF-copyrighted GNAT standard library under GPL, without linking exception. Just as any other software licensed under GPL, your application should be GPL if you link AdaCore distributed GNAT standard library.
GPL forbids further restrictions, but GPL has no problem whatsoever with dropping exceptions. You get the same code with same copyright, but only FSF gives you exception, AdaCore does not give you exception unless you pay. Instead of paying, you could get exception from FSF, but while AdaCore spends efforts to advertise, FSF does not. AdaCore especially does not advertise you can get the same exception from FSF without paying AdaCore. As you have shown, apparently this “revenue by obscurity” is very effective in practice.
Edit 2: Explanation of how this works with GPL’s “you must show users these terms so they know their rights”. GPL requires you to include GPL in any redistributions. But even if you received it with exceptions, there is no requirement whatsoever you should let your users know about exceptions. GPL exceptions are not rights, so they are not covered by “know their rights” provision.
As you have shown, apparently this “revenue by obscurity” is very effective in practice.
Disclaimer: I work at AdaCore.
The reason companies pay AdaCore is that they want support, not that they want to be able to write proprietary software. According to the people in our sales team, “Why should we pay you instead of using the FSF’s GNAT?” is a question that often comes up during negotiations and the answer always is “Because you won’t get access to experts that can answer your questions, fix your bugs in a timely manner and provide insurance in case something goes wrong if you don’t”. Companies chose to pay because in the safety-critical world you can’t afford to not have support for the tools you rely on.
It’s true that the license situation is confusing though. As far as I understand this is why AdaCore is planning on discontinuing GNAT community and instead will start helping linux distributions ship up to date versions of its tools.
AdaCore is planning on discontinuing GNAT community
Don’t forget the Windows users. Given the current dependency on Makefiles, support already isn’t super great, and this would probably incentivize me to go back to writing Rust or C++17.
Companies chose to pay because in the safety-critical world you can’t afford to not have support for the tools you rely on.
This is true in all software, not just safety-critical. I’ve seen this happen many times, and companies don’t understand that it’s better to not burn $50-100+/hr per developer on a team when tools don’t work as intended.
AdaCore is planning on discontinuing GNAT community
Don’t forget the Windows users.
First please don’t take my word as an absolute truth - I am not involved in any of the circles that actually decide what should happen regarding AdaCore’s involvement with the Ada community and I may have misunderstood some of the things I heard. In the end, I don’t really know what’s going to happen wrt Gnat Community.
If what I understood is correct, the plan for windows users would be to support them with Mingw (or maybe another distribution of linux tools for windows whose name escapes me). I remember that one of the other alternatives discussed was to rely on Alire for toolchain management (kind of like rustup/cargo). The other tools (gprbuild, GNAT Studio) that won’t be shipped with MinGW would still be available from AdaCore’s website. I think one of the other goals (aside from clearing the license confusion) of this move is to have the Ada community be more self-reliant, so that people would stop seeing AdaCore as “owning” the ecosystem and rather as just one of its actors.
Disclaimer: I don’t work for AdaCore, or anyone Ada-related. I’m a C++ grunt.
aside from clearing the license confusion
This is a great move since one of my major gripes is the usage of GPL, of which many companies like to steer well clear.
so that people would stop seeing AdaCore as “owning” the ecosystem and rather as just one of its actors.
I think this is a really good goal. Alire is neat. Mingw doesn’t really cut it though, WSL is ok, but native support would be the best. Yeah, I get it’s a lot of toolchain work. It’d be nice if Microsoft built it into Visual Studio, which would be a legitimate option since there’s a formal spec and the ACATS test suite.
I wouldn’t be working at all in Ada if not for the work groundwork for an “Ada Renaissance” so to speak, laid by AdaCore in the last few years (language server, llvm compiler, libadalang, ada language server, the learning site, and quality youtube videos.
Anyone who felt like they missed the bus on getting involved on the ground floor of a language (like on Alire) definitely has huge opportunities in Ada.
companies don’t understand that it’s better to not burn $50-100+/hr per developer on a team when tools don’t work as intended.
I think this is somewhat situational. Having good support for a tool can indeed save a lot of developer time. But paying for support doesn’t guarantee that the support will be useful when you need it.
Low-quality support is one problem, but response time can be an issue too: as a developer, if a tool issue is blocking me from getting my work done, it’s often the case that I can dig into it and figure out a workaround or a fix in less time than it takes to get an initial response, let alone a resolution, from a vendor’s support people. I’m costing the company just as much money when I’m twiddling my thumbs waiting for vendor support as I would if I were digging into the problem myself.
Obviously that depends hugely on which tools we’re talking about and on my level of expertise; it won’t be true for all tools and all developers.
That said, it’s been my experience that tool issues generally fall into three buckets: things I can figure out on my own in a reasonable amount of time, things I can’t figure out on my own but the vendor could solve in a reasonable amount of time, and things that would take the vendor a long time to solve. And the middle bucket is almost always much smaller than the other two.
None of which is to say that paying for support is a waste of money. But I think depending on the situation, it can also be rational to decide that the net cost is lower if developers figure out tool issues on their own.
Thank you for your comment, it put things a bit in perspective for me.
I don’t purport to know if getting free tools in the hands of as many potential developers as possible is a good business decision or not, but I fear that if you manage to scare away even a percentage of potential new users, it may hurt the chances for Ada, the language, to grow.
GPL forbids further restrictions, but GPL has no problem whatsoever with dropping exceptions
This is not true. The GPL explicitly forbids redistributing with weaker restrictions. If this were not the case, you could combine a GPL’d file in a BSDL library and distribute the result under the BSDL, then incorporate this in a proprietary product, defeating the point of the GPL. You can; however, create a new license that is the GPL + some exceptions. This is what the FSF does with the GCC linking exemption, for example[1].
This distinction is important. Your phrasing suggests that it would be possible to take an existing GPL’d file and incorporate it into the GNAT standard library. Doing so would violate the GPL (if you distributed the result) unless the copyright holder agreed to the relicensing. The FSF works around this by requiring copyright assignment.
[1] Note that you have to do this by adding exemptions to the end of the GPL, rather than modifying the GPL because, somewhat ironically, the text of the GPL is copyrighted by the FSF and distribution with modifications is not permitted by the license of the license text itself.
The GNAT version from the FSF (which your distro ships) allows writing software under any license. The GNAT version from AdaCore and the one from FSF are basically the same.
This is a really good writeup! Thanks @marin for taking your time to create it.
Ada really seems to be an overlooked gem. Especially if you’re interested in Rust, you should definitely consider Ada for the same purposes (and more beyond that).
Three very strong points are that Ada is standardized and, in my opinion, much more readable and that it has built-in concurrency. It’s much easier to do contract-based-programming and it’s overall a much more solid foundation to build you projects upon than Rust.
Admittedly, Ada doesn’t have such a vocal “following” like Rust, but its usage alone in nuclear power plants, planes, etc. speaks volumes.
That makes a lot of sense, since readability is an explicit design goal of Ada. (Ada Reference Manual, “Design Goals”) Readability is not a design goal of Rust.
First, “much more readable” is very subjective. Second, yes, rust has more momentum outside of nuclear power plants, which means there’s a lot more crates for everyday programming (e.g. zstd bindings, an AWS client, etc.). Seems like more Ada crates are GPL (looking at “ada web server”) which also restricts the scope in which they can be used.
It’s fine to compare the technical merits (what’s that with the builtin concurrency btw?! Have you seen that rust’s stdlib has a bunch of things too?), but just saying that you can swap one for the other is a bit optimistic.
Readability is very subjective. The argument (not trying to get into one) would probably be that Ada uses much less symbology (but 70+ keywords!) and also has a required principle called “linear elaboration of declarations”. This roughly means programs must be unambiguous when read from start to finish. There are mechanisms like
limited with
to help break circular references.True, but Alire is now at 1.0, and if it builds under GCC, GCC itself can generate Ada bindings for you.
Ada supports types with mutual exclusion (controlled types) and also one-shot and instantiable task types as part of the language itself, which support queueing (called entries, also look up rendezvous).
Rust has a very good stdlib. My point isn’t a denigration of Rust or any other language, or to be an Ada super fan, I’m going for as objective viewpoint and objective comparisons so people understand what it can do, since it doesn’t seem very well known.
You’re not who I was replying to, but yes, these are good points. I’m also used to the linear order of declarations (as in OCaml), and it’s clear Alire is very young.
I’m curious to see what the future holds for Ada. There are things I find personally ugly (mostly that it’s not expression based), but hopefully it will eat some of the space C has held for a long time. I also wonder if someone could implement something like Ada’s rendez-vous in rust…
One of my favorite features of Rust is Cargo. I used Ada a decade ago, and I don’t recall anything similar. I certainly don’t recall such a wide universe of packages so easily accessible.
Does it? Wasn’t Ada mandated from on-high for use in these domains? How many nuclear power plants and aeroplanes were developed since Rust was conceived? Why would a language whose mainstay is mission-critical systems be appropriate for domains where iteration velocity is far more important than correctness? I’m not trying to shoot Ada down–I had a really fun time writing some microcontroller software with it, but these are the sort of baseline questions I’m interested in before seriously considering Ada for a project.
There’s something called Alire which has reached 1.0 and is now available. There’s not much there, but there’s a lot of batteries included in the GNAT community install, so I haven’t needed to manually grab anything else yet.
Ada comes from a time when defense contractors used over 100 languages and some didn’t even include basic support for basic things like “ensure the correct number of parameters are passed.” Imagine how untenable your current project would be if it included C, C++, C#, Rust, Haskell, Ocaml, Bash, Powershell, Lua, Python, Ruby, Tcl, Java, Clojure, Beanshell, Groovy, COBOL, ALGOL, etc.
Ada offers things Rust doesn’t with regard to high-level controls and checks, like the Ravenscar profile, which makes the compiler ensure deterministic behavior of your program, which is super important to real-time systems.
Correctness works with iteration time because iterating on incorrect code is unwieldy and you end up carrying hard-to-fix bugs forward. I think you’re assuming correctness is bulky and heavyweight, which I haven’t found in Ada. In my experience, Ada iterates exceptionally well because of short compile times, better cohesion by using packages instead of types for subprogram (function/procedure) namespacing, and centralized checks which the compiler inserts via integrated design-by-contract and constraints on types. They have made it much faster to iterate on the project I’m working on, since I end up writing small cohesive modules with often automated checks in one place instead of rolling a lot of unit tests or distributing manual checks throughout my codebase which need to be modified on every major refactor.
I think this misses the point, which is that Ada didn’t out-compete other languages for these mission-critical domains; rather, it was mandated from on-high. So we can’t infer that Ada was simply a better fit. Notably, I believe once the mandate was lifted, much of the industry returned to C and C++. To be clear, I’m not advocating for C or C++ or even advocating against Ada. I just don’t buy the “Ada must be good because it’s used in domains in which its use was mandated” argument.
Yeah, this seems pretty cool, absent more information.
To be clear, I understand the “correctness and rapid iteration go hand-in-hand” theoretical argument, and it may even have been true in the days of waterfall, but I don’t think it’s true in the days of continuous deployment. Much of software development is done with languages that are nowhere near as rigorous as Rust or Ada, and if correctness were indeed so very profitable, I think we would see a lot more of these languages. It is interesting that you say that Ada is just as productive as other languages, and I’m sure one could be quite productive in Ada, but I reserve my skepticism about Ada’s application beyond mission-critical systems until I see a few well-known, successful SaaS projects in Ada.
To be fair, I’ve had (and to an extent, I still have) similar reservations about Rust, but while there aren’t many SaaS applications of Rust, it is featuring prominently in lots of important technology that is cloud-adjacent (SSL libraries, hypervisors, networking infrastructure, etc). Given its relative youth, that puts it on the right trajectory to become a mainstream application language in not a lot of time.
That said, I want to reiterate that I’m not anti-Ada; I would really like to see Ada as a mainstream language, throwing its hat in the ring with Rust and Go for high-level application development. I just can’t believe that it’s a good fit until I see some movement.
Isn’t that what Spark’s support for pointers provides?
That list is based on my current understanding.
Move is different than borrowing, iirc move is just the default behavior in Rust for non-copyable types. In C++ it’s done via r-value references and the type system,
std::move
doesn’t have behavior other than to force something to be perceived as an r-value reference so the overload system dispatches the right behavior. The “move” concept is used to transfer resources efficiently in well-defined ways, such as in move assignment/constructor, and is a complicated subject.If Ada implemented “move” the same way,
A := B
(or some equivalentA := Move(B)
) would transfer the contents of B into A and would work even for limited (uncopyable) types. E.g. forstd::vector
in C++, move transfers the ownership of the internal contents without a copy, but it looks likeAda.Containers.Vectors.Move
is just an array assign and hence a copy.https://blog.adacore.com/using-pointers-in-spark
That works for the trivial case. At least in C++, the idea of move semantics is to handle the general case. For (a fairly simple) example, moving one string to another means that the new string takes ownership of the internal buffer and the old string is left in an undefined state. Ideally, you wold have static verification that no uses of the old object other than deallocation occur.
Linear ownership of pointers is one of the key building blocks for implementing move semantics (when you move from object
A
to objectB
, you must transfer ownership of all pointers inA
toB
), but it’s not sufficient by itself.C++ actually implements these the other way around:
std::unique_ptr
provides linear ownership for pointers (with an unsafe escape hatch viaget()
) and is built on top of move semantics by defining move constructors and move-assignment operators. An object whose fields are all move-constructible gets a default move constructor that move constructs all of its fields, so if an object has onlystd::unique_ptr
and primitive value types as fields then it will get a default move constructor that works in the same way as the string example above. One of the biggest gotchas in C++ is that bare pointers are move constructible as a copy operation. You need to be very careful to avoid having bare pointers that need explicit memory management held by anything other than a smart pointer class that does the right thing.I believe Rust has something similar. In Rust, the use of traits to advertise (and infer) compliance with specific properties makes this kind of thing easier.
I’ve been playing with Rust for a few years seeing if it could replace C++ for me, and after the initial enthusiasm I’m losing interest on it, so your comparison with these two is very relevant to me. I read a bit about Ada years ago, but there was always some little obstacle when trying it out and when I could not get it rolling my free time slot was over and I moved on. Just a couple of days ago I started again, going through the tutorial in learn.adacore.com, and now reading this overview is exactly what I need.
I don’t have any substantive feedback yet, just started reading it, but I did notice the word “pregenitor” under “Terminology” and wanted to file an issue in Github asking whether it was correct (neither “progenitor” nor “pregenitor” appear anywhere else in the document) but I did not see any link. I did of course rearrange the URL to find it, but it would be easier to report typos if you put it there: https://github.com/pyjarrett/programming-with-ada
Edit: got into those small papercuts again, which is that my distro’s Emacs package does not include ada-mode, so I installed it with Melpa as instructed, but then it does not work at all because it needs that gpr project manager, which is not packaged for my distro, etc. And it does not degrade gracefully, it’s worse than plain text or fundamental mode because it actively mis-indents your code as you type. Anyway, pascal-mode seems to work fine for simple programs so I’m continuing with it.
I primarily work on open source CLI tooling and related libraries. If I were going to use Ada, that’s what I would try to use it for.
Do there exist any well used and portable CLI tools written in Ada? (“well used” meaning, “there is actually some non-trivial portion of users using it, such that whoever built it had to think about environments other than their own.”) Perhaps I’m using one of them and didn’t know it? If so, I’d love to be pointed to one of them so that I could see how they handle dependencies, deal with portability (especially Windows), test things, document things, build releases and so on.
When I built ripgrep, there were already established Rust tools that were shipping to end users on Linux, macOS and Windows. I learned a lot from them and was able to see how such tools were built and organized. Are there equivalent examples for Ada? If not, why not?
I tried doing some searches myself, but couldn’t find much more than things like this and this.
I don’t think there are. I also still haven’t even met a single person who writes Ada professionally.
I’m following the example of Alire, AdaCore’s gem articles, repos on AdaCore’s github, and filling in gaps with the surprisingly complete wikibook.
Why? This is my perception based on what I’ve read. Ada suffered major PR issues due to slow and costly compilers losing to C. By the time GNAT came out in the mid 90s, that was during the Java fever, followed by Python/Ruby used for tools and scripting. Ada usage is apparently also purposely not advertised. Its reputation as a bureaucratic cumbersome language seems to have mostly shed because so few people know about it anymore.
Thanks for those links. I’ll check them out when I get a chance.
I think my main thought here is whether it has suffered PR issues because of what you say, or because there are legitimate reasons why people don’t use it. It looks like the only way to find out at this point is to go and actually try to build something with it and ship to end users. But that’s very costly to do.
I think (but can’t verify as I’m on mobile) that Ravenport is written in Ada and fairly popular among certain BSD flavors.
After a lot of searching, I think I found it: https://github.com/jrmarino/ravenadm
It doesn’t seem to support Windows though.
It looks like they have nice docs for working with the ports system they developed, but I don’t see any build instructions… There’s
build/Makefile
, but…The
Makefile
says it’s a “BSD” Makefile, but I have GNU make. But it’s not too big. So I just ran the commands manually after installinggcc-ada
. (That dependency is listed nowhere that I can see.) And I was able to get a working executable:Thanks for the link. This definitely helps a bit. If I wanted to go write a CLI tool, this example would likely be quite useful in helping me get started. There’s still a lot more I’d like to see though.
Last time I saw Ada was in this series:
“Finite Field Arithmetic.” Chapter 1: Genesis.
Reading that is like listening to a carpenter promise a building is safe because all his tools are so blunt they can’t cut a finger off. And doing it in the most condescending and patronizing way possible, then never mentioning guard rails on stairwells.
Congratulations, your program is unlikely to have buffer overflows. Now you merely have every other type of bug to worry about.
My understanding is that 70% of bugs are memory corruption problems. If you can avoid a class of bugs entirely it is worth it, I think.
They found 70% of security bugs were memory safety issues. That was likely what you meant, but just to make sure nobody thinks we can fix 70% of all software bugs by using Rust/Ada :-)
No, but fixing 70% of all security bugs simply through appropriate choice of language is profound win.
From the comparison page of the linked compiler it looks like the free edition can only be used to create GPL licensed software. Is there a good free Ada compiler that does not restrict how you license what you write?
You can use GCC. GNAT Pro is not GCC.
Edit: Explanation of how this works with GPL’s “no further restrictions”. GNAT standard library is copyrighted by FSF and distributed under GPL with linking exception. Thanks to linking exception, there is no restriction to linking standard library. AdaCore redistributes FSF-copyrighted GNAT standard library under GPL, without linking exception. Just as any other software licensed under GPL, your application should be GPL if you link AdaCore distributed GNAT standard library.
GPL forbids further restrictions, but GPL has no problem whatsoever with dropping exceptions. You get the same code with same copyright, but only FSF gives you exception, AdaCore does not give you exception unless you pay. Instead of paying, you could get exception from FSF, but while AdaCore spends efforts to advertise, FSF does not. AdaCore especially does not advertise you can get the same exception from FSF without paying AdaCore. As you have shown, apparently this “revenue by obscurity” is very effective in practice.
Edit 2: Explanation of how this works with GPL’s “you must show users these terms so they know their rights”. GPL requires you to include GPL in any redistributions. But even if you received it with exceptions, there is no requirement whatsoever you should let your users know about exceptions. GPL exceptions are not rights, so they are not covered by “know their rights” provision.
Disclaimer: I work at AdaCore.
The reason companies pay AdaCore is that they want support, not that they want to be able to write proprietary software. According to the people in our sales team, “Why should we pay you instead of using the FSF’s GNAT?” is a question that often comes up during negotiations and the answer always is “Because you won’t get access to experts that can answer your questions, fix your bugs in a timely manner and provide insurance in case something goes wrong if you don’t”. Companies chose to pay because in the safety-critical world you can’t afford to not have support for the tools you rely on.
It’s true that the license situation is confusing though. As far as I understand this is why AdaCore is planning on discontinuing GNAT community and instead will start helping linux distributions ship up to date versions of its tools.
Don’t forget the Windows users. Given the current dependency on Makefiles, support already isn’t super great, and this would probably incentivize me to go back to writing Rust or C++17.
This is true in all software, not just safety-critical. I’ve seen this happen many times, and companies don’t understand that it’s better to not burn $50-100+/hr per developer on a team when tools don’t work as intended.
First please don’t take my word as an absolute truth - I am not involved in any of the circles that actually decide what should happen regarding AdaCore’s involvement with the Ada community and I may have misunderstood some of the things I heard. In the end, I don’t really know what’s going to happen wrt Gnat Community.
If what I understood is correct, the plan for windows users would be to support them with Mingw (or maybe another distribution of linux tools for windows whose name escapes me). I remember that one of the other alternatives discussed was to rely on Alire for toolchain management (kind of like rustup/cargo). The other tools (gprbuild, GNAT Studio) that won’t be shipped with MinGW would still be available from AdaCore’s website. I think one of the other goals (aside from clearing the license confusion) of this move is to have the Ada community be more self-reliant, so that people would stop seeing AdaCore as “owning” the ecosystem and rather as just one of its actors.
Disclaimer: I don’t work for AdaCore, or anyone Ada-related. I’m a C++ grunt.
This is a great move since one of my major gripes is the usage of GPL, of which many companies like to steer well clear.
I think this is a really good goal. Alire is neat. Mingw doesn’t really cut it though, WSL is ok, but native support would be the best. Yeah, I get it’s a lot of toolchain work. It’d be nice if Microsoft built it into Visual Studio, which would be a legitimate option since there’s a formal spec and the ACATS test suite.
I wouldn’t be working at all in Ada if not for the work groundwork for an “Ada Renaissance” so to speak, laid by AdaCore in the last few years (language server, llvm compiler, libadalang, ada language server, the learning site, and quality youtube videos.
Anyone who felt like they missed the bus on getting involved on the ground floor of a language (like on Alire) definitely has huge opportunities in Ada.
What’s wrong with Mingw?
I think this is somewhat situational. Having good support for a tool can indeed save a lot of developer time. But paying for support doesn’t guarantee that the support will be useful when you need it.
Low-quality support is one problem, but response time can be an issue too: as a developer, if a tool issue is blocking me from getting my work done, it’s often the case that I can dig into it and figure out a workaround or a fix in less time than it takes to get an initial response, let alone a resolution, from a vendor’s support people. I’m costing the company just as much money when I’m twiddling my thumbs waiting for vendor support as I would if I were digging into the problem myself.
Obviously that depends hugely on which tools we’re talking about and on my level of expertise; it won’t be true for all tools and all developers.
That said, it’s been my experience that tool issues generally fall into three buckets: things I can figure out on my own in a reasonable amount of time, things I can’t figure out on my own but the vendor could solve in a reasonable amount of time, and things that would take the vendor a long time to solve. And the middle bucket is almost always much smaller than the other two.
None of which is to say that paying for support is a waste of money. But I think depending on the situation, it can also be rational to decide that the net cost is lower if developers figure out tool issues on their own.
Thank you for your comment, it put things a bit in perspective for me.
I don’t purport to know if getting free tools in the hands of as many potential developers as possible is a good business decision or not, but I fear that if you manage to scare away even a percentage of potential new users, it may hurt the chances for Ada, the language, to grow.
This is not true. The GPL explicitly forbids redistributing with weaker restrictions. If this were not the case, you could combine a GPL’d file in a BSDL library and distribute the result under the BSDL, then incorporate this in a proprietary product, defeating the point of the GPL. You can; however, create a new license that is the GPL + some exceptions. This is what the FSF does with the GCC linking exemption, for example[1].
This distinction is important. Your phrasing suggests that it would be possible to take an existing GPL’d file and incorporate it into the GNAT standard library. Doing so would violate the GPL (if you distributed the result) unless the copyright holder agreed to the relicensing. The FSF works around this by requiring copyright assignment.
[1] Note that you have to do this by adding exemptions to the end of the GPL, rather than modifying the GPL because, somewhat ironically, the text of the GPL is copyrighted by the FSF and distribution with modifications is not permitted by the license of the license text itself.
The GNAT version from the FSF (which your distro ships) allows writing software under any license. The GNAT version from AdaCore and the one from FSF are basically the same.
Is there any document which compares Ada to Haskell?