Anyone interested in resurrecting an open source strict Ada 83 (mil-std 1815A) compiler?

I havn’t understood the interest since GNAT has a -gnat83 option, then we can easily avoid extra feature in our development.

To have more choice ? I am a bit puzzled. The interest of an alternative is when the new product is better than the previous in at most one aspect. It has been stressed that C compilers have multiple free alternatives. But Clang and LLVM has been developped because of some drawbacks of gcc. Which drawback of gnat will be addressed in the proposed alternative ? (portability ? performance ? better error reports ? other ?)

1 Like

Hi !

gnat user manual says :

-gnat83
Although GNAT is primarily an Ada 95 compiler, it accepts this switch to specify that an Ada 83 program is to be compiled in Ada 83 mode. If you specify this switch, GNAT rejects most Ada 95 extensions and applies Ada 83 semantics where this can be done easily. It is not possible to guarantee this switch does a perfect job; for example, some subtle tests, such as are found in earlier ACVC tests (and that have been removed from the ACATS suite for Ada 95), might not compile correctly.

In short, -gnat83 switch does not insure you have strict Ada 83 enforced.

The problem with Ada versions and gnat updates is long term drifting which generates compilation problems on some old gnat sources.
I never had compilation problems with pure Ada 83, after gnat Ada 95 some incompatibilities appeared over time and symptoms which often occur in C compilation (warnings, errors, incompatible versions) began to appear in gnat Ada.

Ada 83 has a very precise definition aiming at uniform compilation and execution behavior on various hardware, and keeping some strictly conformant Ada 83 compilers is something desirable.

My 2 cents wrt. Ada 83:
Avionics safety critical embeddes software

  • Development, unit and integration test on host computer, tests on software test bench: some Ada 83 compiler
  • Ported to mockup for target tests, embedded target computer: different Ada 83 compiler manufacturer

I’ve never heard of difficulties when porting.

  • Rehosted the complete software for a fullscale flight simulator (big dome with two simultaneous crews): Ada 95 compiler from yet another compiler builder; with extensions up to Ada 2012
  • Original software: Big endian
  • Flight simulator: Little endian

No big problems encountered except for little vs. big endian.

So I would say: When using -gnat83, you won’t stumble over problems because of incompatibilites between Ada 83 and 95. Go ahead with this switch!

There is one I’m aware of: An oversight in Ada 83 with generic type parameters:

generic
  type T is private;  -- Ada 83

When instantiating with an unconstrained type, the body could fail.

type T (<>) is private;  -- Ada 95

cured the situation.

First of all: you’re of course right in a utilitarian way. GNAT is a fantastic compiler and I personally wouldn’t want to backport the systems I’ve written in Ada 2012 to Ada 83. Let alone the horrible task of trying to communicate such a flight of fancy to my clients :smiley:

For most intends and purposes it does not seem to make much sense to want to have a different option of writing Ada 83 code than using the -gnat83 flag. But bear with me, because I do have thoughts (and as I found out “feelings” about this :-).

My personal summary of reasons why I would love to have an open source strict Ada 83 compiler:

  • I love computer history and especially anything regarding programming language theory and development. It’s immensely valuable to realize that many of the fundamental CS problems we are facing today were already in the minds of great thinkers in the 1900s. A nice way to experience this history is to try to immerse yourself in it. With computers we often have the ability to do so. Doing this as a sort of exercise helps you understand the reasons why our field developed like it did and also helps thinking about our future. Why did Ada 95 evolve this way? Why is Ada 2022 considered a “big” language but maybe not such a bad thing? What good arguments are there for this instead of sticking to Ada 83? I think there are more than enough reasons, but I feel nothing helps cement that thought process like experiencing Ada 83 especially using the compilers of the day.

  • Having a separate “small” Ada 83 compiler helps in the efforts with regards to permacomputing and “human scale” computing. The idea that a single person can read and understand an entire compiler without making it a gigantic effort is very charming to me. If we had a separate Ada 83 compiler that was relatively easy to grok and extend to supporting other target platforms, you could make it a nice part of the permacomputing scene. Ada has a great mix of high level programming features and considerations for correctness paired with the ability to go super close to the metal. I don’t know any other language that balances this so well. I like playing around with the UXN/Varvara ecosystem and Ada 83 is one of the high level languages that would actually be feasible to use for targetting this 64kb 8-bit VM.

  • You don’t always need the full modern Ada to be productive. I have tested compiling Ada to WASM with the awesome GNAT LLVM toolchain. It’s a very neat feat of engineering and might in the future be quite usable for a lot of tasks, but at the moment I wouldn’t use it for replacing the JavaScript in a typical SPA. I often have to write web interfaces in embedded environments and pulling in a WASM file that is hundreds of kb’s is too much. Making a smaller RTS, and all the other things involved in getting the size down when compiling “modern” Ada is quite a task. Interesting to some, but I prefer to work from the ground up instead and would love to be able to make an Ada 83 backend that outputs WASM directly. This DIANA project that Vincent has so kindly brought to our attention might be just the ticket :heart_eyes:

  • In the free software side of things Ada has one main compiler and although understandable I think it’s not necessarily a good thing for the health of the language in general. I applaud all the efforts of Adacore and all the other folks who work on GNAT and you’ll have to pull that compiler from my cold dead hands, but having alternatives is a good thing in general. It helps the ecosystem. It opens up alternative paths to the future, to other languages perhaps, or to support on all kinds of platforms. Porting GNAT is quite a bit of effort and although cross-compiling is neat there’s nothing like hearing an old machine from decades ago purring while it’s meticulously compiling the code I’ve written in 2024. But that might be a personal defect :grin:

