Interestingly Co-Pilot gets it wrong and states Ada was designed by committees instead of being multiple competitive processes. How misunderstood Ada is.
True but it was far more open than a committee. The STRAWMAN requirements were circulated widely for comment to industry, military, federal and academic communities and to select experts such as Dijkstra and Hoare. Then WOODENMAN circulated for comment after incorporating changes based on STRAWMANS responses.
I wish I knew who were the anonymous authors of DoD "IRONMAN" (January 1977), especially who has written the paragraph "7.2.F. (7F.) FORMAL PARAMETER CLASSES".
"IRONMAN" has introduced a very important innovation in programming languages, which has been inherited by Ada and by its derivatives, e.g. VHDL (the innovation is that formal parameters may have 3 kinds of behaviors, "in", "out" and "in out", and that the parameter behavior must be specified, but not its implementation mechanism, like in older programming languages).
Unfortunately this innovation has remained largely unknown for the authors of most more recent programming languages, which are defective because of that.
If Bjarne Stroustrup had bothered to read carefully the Ada specification before conceiving "C with Classes", he might have understood the implication of the "IRONMAN" parameter classes for languages with constructors and destructors, like C++, which could have avoided many decades of pain for the C++ users. In a language with the "IRONMAN" parameter classes, constructors can be ordinary functions and there is no need for many features that complicate C++, like distinct copy constructors and assignment operators, or "move" semantics. Moreover, the performance problems that have plagued C++ before 2011, due to the creation of unnecessary temporaries, would have been avoided since the beginning.
It is likely that the authors of "IRONMAN" did not fully understand the consequences of their innovation, but they had proposed it only in order to make the new DoD language more similar to Jovial, which was a programming language used in several DoD projects at that time. Jovial had such formal parameter classes, but their meaning was slightly different than in "IRONMAN" and in the later Ada, enough to make them much less useful.
Before "IRONMAN", the earlier DoD requirements were to be able to specify whether the parameters are passed by value or by reference, which is an extremely wrong requirement. It is the same mistake made by C and by its derivatives, including recent derivatives, like Rust.
How the parameters are passed must be decided by the compiler, not by the programmer. For the programmer it does not matter whether a parameter is passed by value or by reference, when the passing of the parameters is implemented correctly (e.g. an in-out parameter that is passed by value is copied from the caller to the function and then back when the function returns, if that is necessary; frequently this is not necessary, e.g. if the parameter is located in a register; if the in-out parameter is so big that copying would be slow, the compiler decides to pass it by reference; in C and its derivatives, both out and in-out parameters must be passed by reference, even when that is the wrong choice; moreover, the compiler cannot flag as an error the reading of an out parameter prior to its first writing).
Yes this is one of my favorite Ada features (combined with named paramètres at call-site) it always felt clearer reading or writing Ada. The intent ('what') is more important (to me, reading heaps and heaps of code) than the 'how' that I can infer quickly and is less useful in data-flow reading mode.
> the innovation is that formal parameters may have 3 kinds of behaviors, "in", "out" and "in out", and that the parameter behavior must be specified, but not its implementation mechanism, like in older programming languages
Great on paper, not so good in real life: so what is the specification when a parameter is aliased?
That is to say passed two times to a procedure: once as an "in" parameter, the other as an "in out" parameter.
I've been able to use compiler explorer to show the behaviour may change depending on the size of the parameter with GNAT, ( https://news.ycombinator.com/item?id=43001394 ).
Parameter aliasing creates problems for "out" parameters and for "in out" parameters in any language, regardless whether they are passed by value or by reference, and regardless whether there exists a distinction between "out" and "in out".
In C/C++, where such parameters are passed only by reference, the chances of wrong behavior in the presence of aliasing are greater than in a language like Ada, where they may be passed by value and in lucky cases that may happen to produce the right result.
In general, the documentation of any function should specify whether the aliasing of such parameters is allowed. By default any good compiler, for any language, should give at least a warning whenever parameters that can be modified by a function are aliased, because without analyzing how they are used inside the invoked function it is unknown whether the function will produce the expected results.
The distinction between "out" and "in out" parameters that exists in Ada can only make easier the detection of suspect function invocations. It can never be worse than in C, C++ and similar languages.
On the other hand, the distinction between "out" and "in out" would have greatly simplified C++, because for an "out" parameter the compiler can use raw memory, instead of memory for which a constructor must have been invoked, like for an "in out" parameter. There would have been no constructors as a special category that must be handled differently, any function with an "out" parameter of a certain type could have been used to initialize a value of that type.
The distinction between "out" and "in out" and not specifying whether the parameters are passed by value or by reference are great in real life, because they enable the compiler to make optimizations that are otherwise impossible, as proven by the fact that nobody has succeeded to make such a compiler for the pre-2011 C++. C++ from 2011 and later has solved some of the performance issues, but only by introducing tedious and error-prone annotations for ensuring the desired behavior, i.e. the "move" semantics.
Moreover, not having to specify how the parameters are passed eliminates a huge amount of "&" and of "*" or of their equivalents from a program, also eliminating the risk of errors caused by their misuse. In my opinion, this is a great advantage in real life.
> for an "out" parameter the compiler can use raw memory, instead of memory for which a constructor must have been invoked
So let's say the parameter has a nontrivial destructor. Caller A passes an uninitialized variable. Caller B passes an initialized variable. What is the callee supposed to do?
> How the parameters are passed must be decided by the compiler, not by the programmer.
Consider the program
def f(x):
return 17
If omega is a non-terminating expression then the call
f(omega)
might or might not terminate, depending whether the compiler uses a lazy or eager evaluation strategy. This freedom is not something I would recommend to a programming language designer.
I have not encountered yet a programming language where it is unspecified whether the evaluation of expressions is lazy or eager.
This choice has too many consequences and it is pretty much impossible to understand how a program will behave, unless you know whether the evaluation is lazy, like in Haskell and the like, or eager, like in ML, LISP and in most other programming languages.
In a programming language with lazy evaluation, the programmer also does not specify how parameters are passed. Whoever implements a translator for the language will choose a parameter passing method, which for most parameters will be neither by value nor by reference, but it would be something similar to the ALGOL 60 parameter passing by name.
Loving Ada without using exceptions or inheritance on embedded and desktop. Some love Ada full OOP tagged types. I love Ada procedural style with privacy and abstract data types. I wish Flutter was written in Ada but atleast Dart is better than JavaScript atleast for procedural code without it's oop boiler plate. You don't actually need OOP for widgets.
But is Dart better than Typescript? I prefer Typescript for multiple reasons but one of them is that you don't have to use classes to use the advanced typing system. Without a typing system I like Ruby the most, but sometimes we just need a typing system.
2. The language and standard library are waaaaaaaay ahead of Javascript.
3. The tooling is top notch. Better than JS/TS.
But on the other hand:
4. Way smaller ecosystem.
5. Debugging is worse if you're compiling to JS. The fact that the code you run is basically identical to the code you write in TS can be a big advantage. Only really applies for web pages though.
6. Type unions are way nicer in TS.
7. Non-nullable types interact badly with classes. It can make writing methods correctly really awkward - you have to explicitly copy member variables to locals, modify them and then write them back.
As someone curious about learning more about type systems, would you mind elaborating on 1.? I'm assuming you mean the formal definition of "sound", not just as a synonym for "sensible". Sound typing is often something handwaved away as not being particulary consequential in practice; what benefits have you seen there?
From the official website:
> Dart enforces a sound type system. This means you can't write code where a variable's value differs from its static type.
I know you didn't ask me but I think that not ensuring soudness is a feature because it allows the type system to wrap something that could work without it. Would you like unit tests if removing them would break your code? Maybe it's not a fair comparison, or maybe it is...
> I wish Flutter was written in Ada but atleast Dart is better than JavaScript atleast for procedural code without it's oop boiler plate. You don't actually need OOP for widgets.
You can use other libraries for this like Riverpod with flutter_hooks and functional_widget which essentially removes the OOP structure of widgets and turns them more into functions, in a way.
I second that. From 8 to 64 bits systems, embedded or system programming, Ada is the best choice. I've saved tons of missing hours, headhaches, etc. with this gem. Search Github Sowebio Adel for a good setup manual and, in the same repo, v22 for a good gp kiss framework...
Embedded 8 and 32 bits microcontrollers to web linux based erp/crm softwares. Ada can be used for anything, with the speed of C/C++ but in a far more readable and safer way... Ada is a secret weapon. Don't spread theses infos ;)
There is a podcast and blackhat? video about Nvidia choosing SPARK over Rust. Not because of formal verification at all but because it is a more developed prospect and offers better security even without any formal verification. This isn't mentioned but Ada is also far better at modelling registers or even network packets.
I might consider AI if it utilised SPARKs gnat prove but I wouldn't usw AI otherwise.
As an example of modelling packets, here's an example of modelling a complex packet which is a bit-packed tagged union. I don't think many other languages make such packets so easy to declare: https://gist.github.com/liampwll/abaaa1f84827a1d81bcdb2f5f17...
SPARK is free for all to use and is open source. They chose to pay for Adacores pro support services and verified pro Ada compiler over the FSF GCC/Gnat Ada compiler. Spark is actually part of the Gnat compiler (compatibility) but actually the slower analysis is done by gnatprove thereby keeping compilation and iterative development fast. Nvidia can certainly afford to do so of course.
AdaCore's pro support includes more recent releases and, in case of problems, wavefronts. That said, the free version is fairly recent, and you can get community (and sometimes vendor) support.
Predicates are great but most of the good stuff including privacy, proper subtyping and abstract data types came with Ada 83. Rust can't hold a candle even to Ada 83 imo.
Ada has practically no mindshare, Rust does. Just like say, Scala, things can be technically 'good', but without adoption it isn't going to get the attention and visibility to compete with everything that does.
We're talking about mindshare, not commercial incentives. There are plenty of things sold to small groups of buyers with no significant mindshare. Mindshare does not equal commercial viability or sales numbers.
As for who would pay for a Rust compiler: probably not a whole lot of people unless that compiler has something special the offer that the normal compiler does not.
The same goes for a C compiler, there are Intel compilers that are supposed to be 'better', but as it turns out, in most cases not 'better' enough for people to pay for them. But even then, I would not be surprised if more people pay for the ICC than for Ada (but I would also not be surprised if the Ada compiler sales rack up more money than the ICC sales).
I think Ada is seen as some esteemed language that only the military and space would have the expertise to use. I had that opinion for maybe a decade but it was very wrong. The other issue was that it is so powerful that compilers had bugs and by the time an affordable open source compiler came along I guess C++ was gaining libraries and the militaries don't release libraries.
The ironic thing is that Ada was designed to be cost effective over a projects lifetime. C costs you a lot further down the line.
> I think Ada is seen as some esteemed language that only the military and space would have the expertise to use.
I know Boeing is technically a space company these days, but they weren't when they created the 777. Several of its systems are written in Ada, including the cockpit interfaces, electrical generator systems, and primary flight computers.
One of the reasons of the whole safety hype going on, is that companies have finally start mapping developer salaries, devops and infra costs, to fixing all those CVEs.
Hardware products like sensor and control devices. I also use it for desktop tooling whenever a script wants a for loop. Unfortunately I use Flutter for GUI stuff because I hate js and because it has Android/IOS plugins that I would have to write if using Gnoga.
A huge portion of Ada's modern ecosystem is MIT/apache or similar licensed, and available via Alire: https://alire.ada.dev/crates.html
A great deal of that are driver libraries for sbcs and other embedded frameworks, but there's plenty for things like web services and even a few game engines in there.
But the biggest advantage in Ada is the the syntax and good compilers that can empower that syntax. These compilers are the expensive part and most worrying. Availability of the libraries does not matter that much if you can't access the good compilers. I would be particularly interested about the features of open-source compilers vs. these commercial ones. Also, whether there are any effective verification/proofs available on those open-source compilers.
I tried it for AoC 2024. I'd always been curious about it. I wouldn't call it overall easy to use. That's partially due to the way AoC's problems are structured (reading matrices and all that), but there were more general pain-points as well, and there's surprisingly little info about Ada online. Looking up something as simple as converting an integer to a character took me quite some time (also hindered by the seemingly random way Ada uses attributes; sometimes you use a type, sometimes a variable; sometimes it's a constant, sometimes a function, or a property). But it definitely has its positive aspects.
I tried Ada because of Spark, but unfortunately, that's to deep to get into just for a few puzzles, and has an even worse online presence.
https://copilot.microsoft.com/shares/Jp9AmNHMEJzNmcbiu1VNx
https://copilot.microsoft.com/shares/vUjdaDh4mXvj1fm4cyt15