[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)