There might be some more “engineery” reasons why Ada 83 is valuable or maybe sometimes even more so than modern Ada’s. I know there’s still people who prefer C (even C89) to C++ for example, so there might be something there. However I wouldn’t know frankly. I’m no expert since the first Ada I used was Ada 2005, so my love of this language kind of “grew up” in the modern era.

5 Likes

I guess that additions to each previous version helps to make the language more expressive. I guess the GtkAda library is more natural with tagged types.

Well, GNAT has already a llvm backend. If the alternative compiles Ada to llvm IR, I guess that it won’t help targeting other platforms. I have read about a SeedForth approach. I guess that the approach is interesting:

  • threaded code is more compact than machine language,
  • easily portable (a FORTH interpreter/compiler is probably one of the easier system to port).

But it will be less efficient.

GNAT isn’t a real LLVM-level compiler, it’s not equal to clang, it’s not library based.

Hi Jelle !

Your post is very interesting and brings forward deep questions about software resilience, durability, human size technique and understandability. The concept of permacomputing (which I did not know) is really worth thinking about.

Time resilience of Ada 83.

I already alluded to this, but it is a strinking demonstration of Ada 83’s value : I passed my thesis in 1988, the subject was about a symbolic simulation software for electronic circuits. The algorithm is very clever using Coates-Mason graphs for extracting complex transfer functions under the form of the ratio of two polynomial functions. When I started in 1985, my polish thesis director had a Fortran program with an exceedingly astute system for calculating 1-connections ; but it was such a pain to understand how it functioned that I spent several months making it well clear amongst common blocks and Fortran arrays. I convinced my director that if somebody else than her had to improve this simulator, it could not stay in this obfuscated Fortan software. Being young and informed of edge cutting software technology, I proposed to reprogram in Ada 83 which was something really new in 1985. So they bought a MicroVax with DEC Ada ; that was a “whaouh” system and I had a real chance.
After my thesis I had to change my occupations to university jobs and the symbolic simulator stayed in the CNET research center in Paris.
About two years ago, tidying old papers, I found a listing book that I had carefully kept aside : a complete very good quality laser listing of my 1988 final Ada software printed at this time on the Multics system laser printer of Issy les Moulineaux. I scanned with OCR all the pages and recovered all packages easily on Linux. Believe it (or not), gnat recompiled it “floup” without problem, 34 years later ! I can today use it on an x64 Ubuntu as in 1988 !

Drifting gnat compiler and over conceptualization with Ada 95

The other example illustrates opposite properties and drawbacks of gnat compiler evolution.
I stayed an unconditional fan of the Macintosh plus and many years ago (around 1997), I reprogrammed the Mac OS from reading of the four “Inside Macintosh” volumes, targeting x86 with an add on powerpc Intel board. A first version written in CodeWarrior Pascal was very elaborate thanks to the very ergonomic and performant CW ide/debugger on Apple’s Mac, but it became difficult to read and maintain alone ; and today I have problems to understand quickly the Pascal code which was also full of peculiar CW Pascal idiosyncrasies. Anyway, Codewarrior system inflated and finally disappeared in its practical form. The Pascal OS software became unusable.

