Combine .ads and .adb to one .ada file

you might want to have a look at Expression functions for simple functions like that:

function Increment_By (I: Integer; Incr: Integer := 1) return Integer is
  (I + Incr);
1 Like

From what I understand, their development process has in fact been problematic, including a lot of personnel turnover. I also should probably have qualified the above by saying that I havenā€™t personally witnessed these 2-hour builds; thatā€™s what Iā€™ve been told, and that was from some members of our team who arenā€™t fans of theirs. It wouldnā€™t surprise me if there were some exaggeration there, or if it were a problem that happened once in the past and that theyā€™ve since addressed, etc.

While this can be true, Rust has honest-to-goodness modules and incremental compilation, which helps a lot with this. The produce we work on builds from scratch in single-digit minutes both locally and in CI, despite a very large codebase and the heavy use of macros. Typically weā€™re not building from scratch, so compiling takes much less time than that; if it helps, we tend to get annoyed if it lasts more than a few seconds. But one reason for this is that our lead took some time a month or two back to review our dependencies and prune the ones we werenā€™t using, or even some of those that we were using but could find better alternatives. A reorganization of the code also helped.

The single longest event in our build is linking, and that has more to do with --release and link-time optimization. For a while I would build without that, and the compile times were a lot shorter, but eventually I had to start using that again, as execution time grew unacceptably slow.

I didnā€™t see this in the existing replies (though maybe I missed it): The separation of pkg spec and body is a deliberate design decision intended to support the development of large projects. During initial design, major design decisions can be formalized as pkg specs, and the compiler then enforces those decisions. Meanwhile, the decision of how to implement the concept represented by the pkg can be delayed until later, but other parts of the system that use the pkg can still be implemented before the body exists. When the body is implemented, you can experiment with different implementation decisions without affecting the code that uses the pkg.

Clearly, some of this is impossible in a language that requires the two concepts to exist together, or that only provides for the body concept with possible generation of a spec from the body. Since support for large projects is an important goal of S/W eng, separation of spec and body is one of the ways that Ada supports S/W eng and the way that S/W engs think.

5 Likes

I might be a bit late, but I think that single file packages can be useful for distribution purposes. For example there is an increasing number of single-file C libraries consisting in just a single .h file, as that simplifies adding them to projects and avoids having different build systems for the project and the library.

Single file libraries also limit interferences caused by copying 3rd party files into the project folder (two libraries might use a package with the exact same name). This can also be avoided by building them into separate static libraries.

Taking this into account, I think that it might be worth exploring the idea of single-file packages in Ada for distribution purposes (similar to jar files in Java). During compilation, that file could be extracted into a temporary folder, compiled into a static or dynamic library and finally linked.

I havenā€™t personally witnessed these 2-hour builds; thatā€™s what Iā€™ve been told, and that was from some members of our team who arenā€™t fans of theirs.

Follow-up: I just peeked and their current build time is about half and hour.

This conversion seems to have two separate threads:

  • some people want to basically get rid of the package specs, to copy what is done in other languages.
    I think this would get rid of one of the most significant benefits of using Ada compared to those languages. They always rely on external tools to generate readable documentation from their unique file, because having everything mixed up in the same file means the latter is very hard to read for people new to the package.

  • others want to keep spec and body, but merge them in a single file. One argument seems to be that it is easier to distribute. The Ada standard doesnā€™t impose anything in that respect (and indeed GNAT was the first/only compiler to separate them in two files by default), so this part of the discussion is mostly related to GNAT. And this is already doable via project files. The tool gnatname also makes it easy to generate such project files I believe. It might make sense for distribution purposes, I do not recommend that during development since indeed it will increase compilation times.

3 Likes

Can you expound? This happens the same whether using single file or multiple files. Either way if your packages are named the same, it will cause a conflict in both scenarios.

I donā€™t disagree with your premise (I too think separate spec and body is the way to go and that there should always be a spec), but I will say it is not impossible. We used a custom C++ compiler (I forget the name offhandā€¦like nearly 20 years ago now) that was smart enough to separate the intended ā€œ.hā€ parts of a single file from the ā€œ.cppā€ parts and treat them as separate files for the compilation process. It was pretty smart and would not recompile any files that only relied on the ā€œ.hā€ part unless that part changed. I think they used a marker ā€œcommentā€ to separate the sections of the file (againā€¦20 years ago, so donā€™t hold me to that). It would be even easier to do in Ada as ā€œpackage X is ā€¦ end Xā€ and ā€œpackage body X is ā€¦ end Xā€ are pretty easy to parse quickly in a file. That said, I donā€™t think single file is the way to go. I really like the normal Ada compiler convention of split spec and body files.

