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.