To convince myself of the true nature of C language, I restarted programming the Mac OS in C. I quickly abandoned, it was an horror, much sooner than Pascal it became unreadable and impractical to maintain structuring being inexistent.

So I restarted once again with Ada 95 gnat. But the new object functions offered led me to a conceptual surcharge in the system definition and it became more complicated than the initial Macintosh structure. Wanting to do too well with tagged typed led me astray from simplicity. Especially the memory manager became a strangely complicated module.

And I restarted once more by writing Ada 83 conformant code with only the tolerance of child packages because I did not see how to program system interfaces which could be reused by applications with a table of content jump mechanism and system implementations only present when compiling the system. Constrained by Ada 83, the system was better, conceptually simpler than with Ada 95 and much closer to Macintosh Pascal version.
With gnat 3.15 I could produce a cross system debugged on Bochs and USB bootable on a bare x86. Then gnat evolved, some critical pragma became obsolete, system predefined modules changed and I could not produce the executable anymore, moreover the gnat 3.15 compiler became impossible to recompile with posterior gnat/gcc versions…
Finally, I discovered that conditional compilation for packages was possible inside Ada 83, so that I got rid of the Ada 95 child packages (which moreover complicated the global variables arrangement because child packages promote a sort of multi sub-level access efflorescence, while in Ada 83 variables are only visible from top of module).
So finally, to my complete satisfaction, this Mac OS reproduction wandering exercise brought me back to a pure Ada 83 system on Linux with less files and simpler structure. But I lost cross compilation and execution on an old x86 pc, which I got once with Pascal Code Warrior and a second time with gnat 3.15 ; and twice I lost this opportunity with changing compilation systems.

Conclusion

For your software to pass year decades fresh and pink, to avoid headache when diving in old software, program in Ada 83 !
These are some of the reasons why I got attached to availability of a pure Ada 83 open compiler.

Now this conclusion is especially valid when the developer team has cardinal one or a few and time to think how to do best for durability. With a number of engineers, enough programming power and time constraints, things can be made differently.

4 Likes

Threaded code essentially uses lists of addresses. On 64 bits address machine, it is a disaster.

Your story reminds me of the discussion about “the hundred-year programming language” a few years back. (See for example The Hundred-Year Programming Language | Lobsters ). The programming language Hare aims to become just that. It’s a very interesting endeavor and Ada 83 might be a feasible way to achieve this as well. Given the fact that it was developed before I was born and most Ada 83 code still compiles fairly easily is quite a testament to it’s resilience indeed.

I could put up a wiki so we can store the info we collect on old Ada 83 compilers there and the ideas regarding building a modern Ada 83 compiler. Would that be a good idea?

@VMo I do think tagged type (and Oriented Object Programming more generally) can be very useful in some cases.

Typically, an operating system that propose generic files (regular files, tape device, raw disk/partition…). The read method must be dispatched according to the actual type of the file handle and the method would need to access different internal data. An other one is GUI where a dialog box is a bunch of widgets which behave differently.

