They could do varargs for C importing, because unfortunately people still use it, with a generic (for the allowed types) which implements an array of va_length. A default record type with all the C types should be provided, but the generic would allow passing in a new record which contains C types that you expect to be passed, so that means you could define numeric, float and enum types of convention C, pack them into a record of convention C and create a vararg array with that.
type My_Args is record
Name : chars_array;
Num : My_Range;
end record with
Convention => C_Pass_By_Copy;
package My_Va is new Va_Args (My_Args);
procedure Some_C_Va (...; Args : My_Va.Va_Array);
It would require the compiler to know about it and set up things properly.
Everything should be redone. The library goes all the way back to the decisions made at the start of the language and it really shows. As I said in the link, there can be two modes to implement this. But I really think that a modern library could do away with all this baggage and streamline a lot of stuff, especially where constant at compile time is required, which Ada currently struggles with because it wants to make elaborated stuff executable even when the compiler should be able to see everything’s there to make it static!
I complain about code being incompatible with runtimes. Mainly, there could be a light runtime container package (more easily done safely with Sparks new features).
However, conversely isn’t it easier to do concurrency safe and memory safe code with protected objects than with Rust due to that runtime support?
Sparks borrowing looks more straight forward and catches memory leaks, too.
I can’t say I have understood it but it seems he was more concerned about language complexity and pulling funds away from whatever he meant by interfaces. One person says it wasn’t about tagged type semantics. 🤷🏼♂
Depends on your point of view. Here by default Rust has compile time checks to ensure you don’t have any data races in your shared variables. Ada does not do this by default and allows you to mangle data between threads if you don’t know you are doing it wrong. I see this happen a lot in large projects with lots of variables. Someone doesn’t catch that a specific global isn’t protected (or is a new programmer and doesn’t realize it needs to be). It gets missed in review and then you get a really hard to track down bug in a huge code base.
I like Ada’s task/rendezvous approach better than the standard thread model of most languages, but It does allow you to make a lot of memory related mistakes using what appears to be regular/safe Ada code when you dip into concurrency (a common one I see in reviews is when/where people update variables relative to a rendezvous…inside/outside). I believe Ada added a pragma/aspect for it now, but it isn’t on by default (due to backwards compatibility concerns?) … not 100% sure on that though? So for now, default Rust would be safer if you are purely looking at memory safety.
That said I believe Ada’s tasking/rendezvous model is better for logic safety (Getting the program logic right the first time), which is a much larger factor than most admit (in my opinion).
The big hurdle for Ada concurrency is it is really complex if you want to do anything large/interesting. And that throws off a lot of new comers because they come from languages with a thread model and have no experience in Ada’s model and there are very limited affordable resources on the topic. I myself bought a book on it and got a lot of out that, but not everyone can toss $ at books.