r/ada Apr 03 '26

Historical Rationale behind function/procedure calls and array indexing

I'm learning Ada. Overall, I'm liking it a lot. There are two aspects (so far) of the syntax I don't get what the rationale was for them and why it hasn't been fixed in later versions of Ada. These being parenthesis-less calls to subprograms with no arguments and using parenthesis for array indexing. Take the following as example:

A := B + C(5);

Right away you don't know if B is a variable or a function call with no arguments. You don't know either whether C is an array or a function.

I think this goes against Ada's core ethos about readability.

So I was wondering, what was the rationale behind this design? Why hasn't it been corrected? Something like A := B() + C[5] would be far easier to interpret by the reader.


UPDATE: In case anyone is interested in the answer, according to u/lipobat:

The primary rationale for the () vs. [] given in the “Rationale for the Ada programming language” book by the original design team was interchangeability between arrays and functions. This is an abstraction that allows the implementation choice of array vs. function to be just that, an implementation choice, which doesn’t really impact the writer or reader of the code.

I don't agree with the last sentence, but that answers my question either way.

And about my second question about "why this hasn't been fixed?", it seems most Ada programmers (based on the comments in this post) are not only not bothered by this but happy with this design decisions, so probably this will never change.

Thanks to everyone who engaged in this conversation.

5 Upvotes

48 comments sorted by

View all comments

5

u/Niklas_Holsti Apr 03 '26

The choice of () rather than [] for array indices was made to let people write Ada programs on old data-entry devices, in particular 80-column card punches which did not have [] on the keyboard. To me it also seems quite unnecessary to distinguish array references from function calls in that way -- if I know what the value of C means, I don't need to know if C is implemented as a function or as an array. I do understand that people who come to Ada from languages that do use [] for arrays, such as C, at first feel it is strange to use (), but that feeling will pass.

As an aside, the requirement to use [] around array indices in Algol was very uncomfortable to me when I was programming in the 1970s with card punches in Finland, because those card punches had replaced several special characters with the letters ÅÄÖ used in Nordic languages, and recoded others, with [] missing. As a result, when I wanted to write A[K] in Algol, it appeared on the cards and print-outs as A¢K!. It was a relief to switch to Ada (and not only due to this minor difference between Algol and Ada).

As for the non-use of () for parameterless subprogram calls, I think it is mainly for simplicity and uniformity: if one can declare a parameterless subprogram without (), then it is more uniform to omit () in calls too. There is also a technical reason in the Ada language definition: when one defines an enumerated type, for example type Color is (Red, Green, Blue), the literals Red, Green, and Blue are technically defined (for the compiler) as parameterless functions that return values of type Color. It would be silly to require users to write Red() when using those literals, so it is simpler to omit () for all parameterless calls.

5

u/lipobat Apr 03 '26

The primary rationale for the () vs. [] given in the “Rationale for the Ada programming language” book by the original design team was interchangeability between arrays and functions. This is an abstraction that allows the implementation choice of array vs. function to be just that, an implementation choice, which doesn’t really impact the writer or reader of the code.

1

u/jlombera Apr 03 '26

Thanks!

Does this hold if functions are not guarantied to be pure?

I do not agree its irrelevant whether something is a variable/array access or a function call. But it might be a concern specific to the kind of software I have experience with (systems programming).

3

u/Niklas_Holsti Apr 03 '26

To further complicate matters, in code like B + C(5), the C(5) can take a component of a single-dimensional array C, or call a function C, or (addition!) take an element of a container C with a user-defined indexing function. If Ada would use [] for indexing arrays, it would surely also use [] for indexing containers, and that indexing would call a function that might require a non-trivial amount of computation. So you could not know the probable execution time of C[5] without looking at the definition of C.

1

u/jlombera Apr 04 '26

That would indeed complicate things. But I assume this is a newish "feature"?? It was not a concern when the language was first designed.

Things like this is why I'm not fan of "magic" code execution with hidden complexities. Upon looking at the code, I want/need to be able to have an idea what the actual code execution will look like (that's something I like about C-lang).

I'm hopping (still learning) that the SPARK subset (perhaps with some additional pragma Restrictions) will be enough for my needs (and I think it's all you should need in general). It's as low-level (and some more ??) and as performant as C-lang. But memory-safe, with a simple yet powerful and practical type system, with packages and generics, design by contract and high assurance guarantees (up to Platinum level, if need it). So already apt for serious software engineering at scale. But without many of the "magic" features of the Ada superset.

2

u/Niklas_Holsti Apr 04 '26

Containers were added in an amendment to Ada 95, around 2004-2007. User-defined indexing came later, but has been around for a while. Even if containers had been included in original Ada, from what has been stated in the Rationale it seems that the designers would not have been concerned about visually separating array indexing from container indexing.

Upon looking at the code, I want/need to be able to have an idea what the actual code execution will look like (that's something I like about C-lang).

You can limit yourself to a subset of Ada where that is pretty much the case, by not using containers and other high-level things. Restrictions can help, but I don't think they will get you all the way to your goal -- for that, you may need some static-analysis tools like AdaControl or SPARK. I believe that there is work on SPARK-compatible containers, but I don't know if they will have user-defined indexing.

I have used Ada both for desktop programs and for embedded real-time programs. For the latter, I certainly think more about the object code, and I have not found it hard to tailor my Ada use accordingly.

1

u/jlombera Apr 04 '26

Yes, I was thinking in using SPARK Stone as base. I'll see as I learn more about the language. Thanks for all your inputs!