We could use instead a giant record with variant (type Generally_File(Kind : File_Kind) is record case Kind …) but implementing a new file kind would need to change many parts (the type definition, each « methods »… An object oriented way would just need to add a new package and register a object factory (it can be a simple Open_File procedure access).

Very useful for some tasks, but probably harmful for others ! It is interesting to see OCaml where the O is about objects. Very very few programs use really the Object Oriented features, but the Gtk binding library use them which is well adapted.

1 Like

Hi @F-Loyer

I answer briefly because the subject is somewhat aside of the initial topic.

For sure Ada 95 object programming can be usefully employed.
But for scientific computing, embedded and high reliability micro-controller systems, Object Programming (OP, with classes or tags) is mostly inappropriate and class are mainly used for methods grouping as a contrived module packaging of subprograms.
Now Object Oriented Programming (OOP) is what Ada 83 was already promoting with packages and private types (see note below).

For your first example, “read” subprogram overloading suffices with different data structures as appropriate for parameters.
For the second example, when I re-implemented the Draw, Windows, Controls, Dialogs… modules of MacPlus MacOS GUI, I tried Ada 95 tagged types and abstractions. It was not simpler than the original.
If someone fluent in Ada 9X/2X takes it as an exercise : prove that Ada 9X/2X allows better expression (simpler, more compact/easy to grasp) of equivalent GUI services offered by ancient Macintosh API ; just an interface specification will do.
Another exercise : demonstrate that with Ada 9X/2X Object Programming one could make a Squeak like system with better properties than Smalltalk.

NB: I make a distinction between OP (Smalltalk and class languages) and OOP (Ada 83). Most people don’t and call OOP the use of class and instances, leaving no term for programming with classical module packaging of private/discriminated data types and subprograms.

1 Like

I think the problem with this is that it is very subjective. You can’t prove that since what is simple, better expression, compact/easy to grasp are all things that people can view/rate differently. Additionally, many people have different priorities when writing code and reading code so there isn’t one unified answer to that.

For me, having to update all kinds of case statements and variable definitions every time we add a new component, made maintaining a non class based GUI framework a huge maintenance hazard. It wasn’t simple, it was super error prone (lots of copy/paste errors over the years from multiple different developers), it was very difficult and time consuming to update with new global features, and it made the code really hard to read (for me, I’m sure some folks were fine with it). Some folks might find it simple though, it all boils down to preference.

1 Like

I usually think of “object-oriented” not merely as modularity, but as including “inheritance” or “type extension”. For instance, Simula and Smalltalk, the prime examples of OO languages (or so they were called when I was young, 30 years ago), both offer inheritance.

To be honest, I always thought that was the main requirement of it: in the main motivating situation, “type Window is a Container” and “type Container is a Component”, automatically gaining functionality. I know it’s possible to implement this without it, but in my experience it’s much harder, and the implementations are usually ugly and hard to work with.

1 Like

I’m reading some of the Ada 83 literature and have noticed some writers using “object based” to describe Ada 83 in contrast to “object oriented” in the conventional sense.

1 Like

The object paradigm is about 3 things:

  • encapsulation,
  • Inheritance,
  • Polymorphism (in sense dynamic dispatching).

Ada83 only provides the encapsulation (private type).

Ada95 with tagged types, add the other aspect needed for a strict object oriented programming.

Note: there is also geneticity which is provided since Ada83, a must have feature, but not implied by the OOP.

1 Like

Modern convention states that OOP is what class based languages support.

Though it proves largely useless to be the single opponent of widely accepted qualifications of things, I personally think that this convention lacks precision and we should say that class based languages in fact support OP ; not oriented, but truly object programming because the language aims at describing objects and their behavior in the manner real objects behave. And effectively this implies inheritance as an economy measure to describe non redundantly the objects, encapsulation resulting from a natural “belongs to” implementation of operations and properties, and polymorphism as a mechanism of effecting what an object has to do taken its inherited and singular characteristics into account.

In the same line of thinking, Ada 83 should not be called an OP language but should be rather named OOP, because with encapsulation and genericity it promotes a programming model where data structures are computer implementations inspired from real life objects or concepts and related operations are meaningfully grouped into modules operating on thoses formalized computerized “objects”.
This Object Oriented approach is generally sufficient when scientific computing or computerized control is in question, that is when raw computing has priority over virtual worlds simulation. Oriented programming brings conceptual clarity without the need of complex mechanisms and hierarchical structure descriptions whose appraisal is often time consuming.

So with my conventions, Ada 83 is an OOP language, Ada 95 is an OP language.

Some short news about the Ada 83 / Diana / fasmg TLALOC compiler. I have found a solution for the generics in TEXT_IO. Though adapted first for those simple generics as INTEGER_IO, FLOAT_IO and so on which only have a type as generic parameter, I think this solution can be generalized.

Problems with fasmg namespace hierarchy have been resolved for this generic problem resolution (a root namespace has been added which corresponds to the STANDARD Ada 83 package).

A version of the “hanoi_tower” program runs. There are some improvements to do in relation with string catenation.

1 Like

Hello to all interested in the topic. I added some wiki pages to the framagit project. Feel free to have a look and comment about the information (clarity, structuration…).

I tried to understand some modern software development organization such as CI/CD. Is there a docker image for gnat ? Ruby or Rust have official Docker images. I understood that such images allowed compilation of projects sources in a controlled environment. Wouldn’t it be useful for Ada ?

Also, I had a look at Free Pascal Compiler documentation system, it seems to me that it has interesting aspects. Do some Ada people have ideas on how to document efficiently an Ada software system ? The aim is to grasp the system source code structure and interact easily with it.

Nice day to all !

I am having a hard time with Ada 83 runtime support. I added one page to the Framagit wiki on the relation between three Diana node types which are at first confusing (TYPE_DECL, TYPE_DEF and TYPE_SPEC).

I had to dive in because of the FILE_TYPE limited private type in TEXT_IO. Linux file support through syscalls does not allow DELETE on an open file id, only unlink with a file name. So the TEXT_IO.FILE_TYPE must be a record with LINE, COL, PAGE… and a string array for the file name, so that a DELETE( FILE :in out FILE_TYPE ) can be realized with unlink on memorized opening name.

At first I thought it would be simple… nope. A general approach to composite types in Ada 83 is not that simple. The best reference to understand the problems is P.Kruchten’s thesis (especially chapter 4) which details what has been done in Ada/Ed and gives some hints on what others have done at the time.

So I read again with scrutiny this these, had a closer look at the Ada/Ed interpreter files (inta.c, intb.c, intc.c and associated headers) and tried to find a correct formulation for FASMg.
It is beginning to take shape, but this is difficult.

There is a non obvious runtime support for Ada 83. It sometimes surprises me that such a demanding language can be used to program for example an AVR atmega328P microcontroller.

Why are these confusing?
Page 84 [PDF pg], of the DIANA manual (rev 4) says:

The classes TYPE SPEC and TYPE DEF are complementary – the former
represents the semantic concept of an Aja type or subtype, the latter represents
the syntax of the declaration of an Ada type or subtype. A TYPE SPEC node does
not represent source code; it has no lexical or structural attributes, only
semantic attributes and code attributes. A TYPE DEF node has no other purpose
than to record source rode, containing only lexical and structural attributes.
A node from class TYPE SPEC will NEVER be designated by a structural attribute,
a…

So, translating:

  • TYPE_SPEC: the conceptual components of the type, the things to which attributes are bound.
  • TYPE_DEF: the textual stuff for the source-code.

The runtime support is actually one of the more interesting problems when doing self-hosted Ada translators because you can offload a lot onto it; consider the (IMO wrongheaded) typical compiler-construction for dealing with the recognition/parsing of base-types, e.g. Integer: throw RegEx at it! — But with Ada, we can offload things to the runtime, avoiding dependency on RegEx altogether: Integer'Value( Text );.

This allows the self-hosted compiler to offload onto the runtime the entire concept of “recognize-and-parse Integer — but at the language-level, as this construct reads and renders based-numbers (3#11# → Val:4), as well as the more uncommon forms like exponentiated (12e8 → Val: 1200000000), or separated (2_328 → Val:2328) — so, while this is a function of the form Function Parse(X: String) return Integer, with the simple concept of “transform a textual representation to an integer value” it is hiding a lot of complexity… but, this is again where the techniques of bootstrapping [w/ Ada] can be used to simplify the problem.

Consider the following:

Package Runtime is
  Function Integer_Value( X: String ) Return Integer;
  Function Float_Value  ( X: String ) Return Float;
  -- …other runtime functions.
Private
  -- Using the '$' separator for VMS-look-and-feel…
  pragma Export(Ada, Integer_Value, "INTEGER$VALUE");
  pragma Export(Ada, Flaoat_Value, "FLOAT$VALUE");
End Runtime;

with

Package Body Runtime is
  -- Hm, let's cheat:
  Function Integer_Value( X: String ) Return Integer
    renames Integer'Value;
  Function Float_Value  ( X: String ) Return Float
    renames Float'Value;
End Runtime;

But what about the viral-GPL?!!?!1!?
Simple, cheat-harder.
(Because Ada has the ability to do separate implementations - Use the above, generate the assembly to make the “shape” you need, then use the below + rewritten-assembly.)

Package Body Runtime is
  Function Integer_Value( X: String ) Return Integer;
  Pragma Import( Ada, Integer_Value, "ASM.INTEGER.VALUE" );

  Function Float_Value  ( X: String ) Return Float;
  Pragma Import( Ada, Float_Value, "ASM.FLOAT.VALUE" );

You could also write the runtime in Ada, and use the same re-export/import trick.

EDIT:
Two perhaps non-obvious consequences of this “cheating” using import/export are (1) it allows incremental changes of your implementation-language [in this case ASM to Ada] for the runtime; and (2) it allows you also to do something like RT_Unimplemented function where you overload RT_Unimplemented (function raising an exception) across all your runtime-function profiles, have your Runtime-body be renames on everything to RT_Unimplemented and the incrementally replace the renames with the implementation for that function.