A number of Ada users have expressed that they would rather Ada was simpler whilst others desire more features.
I appreciate Ada 83 portability but also like a lot of modern Ada features.
Out of interest. Could anyone help me with what an Gnat or other compiler Ichbiah_2022_Mode might look like. Perhaps it might be possible to use pragmas to get an estimated mode of what features he might keep or drop.
I can continue research but currently I do not have the details of his objections to Ada 95 and how those may have continued through to today is perhaps a nuanced question.
What do you think Ichbiah would jettison from Ada 2022? All comments welcome. Perhaps he would have just done things differently which doesn’t equate to dropping features?
Is not a matter of just having a simpler language, it’s a matter of removing the stuff they knew were a mistake at the time but put them in anyway, like anonymous access types, string_utf8 being a subtype of string, which is wrong from the unicode perspective because unicode isn’t a superset of latin1, it’s a superset of 7-bit ascii.
It’s also the refusal to version the language to allow for deprecations.
Ichbiah hated tagged types and he wanted classes and walked out because of that.
As a user I heartily approved of 95, 2005, and 2012. 2022 has some interesting features, but not I think ones I would pay for (said from the point of view of someone who hasn’t really felt the need to get to grip with all the details).
“Moreover, the choice of Ada over some competing language such as C or C++
is not going to depend on the presence of tasking features since these
competing alternatives do not have any. On the contrary, the presence in
9X of features that they do not use could be an argument for not using the
language as people fear the distributed inefficiencies that are commonplace
for implementation of new languages (and with the level of change presently
contemplated, 9X would be a new language to which the fine-tuning that took
place for Ada in the past ten years would not apply).”
Looks like an Ichbiah mode isn’t really possible to me.
Aside from Unsigned types in this articles list I am not sure that I see much in Ada 95 that I use or like (I don’t understand all of it). I have used tagged types once and would rather tasking and protected types never existed. Then like C most Ada code could run everywhere and be SPARK compatible. It would just be a choice as to whether you wanted to considering the hardware constraints.
Tasking and protected types?
I think you may be misunderstanding.
The whole hype about having to rewrite all the OSes/applications to take advantage of multi-core CPUs a while back could have been reduced to “recompile with a multicore-aware compiler” had those been written in Ada. — Having task as an high-level, in-built, language-level construct makes portability of non-trivial and/or multi-threaded applications much, much easier.
To make it even more stark, you might have been able to avoid even recompiling: simply re-link with a multi-core aware runtime.
See above.
Much of the “it can’t run everywhere” is actually the compiler toolchain (GCC) limitations and/or difficulties [re-]integrating Ada into GCC. — Thus the reason for people complaining about bootstrapping GNAT: it’s a pain because of how terribly un/dis-organized and intuitive it is. (Hence why I started Byron [self-hosted, 100% Ada], and the Truffle bootstrap [Java].)
Ideally though, I had wanted to have Byron have a SeedForth emitting back-end, and a SeedForth interpreter, which would reduce the load of bootstrapping to implementing the thirty-odd forth words and following a simple/intuitive compilation-path.
What?
That’s literally the opposite of true.
I, myself, have compiled non-trivial Ada from 30 years ago, written on/for an architecture/OS that “doesn’t exist anymore” having to only (a) split a file because GNAT has an implementation limitation, note not a language limitation, prohibiting the spec and body from occupying the same file; and (b) renaming about a dozen instances of an identifier that had become a reserved word in later revisions. — Having seen what porting is with C, I’m confident in saying that what I did was trivial and, TBH, as painless as porting should be given a lack of system-dependence. (I.E. things would have been different if there’d been e.g. memory mapped I/O on a IEEE-1488 and/or RS-232 port.)
Or, perhaps you’re talking about limitations due to runtimes?
That is a separate issue and, strictly speaking, not a language issue.
(I would categorize it as a tooling issue.)
Remember: GNAT is not Ada.
(AdaCore is not Ada, either.)
Does it matter what kind of issue it is. Ada 83 didn’t have the issue because it lacked protected types and tasks. Yes Ada has great portability and compatibility but it is spoilt by protected objects and tasks. The original Booch containers run on any chip with relative ease. The Ada stdlib ones do not. Along with most of the stdlib.
Yes, it really does matter — your assessment is one of the language, and features therein, which is absolutely incorrect. Ada83 certainly has tasks.
(Protected types were introduced in Ada95.)
It also matters because where you would be directing energy is not the actual issue: sure you can buy a new car when your car-battery dies… but it would be far more efficient use of your time/energy/resources to get a new battery. — But maybe it wasn’t the battery that was bad, maybe the alternator went out.
See now why it matters?
Unless there is a correct diagnosis, you cannot effectively address the underlying problem.
No, as I showed above, there is a wide portability that exceeds that of C.
(Assuming a non-trivial program and dissimilar archetecture.)
…again, you are conflating things.
There is Ada, and there is GNAT, and there are runtimes.
The runtimes, what you are calling the stdlib, might be restricted; but [IIUC] a large number of the restrictions are not due to technical issues (i.e. impossible), but rather that the full runtime is-not/has-not been ported to that chip, and if it has has not been publicly released.
This is one reason that I promote the idea of an Ada-SeedForth backend & SeedForth interpreter as the route to bootstrapping— it reduces all of those issues to (1) implementing the approximately 30 forth-words on that archetecture, and (2) running that interpreter on the target… if that is not efficient enough, then write a new native-producing backend, and recompile: thus bootstrapping to running becomes much easier (just compile to SeedForth and run that on your target), and bootstrapping to native-executable is thus only dependent on writing the appropriate backend.
(To be honest, using SeedForth as a VM is likely small and robust enough to be acceptable for [wild ass guess] 85–95% of the microcontroller needs.)
I think that you are confusing things. The runtimes are the chip support libs e.g.bb-runtimes. The level of runtime support determines how many of the Ada and Gnat and github libraries can be run without changes. C has less portability support but it does not have the problem of lots of code bases depending on complex runtime features such as taaking or protected objects which I assume is not provided in e.g. a light cortex-m* runtime because it is chip specific.Whatever the reason it requires users to port runtime support for Gnat and it is burying your head in the sand to think they would. I have seen it prevent adoption of Ada. It absolutely makes sense that it would further the use of C or other languages instead. I’m sure I could port the needed runtime support to my chips. I refuse to on principal because this has to be holding Ada adoption back and I do not need tasking or protected objects. This leads me to have further conviction that there is other complexity that Ada may be more readily adopted without e.g. more features making code harder to read, Hence the interest in Ichbaiahs concerns.
No, the runtimes are all the “automatic”/“included” functionality of the language —things like the 'Image- and 'Value-functions, the secondary-stack (for e.g. returning indefinitely sized arrays)— yes, this also includes tasking.
These are language-level features, not “chip support” — however, the runtimes are dependent upon the details of the chip (i.e. low-level) and typically cannot rely on those features.
This is why my above-described method for bootstrapping is so powerful: the whole of the runtime could be compiled into an “instruction set” of about 30-instructions, and interpreted —the full, unrestricted runtime, written in Ada— which would allow using those features even w/o a “native” executable. (With Byron, the self-hosted Ada compiler, I used this for parsing integers: Integer'Value( Token_Text )… and the same w/ floats. The same sorts of tricks can be done with an Ada runtime, translating it to SeedForth, and then allowing that to carry the weight.)
Your assumption is half-right, but half-wrong.
Remember that (a) Ada83 did have tasking, (b) compilers targeted the MIL-STD-1750 CPU, (c) that CPU was from the early 80s — I doubt that Cortex-M* have less specs.
Which is why I offer a method to ease all porting, whatsoever.
Reducing the pain of getting an “it works” to implementing 30-ish Forth-words… that would be things like
-- MAX (n1 n2 -- n3)
-- n3 is the greater of n1 and n2 according to the operation of ">" .
Procedure Max( State : not null access Forth.VM.Interpreter );
----------------------------------------------------------------
Procedure Max( State : not null access Forth.VM.Interpreter ) is
-- if the bigger item is on top, swap it. Pop the top/smaller item off.
begin
if Left(State) > Right(State) then
Swap(State.Data);
end if;
Pop(State.Data);
end Max;
Bam! One Forth word in Ada.
(In ASM it is a few instructions, and I would be surprised to see one requiring more than a dozen instructions: that is how you leverage things to make bootstrapping painless.)
Again, that’s because of how GNAT is.
Not, necessarily, how Ada is.
And, again, it absolutely could be much better.
…that’s very unhelpful.
But I don’t really blame you, GNAT is really quite difficult to bootstrap.
Which is one reason why I started Byron (self-hosted Ada compiler) and BAATS (GraalVM/Truffle implementation).
Erm, you do realize that syntax is very far from the semantics in programming-languages? [This is to say that “readability” and underlying-complexity, esp. WRT generated-code, need not be correlated at all.]
I agree with @OneWingedShark. The runtime implements the language features. It has to rely on the underlying processor/chipset but this HAL should be clearly identified. The problem of the bb-runtimes is that this is not the case. When porting bb-runtimes, you have to deep dive in the source code to understand it and adapt it to the target. I did it twice. This was a complex task. I’m not sure I did it correctly. Simple applications were running correctly but this was not the case of more complex ones. Maybe a (second) stack problem. I did not really investigate the crash I got since my goal was to evaluate the use of Ada on Cortex-M targets and my need was Ada full tasking functionalities. That’s not what bb-runtimes provides. bb-runtimes goal is to support the writing of certifiable applications (using restricting Ravenscar or Jorvik profiles).
Another solution is to use @simonjwright compiler/runtimes. It is still a subset of Ada tasking but it relies on the use of FreeRTOS. When porting to a new target, you should only modify the FreeRTOS HAL, which is a much simpler job. However, I have never tried this path, so I might be wrong here.
The light runtimes, which may well use only Ada83 syntax (though I very much doubt it – who’d want to be hobbled?) don’t have tasks. Though I do think they have interrupts, and interrupts vary wildly between different chip families.
Honestly, it feels like (and, keep in mind this is a intuitive leap, as I haven’t used the bb-runtimes, only hearing others talk on them) the bb-runtimes were never properly HAL-abstracted. — Almost like there was a kernel/model/minimal-example C-runtime [for the microcontroller] that was transliterated [possibly by automated generator] and the rest of the Ada-runtime bolted on, and then those used to spin-up functionality.
Kind of like kludging C-#ifdefs and “macros” as a poor-man’s generic-system in order to provide “portability”, though because Ada doesn’t have a pre-processor these are forced external. — IOW, applying the C-mindset of “good enough” half-solutions on the base-levels.
The absurd thing here is that bootstrapping need not be a painful process at all, though it does require upfront engineering work to make it painless: and that is what the C-mindset precludes. (I.E. “Good enough” means it works for the 80% or so, and precludes any finishing because “it’s good enough for my use” and “it works on my computer”.)
You would think that Cortex-M, being a family of very related processors, that much of the interfacing/HAL could be a collection of generics atop a common core— indeed, using the SeedForth idea, you could use a singular ARM SeedForth VM to execute the common ARM instructions, using the Ada written runtime(s) translated w/ the Ada-to-SeedForth backend, doing minor patches to the emitted IR-/opcode-stream as needed. (e.g. using the opcodes/interfacing for the 24-bit system-time w/i tasking for the M7, vs not using such for an M0 w/o the timer should be as simple as replacing that particular function’s word-sequence with one specialized for the task.)
Or, to give a clearer example, consider test-and-set:
On instructions with the instruction use the opcode directly;
For CPUs lacking TSET:
Disable interrupts;
Test the value;
Set if appropriate; and
Enable interrupts.
The VM-opcode/SeedForth-words for the CPU would implement the SeedForth word as the appropriate set of instructions— meaning that there would need no code-changes or recompilation to accommodate the presence/absence of TSET.
Interesting.
This is why I’d like to have a formally verified:
Ada front-end;
Ada backend, generating SeedForth;
Ada implementation of SeedForth;
Ada implementation of of the runtime.
Given these four items, bootstrapping into a verified correct Ada is merely application of procedurally applying these, repeatedly, in particular order. (And the dirty secret: once you have the SeedForth stream, you can re-use them w/o having to recompile, meaning you can distribute the streams as the “executables”.)
That might be the stated goal, but the amount of deep-dive you’ve been describing makes me wonder if that isn’t post-hoc rationalization — the “extra work” of producing a verified SeedForth backend & verified SeedForth interpreter are the only things needed to make the porting part of bootstrapping “solved” in a verified environment.
(Having a verified Ada frontend, and “middle-end” [gag, what a horrid term], is the other part to having fully verified toolsets.)
Having a good abstraction to program against absolutely helps.
There’s a Roman saying: well-begun is half done.
@simonjwright What is your evaluation on the runtime-topic as-a-whole? And do you have any particular insights WRT wild variances among different chip-families?
On a light runtime kindly provided by Gnat to work on e.g. cortex-m33 then there isn’t support. Note there are different runtimes even for cortex-m0, m3, m4 and m33. Where the system clock setup is untouched by the runtimes and the runtimes are independent of the clock setup. One issue with heavier run times may be dynamic clock speeds used by low power parts. So I am skeptical of @OneWingedShark claims.
For STM32F4, FreeRTOS_Ada’s port-specific files are
FreeRTOSConfig.h
a-interr.adb, interrupt handling
a-interr.ads, same
a-intnam.ads, derived from SVD interrupts package
interrupt_vectors.s, actual interrupt vector (used to be able to write this in Ada!)
s-interr.adb, interrupt handling
s-interr.ads, same (needs to be different from other ports because of number of interrupts)
startup-set_up_clock.adb, separated out to reduce complexity in startup.adb
startup.adb, sets up stack pointer, interrupts, data, bss (& for this port some address vectoring)
startup.ads, actually I think this could possibly be in common?
stm32f40x-flash.ads, from SVD, for the hardware
stm32f40x-pwr.ads., same
stm32f40x-rcc.ads., same
stm32f40x.ads, same
system.ads. things like Tick, number of interrupts
I haven’t looked very closely but doesn’t look like that much porting work. I asked a couple of questions on the projects mailing list. I’m quite happy with bare metal but interrupt package support might be quite nice and perhaps it would provide for more Ada code support like the two Ada containers it currently provides for.