Having a single file per library reduces the possibility of having multiple files with the same name. Normally a library consists in multiple packages, so a gui library might have a package called vector and a sound processing library might also use a different package called vector, which could cause a conflict if both files get copied into a single folder. If things get done properly, each library would be stored in separate folders or compiled into static or dynamic libraries. Using a dependency manager would also avoid these types of conflicts.

However, building the library separately requires a two stage compilation and, as Ada does not enforce using a specific file format and extension (as it has been said before each compiler has different approaches), the dependency manager could be incompatible with the only compiler available for a particular target. A container format enforced by the standard avoids these limitations, as well as things like forgetting to copy any of the sources (either the library is included or not). It also could allow to hide internal packages from the user of the library (following the previous example, it might not make sense to expose vector package)

Another reason for having a jar-like distribution format could be handling resources properly. For example a library might require some resources (images, configuration files, DLLsā€¦), which need to be copied to a particular folder. Graalvm (an aot Java compiler) does this automatically, avoiding setup problems. Additionally, python wheels handle library building automatically, which is handy if several languages are used (for example a library written in rust might require using C as an intermediate layer to interface with Ada or python)
If some resources are operating system or architecture dependent (like a shared library), graalvm chooses the adƩcuate one from the ones provided in the jar file. This could be interesting to avoid Ada libraries from using compiler provided preprocessors to handle cross-platform support (a single specification could be used for every platform and a separate implementation for each one, being the adequate one chosen automatically by the compiler).

Finally, jars can also contain documentation, which could be an interesting feature for a language like Ada.

In general all these things can be solved using additional programs (which might be different for each library, as it happens in C when a library requires scons to get built and another one cmake), but having something like this included in the standard would simplify distributing packages that could be used by any Ada compiler.

The form of the program library needs to be abstracted away I think. Wether the program is stored in a file format or database format or tree strukture in memory format. Then the program text is exported from/imported to the library.

The specifications should be able to build on their own.

Iā€™m not sure if Iā€™m understanding your response well. Do you mean that Ada compilers should be able to read the source code of a program independently of the format in which it has been stored (a database, a text file or a tree structure)? Or do you mean that each compiler should be allowed to choose the format that it requires the source code to be stored in?

Reading any format would solve the problem of reusing Ada code written for different compilers, but it might be difficult to support every possibility.

On the other hand, allowing compilers to choose the format in which the source code needs to be stored limits code reusability (each compiler might choose a completely different solution). That can be a problem for developing successful open source libraries, as they would require additional tools for targeting multiple compilers. In this case, allowing compilers to choose the format that they normally use, but enforcing them to support a standard source code exchange format (not necessarily a human readable text file format, just a file format that allows distributing libraries for any Ada compiler) could help increasing the number of Ada libraries available.

Iā€™m sorry for taking so long to reply. I didnā€™t receive the usual mail notifying that this thread had new responses

I am not sure I use the correct words hereā€¦

The program text is the human readable form for program exchange.

The compiling system may store the program as it wishes.

This will require that we should let go of the idea that we should control how the program text is exactly formatted - like how comments are written and so, and use a configured style instead when viewing the program.

For GNAT it is chosen to use program text as input.

The Rational Ada machine from around 1994 does it otherwise as far as I know. This machine is said to be far ahead of its time.

In other words; move away from looking at the program as the program text. The program is stored somehow (library I guess), and we import the program text into the library and exports for exchange. Viewing/editing (managed) should be integrated in the IDE (hopefully)

1 Like

I didnā€™t know that. Was that machine something similar to a Smalltalk virtual machine? Did it support REPL?

Itā€™s a long time ago now! but - the command shell was very Ada-like.

I would love trying that system. I started using Ada as a substitute of matlab. Adacore library for using units (like meters or seconds) is great for detecting errors in scientific programs and Ada allows managing memory much better than matlab. However, I miss how easy is plotting graphs in matlab

Rational/R1000s400

https://datamuseum.dk/wiki/Rational/R1000s400

Not quite sure about this but it may use DIANA internallyā€¦

DIANA

Which may have been superseded by ASIS.