[HN Gopher] Ada is not just another programming language (1986)
       ___________________________________________________________________
        
       Ada is not just another programming language (1986)
        
       Author : kickitover
       Score  : 63 points
       Date   : 2021-10-28 07:57 UTC (2 days ago)
        
 (HTM) web link (sci-hub.se)
 (TXT) w3m dump (sci-hub.se)
        
       | transfire wrote:
       | Ada is just another programming language.
        
         | andi999 wrote:
         | Yes, but Spark is almost unique.
        
         | IshKebab wrote:
         | Maybe in the same way that every language is "just another
         | programming language". Ada clearly has unique features.
        
         | adrian_b wrote:
         | True, but nevertheless Ada is an important language in the
         | history of programming languages.
         | 
         | After 1970, there were less and less innovations in programming
         | languages, in the sense of features that have not existed in
         | any earlier languages.
         | 
         | Many new languages have been introduced since then and some of
         | them might be better than most previous languages, but usually
         | the new languages offer only new combinations of features that
         | have previously existed in different languages and not anything
         | really new.
         | 
         | Ada is important, because in 1979 it included a few features
         | never provided before. Some of those features have been
         | introduced only recently in more popular languages, while
         | others are still missing from most languages.
         | 
         | For anyone who wants to create or improve some programming
         | language, Ada is on a long list of mandatory programming
         | languages that must be understood well, before attempting to do
         | anything that is intended to be better. Sadly, there are many
         | examples of ugly misfeatures in recent programming languages,
         | which demonstrate that their authors were not aware about which
         | was the state of the art 40 years or 50 years ago, and they
         | solved again, but badly, problems that were solved well already
         | in the distant past.
         | 
         | Unfortunately Ada also had defects, some of which were mandated
         | by the Department of Defense requirements.
         | 
         | The defect that is most universally accepted is that it is too
         | verbose.
        
           | qPM9l3XJrF wrote:
           | >Some of those features have been introduced only recently in
           | more popular languages, while others are still missing from
           | most languages.
           | 
           | Can you give an example of an ADA feature missing from most
           | languages? I know ADA is supposed to be good for writing
           | reliable software, are there any important features related
           | to that which other languages could adopt?
        
             | adrian_b wrote:
             | A feature that for a long time was missing from most
             | languages, but which has been adopted by many during the
             | last decade, is to accept separator characters in numbers,
             | to improve the readability of long numerical constants.
             | 
             | Ada introduced this in 1979, by allowing "_" in numbers.
             | Cobol, in 1960, allowed hyphens in identifiers, for better
             | readability. Because hyphens can be confused with minus,
             | IBM PL/I, in 1964, replaced hyphen with low line, which
             | remains in use until today in most programming languages.
             | Ada extended the usage from identifiers to numbers. Most
             | languages have followed Ada and also use "_" for this
             | purpose, except C++ 2014, which based on a rationale that I
             | consider to be extremely wrong, has substituted the low
             | line with single quote.
             | 
             | While this is an example of an Ada feature that could be
             | easily adopted in any other language, other features are
             | more difficult to adopt without important changes in the
             | language, so they did not spread much.
             | 
             | An example is the specification of the procedure/function
             | parameters as being of 3 kinds, _in_ , _out_ and _inout_.
             | 
             | This feature was not invented by the Ada team, but by one
             | of the authors of the DoD IRONMAN language specifications,
             | maybe by David Fisher, but the DoD documents do not credit
             | any authors.
             | 
             | In the predecessor of Algol, IAL 1958, the procedure
             | parameters had to be specified as _in_ or _out_. However
             | this feature was dropped in ALGOL 60. Nevertheless, there
             | was a programming language, JOVIAL, which, unlike most
             | programming languages, was derived directly from IAL 1958,
             | and not from the later version, ALGOL 60.
             | 
             | So JOVIAL inherited the specification of parameters as _in_
             | or _out_. JOVIAL happened to be used in many DoD projects,
             | and because of this it influenced the initial versions of
             | the DoD requirements, which eventually resulted in Ada.
             | 
             | The first DoD requirements included the specification of
             | _in_ and _out_ parameters, but in the beginning the authors
             | did not have a good understanding about how the parameter
             | specification should be used, so the DoD requirements had a
             | bad wording, implying that this specification is meant to
             | determine whether the parameters shall be passed by value
             | or by reference.
             | 
             | After several revisions of the DoD requirements, in 1977,
             | the IRONMAN requirements were issued, which were very much
             | improved. By the time when IRONMAN was written, the authors
             | had realized that whether the parameters are passed by
             | value or by reference is an implementation detail that must
             | be decided by the compiler and which must be transparent
             | for the programmer.
             | 
             | Moreover, they realized that 3 categories must be
             | specified, i.e. _out_ and _inout_ must be distinct, because
             | the semantic is very different and the compiler must do
             | different actions to implement them correctly.
             | 
             | Many current programming languages are much more
             | complicated than necessary because they lack this 3-way
             | distinction of parameters.
             | 
             | The language most affected by this is C++, which has
             | struggled for 30 years, from 1980 until 2011, until it has
             | succeeded to include in the language the so called "move
             | semantics", to avoid redundant constructions and
             | destructions of temporaries. Even if now the extra
             | temporaries may be avoided, this requires a contorted
             | syntax.
             | 
             | All such problems could have been trivially avoided since
             | the beginning, if C++ had taken from Ada the "out" and
             | "inout" specifications. During the transition from C with
             | Classes to C++, in 1982-1984, C++ was nonetheless strongly
             | influenced by Ada in the introducing of overloaded
             | functions, overloaded operators and generic functions
             | (templates).
             | 
             | While C++ has introduced the reference parameters, to avoid
             | to write large quantities of "&" and "*", like in C, it
             | would have been much better to apply the Ada method, where
             | it is completely transparent whether the parameters are
             | passed by value or by reference and the programmers never
             | have to deal with "&", unless they use explicit pointers
             | and pointer arithmetic, wherever pointers are really needed
             | for their extra features, not for telling the compiler how
             | to do its job.
             | 
             | This purpose is as obsolete as the use of the keyword
             | "register" for telling the compiler where to allocate
             | variables. Even the C/C++ compilers ignore the fact that
             | the programmer writes that an input parameter shall be
             | passed by value and they pass it by reference anyway if the
             | parameter is too large. This should have been the rule for
             | any kind of parameters.
        
           | rezaprima wrote:
           | How verbose is it compared to others like Go or Rust ?
        
             | adrian_b wrote:
             | Somewhat more verbose.
             | 
             | A great part of the verbosity is due to the fact that
             | unlike CPL/BCPL/B/C and the languages inspired by them,
             | which have replaced the Algol statement parentheses _begin_
             | and _end_ with  "{" and "}" or similar symbols, Ada uses
             | relatively long words as statement parentheses, e.g. _loop_
             | and _end loop_.
             | 
             | On the other hand, a good feature of Ada is that it
             | followed Algol 68 in having different kinds of statement
             | parentheses for different program structures, so you do not
             | need to spend any time in wondering whether a closing "}"
             | matches the one opened by a "for" or by an "if", many lines
             | above.
        
               | Zababa wrote:
               | With good tooling, it might be possible to have
               | autocomplete once you write the b of begin or the l of
               | loop, which would reduce the typing verbosity.
        
               | adrian_b wrote:
               | Like autocompletion, also syntax coloring becomes more
               | important with verbose programming languages, to help
               | distinguish the relevant text between the large areas
               | occupied by keywords.
        
               | Zababa wrote:
               | That's a good point too.
        
               | Arch-TK wrote:
               | Honestly, I don't get why people care so much about
               | typing loop and end loop etc in their code. But after
               | using nim where I can just ignore the default style and
               | write everything in snake_case (which brings me joy as I
               | find camelCase harder to read and annoyingly ugly), I
               | think more language should be style agnostic (with tools
               | for converting between styles for others' reading
               | benefit). Ada could support curlies AND verbal curlies
               | allowing people who don't think that there is any benefit
               | in loop/end loop to just use {}.
        
               | adrian_b wrote:
               | Moreover, besides the long statement parentheses, the
               | other main source of verbosity in Ada is that Ada does
               | not use abbreviations.
               | 
               | Most programming languages use a set of abbreviations
               | that have appeared in either PL/I or Algol 68, but Ada
               | does not use them, for example Ada uses _constant,
               | procedure, character, integer_ instead of _const, proc,
               | char, int_.
        
               | Jtsummers wrote:
               | Even setting aside keywords, the real verbosity with Ada
               | is that nearly everything is explicit, not implicit. In C
               | you have many implicit conversions between (similar)
               | types, in Ada these are always explicit. In C++ you have
               | implicit instantiation of templates when they get used,
               | in Ada you must _explicitly_ instantiate a generic before
               | it 's used.
               | 
               | On the other hand, arrays carry their range information
               | with them and you don't need to pass that explicitly like
               | in C. And having types with explicit ranges means you can
               | use them and trust that they'll work correctly (which may
               | include erroring out when used incorrectly, like adding 1
               | to the largest value), but in most other languages you'd
               | have to include explicit range checks at (potentially)
               | numerous locations throughout the code (did we start with
               | a correct value, did we end with a correct value).
               | 
               | Tradeoffs.
        
               | adrian_b wrote:
               | You are right.
               | 
               | However the Department of Defense requirements prohibited
               | any kind of implicit conversions, without making any
               | distinction between safe conversions, which preserve the
               | value and which are reversible, and unsafe conversions,
               | like truncations or roundings or signed to unsigned
               | conversions.
               | 
               | The complete lack in Ada of some very frequently needed
               | implicit conversions is annoying and it does not decrease
               | the likelihood of bugs, but it increases the likelihood
               | of bugs due to code bloat that can obscure the erroneous
               | absence of some meaningful operation.
               | 
               | However, this defect is on DoD, not on the Ada authors.
        
           | thesuperbigfrog wrote:
           | >> The defect that is most universally accepted is that it is
           | too verbose.
           | 
           | Another huge barrier (especially to early adoption) was the
           | cost of Ada toolchains.
           | 
           | Even today, there are proprietary Ada implementations that
           | cost thousands of dollars per seat.
        
             | Jtsummers wrote:
             | There are also C and C++ toolchains that cost similar
             | amounts (if you want to use them for safety critical
             | systems). But they do have more free or open source options
             | than Ada does. Fortunately FSF GNAT is free and
             | unencumbered (unlike AdaCore's release of GNAT GPL).
        
               | CRConrad wrote:
               | > But they do have more free or open source options than
               | Ada does. Fortunately FSF GNAT is free and unencumbered
               | (unlike AdaCore's release of GNAT GPL).
               | 
               | Sorry, I don't quite get what you're trying to say here.
               | You mean unencumbered by being free or open source?
        
               | Jtsummers wrote:
               | GNAT GPL removes the runtime exception, so if you build
               | something with it linked to its standard library, it's
               | also supposed to be open sourced. This means you can't
               | (in a legal/technical sense, not a true prohibitive
               | sense) make closed source software with it. FSF GNAT
               | doesn't remove that exception, so it can be used in
               | releasing closed source software.
               | 
               | That's the encumbrance that GNAT GPL imposes and FSF GNAT
               | does not.
        
       | Cloudef wrote:
       | I like how in ada you can specify custom range integers
        
         | riffraff wrote:
         | other than "older" languages in the Pascal family, there is an
         | extended "subset" feature in Raku[0], which is pretty cool.
         | 
         | For number ranges you would say                   subset
         | HandCountable of Int where 1 <= * <= 5
         | 
         | [0] https://ohmycloudy.github.io/24.html
        
         | wk_end wrote:
         | I've always wondered - does Ada track or enforce these ranges?
         | 
         | Like, if I have a variable `i` in range 0...10 and write the
         | Ada equivalent of `i++`, does Ada know that from there on out
         | `i` is in range 1...11? Something like TypeScript's type
         | narrowing?
        
           | Cloudef wrote:
           | Yes, it's enforced by any _runtime_ operation. See: https://w
           | ww.adaic.org/resources/add_content/standards/05rm/h...
        
           | Jtsummers wrote:
           | The range wouldn't change in Ada. The type for a variable is
           | fixed at compile time. It will ensure (at runtime and
           | partially at compile time) that the value doesn't go outside
           | the range, though.
        
           | throwaway81523 wrote:
           | Usually with runtime checks, but it can also in some
           | situations be done statically, such as with SPARK.
        
         | tasty_freeze wrote:
         | Pascal had subrange types before Ada, not only for integers but
         | characters too.                   var day : 1 .. 31;
         | letter : 'A' .. 'Z';
         | 
         | And you could specify ranges on array subscripts as well:
         | var weight : array[-5 .. 5] of integer;
        
           | andi999 wrote:
           | Now let's say your name includes one of these weird 'A'
           | characters...
        
           | adrian_b wrote:
           | Yes, but Ada extended the number of usable types for ranges,
           | e.g. including fixed-point numbers.
           | 
           | All those that existed in Pascal also exist in Ada.
        
           | mseepgood wrote:
           | Wirth removed this again in Oberon, because experience with
           | Pascal and Modula showed that it is not worth it.
        
             | open-source-ux wrote:
             | That's very interesting. Subranges is a feature that I have
             | always liked in Pascal and other languages.
             | 
             | You do have any more detail about the reasoning why Wirth
             | thought this feature was "not worth it" for Oberon? Were
             | programmers not using this feature in Pascal and Modula-2?
             | Did Wirth consider it more noise or complexity in those
             | languages?
        
               | [deleted]
        
               | tored wrote:
               | Found this paper "From Modula to Oberon" by Wirth himself
               | 
               | http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.
               | 578...
               | 
               | "Subrange types were introduced in Pascal (and adopted in
               | Modula) for two reasons: (1) to indicate that a variable
               | accepts a limited range of values of the base type and to
               | allow a compiler to generate appropriate guards for
               | assignments, and (2) to allow a compiler to allocate the
               | minimal storage space needed to store values of the
               | indicated subrange. This appeared desirable in connection
               | with packed records. Very few implementations have taken
               | advantage of this space saving facility, because the
               | additional compiler complexity is very considerable.
               | Reason 1 alone, however, did not appear to provide
               | sufficient justification to retain the subrange facility
               | in Oberon."
               | 
               | "... was the observation that in a growing number of
               | programs the indiscriminate use of enumerations (and
               | subranges) had led to a type explosion that contributed
               | not to program clarity but rather to verbosity."
               | 
               | Instead the proposed solution is to use SET.
               | 
               | "With the absence of enumeration and subrange types, the
               | general possibility of defining set types based on given
               | element types appeared as redundant. Instead, a single,
               | basic type SET is introduced, whose values are sets of
               | integers from 0 to an implementation-defined maximum."
        
               | open-source-ux wrote:
               | Thank you :-)
               | 
               | It seems subranges could be something of a double-edged
               | sword. Too many enumerations and subranges in a program
               | adds complexity. However, without them I presume the
               | guards need to be coded manually elsewhere in the
               | program.
               | 
               | It's really fascinating to see the reasoning a
               | programming language designer makes when choosing what
               | feature to include - or exclude.
        
               | tored wrote:
               | > without them I presume the guards need to be coded
               | manually elsewhere in the program.
               | 
               | That is my conclusion as well, reading the Oberon manual
               | a SET seems just to be a normal set but for integers
               | only, thus you have to manually check if your integer
               | value is part of the set within the procedure itself,
               | however that check will be a runtime check, not a compile
               | time check if you had a proper enumeration type (I
               | assume). And to my understanding Oberon doesn't have any
               | error handling, so how exactly you would promote a out of
               | range check to an error is unknown to me.
               | 
               | I guess that you would probably want to define constants
               | to fill the set with, thus adding some more noise.
               | CONST RED = 1;       CONST GREEN = 2;       CONST BLUE =
               | 3;       SET COLORS = (RED, GREEN, BLUE)
               | 
               | So you can use it a procedure call
               | draw(RED);
               | 
               | Compare to Pascal enumeration                 type COLORS
               | = (RED, GREEN, BLUE);
               | 
               | It feels like Wirth was somewhat obsessed with the idea
               | of type extension with Oberon, it should be possible to
               | import any module (program) and extend it without
               | restrictions and enumerations created a problem how you
               | would extend it.
               | 
               | If you have a color module defining the enumeration
               | COLORS together with a bunch of procedures accepting
               | COLORS, then in another custom module you want extend
               | COLORS with the color YELLOW plus some YELLOW specific
               | procedures.
               | 
               | But if you pass an extended enumeration E' to a procedure
               | that accepts the base enumeration E, which should be
               | legal similar how you can pass T' as T, the procedure
               | would receive illegal values, in this case YELLOW. What
               | you need to do instead is create your own CUSTOM_COLORS
               | enumeration, manually include every color from COLORS and
               | add YELLOW, and when calling procedures within the colors
               | module type cast from CUSTOM_COLORS to COLORS
               | enumeration. Perhaps this is the type explosion Wirth was
               | referring to.
               | 
               | Out of range would still be problem if you extend a SET,
               | but you avoid type casts.
               | 
               | This is how I interpret Wirth reluctance to enumerations
               | (and subranges).
               | 
               | https://www.inf.ethz.ch/personal/wirth/Oberon/Oberon07.Re
               | por...
        
             | vrotaru wrote:
             | Not sure that is the actual reason. (Also define worth it)
             | 
             | Wirth had developed that original, but misguided (IMO)
             | notion that the faster a compiler can compile itself the
             | better it is.
             | 
             | Consequently he has removed a lot from latest iterations of
             | its languages/compilers
             | 
             | Pascal had an enum-like feature we could define an
             | enumerated type.
             | 
             | Wirth removed it because... `CONST` should be enough for
             | everyone.
             | 
             | Obviously it has simplified the compiler and increased the
             | self-compilation speed. But I would not call that an
             | improvement.
        
               | tored wrote:
               | If you read the paper, From Modula to Oberon by Wirth, I
               | already linked in a pervious comment when answering the
               | question about subranges, you can also find the reasoning
               | behind the removal of enumerations.
               | 
               | "Enumeration types appear to be a simple enough feature
               | to be uncontroversial. However, they defy extensibility
               | over module boundaries. Either a facility to extend given
               | enumeration types has to be introduced, or they have to
               | be dropped. A reason in favour of the latter, radical
               | solution was the observation that in a growing number of
               | programs the indiscriminate use of enumerations(and
               | subranges) had led to a type explosion that contributed
               | not to program clarity but rather to verbosity. In
               | connection with import and export, enumerations give rise
               | to the exceptional rule that the import of a type
               | identifier also causes the (automatic) import of all
               | associated constant identifiers. This exceptional rule
               | defies conceptual simplicity and causes unpleasant
               | problems for the implementor."
               | 
               | http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.
               | 578...
        
               | mananaysiempre wrote:
               | I'm not sure this was the reasoning. None of the
               | languages in the direct Algol heritage have any sort of
               | parametric polymorphism, including for range bounds, so
               | working with arrays (which were, at least in Pascal, the
               | primary application of range types) was either constant
               | and repetitive fighting with the compiler or unsafe
               | escape hatches all the way. (Usually both.) I believed
               | this was the primary motivation for the removal of
               | ranges.
               | 
               | (Of course, it's literally _impossible_ to make
               | polymorphic range bounds work completely, due to the
               | undecidability of Peano arithmetic. The most convincing
               | attempt I've seen that doesn't just go full dependent
               | types on you is ATS, and even that is not exactly the
               | friendliest of environments.)
               | 
               | Another system whose evolution was explicitly guided by
               | self-compilation speed is Chez Scheme, and it's a fine
               | one. Generally it seems to me that it's a valid
               | optimization principle, but not a global one: you can
               | fall into an unfortunate local minimum if you start in
               | the wrong place. ... Well, so what, it's not like there
               | are any infallible design principles in programming.
        
           | elcritch wrote:
           | Nim borrows from both. It's nice using it for embedded work:
           | proc set_mode(mode: range[0..3]) ## SPI mode (0-3)
        
           | Cloudef wrote:
           | Ah yes, it's been a while since I've touched pascal.. Good
           | times
        
       | kickitover wrote:
       | A technical and non-technical article on the development of the
       | Ada programming language.
        
         | Taniwha wrote:
         | Well it's essentially a PR piece, says lots of reasons why Ada
         | is better than everything without actually showing any concrete
         | examples
        
           | gigatexal wrote:
           | The Wikipedia article has some good stuff here:
           | https://en.m.wikipedia.org/wiki/Ada_(programming_language)
        
       | inamberclad wrote:
       | Ada has every feature you could ever want to express programmatic
       | intent.
        
       | hoyd wrote:
       | Ada was the programming language used when I took computing
       | science in Glasgow, Scotland in 2002.
        
         | sambeau wrote:
         | It was Pascal, Haskell* and C back in the 1990s.
         | 
         | * and variants of Haskell, e.g. Gofer
        
         | naltun wrote:
         | Fyt like the day in Glasgow?
        
         | iamevn wrote:
         | Western Washington University used it for intro CS classes
         | until about 8 years ago. They switched to doing the professor's
         | choice between Java and Python which most people seem to prefer
         | now. Some of the professors do still use it for classes on
         | concurrency and proofs.
         | 
         | I really appreciated the sort of errors the compiler gives you
         | but remember struggling to find good beginner level
         | documentation. I kept landing on more specification-style docs
         | which were more confusing than helpful. Also diving straight
         | into Java after Ada was a shock.
        
       | tombert wrote:
       | Ada is a language that has been on my "todo list" of languages
       | for awhile (just after FORTH). I generally hate this term, but
       | Ada does kind of look like a language that was "ahead of its
       | time", specifically in regards to concurrency.
        
         | adrian_b wrote:
         | While studying how concurrency is done in Ada is certainly
         | instructive and even today many languages and multi-threading
         | libraries have more poor support for concurrent programming
         | than Ada had since the beginning, a language that was really
         | ahead of its time regarding concurrency was IBM PL/I.
         | 
         | 15 years before Ada, in 1964, IBM PL/I had facilities for
         | multitasking that e.g. included a _wait_ function that could do
         | everything that can be done with _WaitForMultipleObjects /
         | WaitForSingleObject_. The POSIX threads suck because they lack
         | such a powerful _wait_ function and many other multi-threading
         | libraries, e.g. the C++ standard library, are forced to offer
         | only what is available everywhere, so they do not have anything
         | that is missing in the POSIX threads.
        
           | gpderetta wrote:
           | Any kernel based wmo is bot going to work well for fastpathed
           | primitives. For example on windows you can't wmo for critical
           | sections or keyed events.
           | 
           | But you can implement an pure userspace or hibrid user/kernel
           | wmo even on top of something like unix poll just fine, so
           | saying that the standard lacks it because of POSIX is wrong.
        
             | adrian_b wrote:
             | The UNIX _wait_ system call, introduced in 1970 or 1971,
             | after porting UNIX to PDP-11, provided a subset of the
             | features of PL /I _wait_ , e.g. it allowed waiting until
             | _any_ of the children of a process terminates.
             | 
             | So UNIX had very early some kinds of waiting for multiple
             | events. A decade later, various other waiting functions,
             | e.g. _select_ and _poll_ were introduced, for networking.
             | 
             | I did not say anything about UNIX processes, but about the
             | standard POSIX threads, the normal way to use multiple
             | threads in a single process under UNIX-compatible operating
             | systems. For example, with pthreads, you can _join_ only a
             | single thread. You can _join_ all threads in an inefficient
             | way, joining them one-by-one, but there is no way to _join_
             | the first thread that happens to terminate, which is
             | actually the most frequent thing that you want to do.
             | 
             | You can achieve this in a convoluted and inefficient way,
             | using various forms of communication between threads, but
             | this is a very basic feature that should have existed in
             | the standard.
             | 
             | Taking into account that various methods of waiting for
             | multiple events had existed for decades in UNIX, it is even
             | more baffling that this was omitted in the POSIX threads
             | standard. Like I have said, this has also constrained the
             | later standards, e.g. the C++ standard.
        
       ___________________________________________________________________
       (page generated 2021-10-30 23:01 UTC)