diff --git a/ada.html.markdown b/ada.html.markdown new file mode 100644 index 00000000..a06792b3 --- /dev/null +++ b/ada.html.markdown @@ -0,0 +1,416 @@ +--- +language: Ada +filename: learn.ada +contributors: + ["Luke A. Guest", "https://github.com/Lucretia"] + ["Fernando Oleo Blanco", "https://github.com/Irvise"] + ["Fabien Chouteau", "https://github.com/Fabien-Chouteau"] + ["Manuel", "https://github.com/mgrojo"] +--- + +Ada is a strong statically typed imperative, [object-oriented](https://ada-lang.io/docs/arm/AA-3/AA-3.9), [real-time](https://ada-lang.io/docs/arm/AA-D), [parallel](https://ada-lang.io/docs/arm/AA-9) and [distributed](https://ada-lang.io/docs/arm/AA-9) programming language from the Pascal/Algol family of languages, but nowadays, it only has a passing resemblance to Pascal, with the only remnants left being the ```begin/end``` keyword pair, the ```:=``` assignment symbol, records and ```if/case``` control statement structures. + +Ada was originally designed to be an [object-based](https://ada-lang.io/docs/arm/AA-3/AA-3.3) language and to replace 100's of languages in use by the US government. This means that all entities are objects, not in the object-oriented sense. The language became [Object-Oriented](https://ada-lang.io/docs/arm/AA-3/AA-3.9) in 1995, and added [interfaces](https://ada-lang.io/docs/arm/AA-3/AA-3.9#Subclause_3.9.4) derived from Java in 2005. [Contract based](https://ada-lang.io/docs/arm/AA-13/AA-13.1#Subclause_13.1.1) programming was introduced with Ada 2012. + +Ada was designed to be easy to read and learn, even for non-programmers, e.g. management within an organisation, therefore programs written in the language tend to be a bit more verbose. + +Ada is a modern programming language, and now has a package manager like other modern languages, Alire, see below. + +```ada +-- Comments are written with a double hyphen and exist until the end of +-- the line. + +-- You do not need to call the entry point "Main" or "main," you should +-- name it based on what the program does. +procedure Empty is + -- This is a declarative part. +begin + -- Statements go here. + null; -- Do nothing here. +end Empty; + +-- Ada compilers accept compilation units which can be library packages, +-- tasks, sub-programs, generics, etc. + +-- This is where "context clauses" go, these can be pragmas or "with" +-- statements. "with" is equivalent to "include" or "import" in other +-- languages. +with Ada.Text_IO; -- Get access to a library package. + +procedure Hello is +begin + Ada.Text_IO.Put_Line ("Hello, world"); + + Ada.Text_IO.Put ("Hello again, world"); + Ada.Text_IO.New_Line; +end Hello; + + +-- Ada has a real module system. Modules are called packages and are split into +-- two component parts, the specification and a body. +-- It is important to introduce packages early, as you will be using them from +-- the start. +package Stuff is + -- We could add the following line in order to tell the compiler that this + -- package does not have to run any code before the "main" procedure starts. + -- pragma Preelaborate; + + -- Packages can be nested within the same file or externally. + -- Nested packages are accessed via dot notation, e.g. Stuff.Things.My. + package Things is + My : constant Integer := 100; + end Things; + + -- If there are sub-programs declared within the specification, the body + -- of the sub-program must be declared within the package body. + procedure Do_Something; -- If a subprogram takes no parameters, empty + -- parentheses are not required, unlike other + -- languages. + + -- We can also make generic sub-programs. + generic + type Element is (<>); -- The "(<>)" notation specifies that only + -- discrete types can be passed into the generic. + procedure Swap (Left, Right : in out Element); + + -- Sometimes we want to hide how a type is defined from the outside world + -- so that nobody can mess with it directly. The full type must be defined + -- within the private section below. + type Blobs is private; + + -- We can also make types "limited" by putting this keyword after the "is" + -- keyword, this means that the user cannot copy objects of that type + -- around, like they normally could. +private + type Blobs is new Integer range -25 .. 25; +end Stuff; + + +package body Stuff is + -- Sub-program body. + procedure Do_Something is + -- We can nest sub-programs too. + -- Parameters are defined with the direction of travel, in, in out, out. + -- If the direction of travel is not specified, they are in by default. + function Times_4 (Value : in Integer) return Integer is + begin + return Value * 4; + end Times_4; + + I : Integer := 4; + begin + I := Times_4 (I); + end Do_Something; + + + -- Generic procedure body. + procedure Swap (Left, Right : in out Element) is + Temp : Element := Left; + begin + Left := Right; + Right := Temp; + end Swap; +begin + -- If we need to initialise something within the package, we can do it + -- here. + Do_Something; +end Stuff; + + +with Ada.Unchecked_Conversion; +with Ada.Text_IO; +with Stuff; + +procedure LearnAdaInY is + -- Indentation is 3 spaces. + + -- The most important feature in Ada is the type. Objects have types and an + -- object of one type cannot be assigned to an object of another type. + + -- You can, and should, define your own types for the domain you are + -- modelling. But you can use the standard types to start with and then + -- replace them later with your own types, this could be called a form of + -- gradual typing. + + -- The standard types would only really be a good starting point for binding + -- to other languages, like C. Ada is the only language with a standardised + -- way to bind with C, Fortran and COBOL! See the links in the References + -- section with more information on binding to these languages. + + type Degrees is range 0 .. 360; -- This is a type. Its underlying + -- representation is an Integer. + + type Hues is (Red, Green, Blue, Purple, Yellow); -- So is this. Here, we + -- are declaring an + -- Enumeration. + + -- This is a modular type. They behave like Integers that automatically + -- wrap around. In this specific case, the range would be 0 .. 359. + -- If we added 1 to a variable containing the value 359, we would receive + -- back 0. They are very useful for arrays. + type Degrees_Wrap is mod 360; + + -- You can restrict a type's range using a subtype, this makes them + -- compatible with each other, i.e. the subtype can be assigned to an + -- object of the type, as can be seen below. + subtype Primaries is Hues range Red .. Blue; -- This is a range. + + -- You can define variables or constants like this: + -- Var_Name : Type := Value; + + -- 10 is a universal integer. These universal numerics can be used with + -- any type which matches the base type. + Angle : Degrees := 10; + Value : Integer := 20; + -- New_Angle : Degrees := Value; -- Incompatible types won't compile. + -- New_Value : Integer := Angle; + + Blue_Hue : Primaries := Blue; -- A variable. + Red_Hue : constant Primaries := Red; -- A constant. + Yellow_Hue : constant Hues := Yellow; + Colour_1 : constant Hues := Red_Hue; + -- Colour_2 : constant Primaries := Yellow_Hue; -- uncomment to compile. + + -- You can force conversions, but then you are warned by the name of the + -- package that you may be doing something unsafe. + function Degrees_To_Int is new Ada.Unchecked_Conversion + (Source => Degrees, -- Line continuations are indented by 2 spaces. + Target => Integer); + + New_Value_2 : Integer := Degrees_To_Int (Angle); -- Note, space before (. + + -- GNAT is the GNU Ada Translator (compiler). + -- Ada has a style guide and GNAT will warn you to adhere to it, and has + -- option to check your style so that you can correct it so that all Ada + -- source looks consistent. However, the style can be customized. + + -- Yes, you can even define your own floating and fixed point types, this + -- is a very rare and unique ability. "digits" refers to the minimum + -- digit precision that the type should support. "delta" is for fixed + -- point types and refers to the smallest change that the type will support. + type Real_Angles is digits 3 range 0.0 .. 360.0; + type Fixed_Angles is delta 0.01 digits 5 range 0.0 .. 360.0; + + RA : constant Real_Angles := 36.45; + FA : constant Fixed_Angles := 360.0; -- ".0" in order to make it a Float. + + -- You can have normal Latin 1 based strings by default. + Str : constant String := "This is a constant string"; + -- When initialising from a string literal, the compiler knows the bounds, + -- so we don't have to define them. + + -- Strings are arrays. Note how parentheses are used to access elements of + -- an array? This is mathematical notation and was used because square + -- brackets were not available on all keyboards at the time Ada was + -- created. Also, because an array can be seen as a function from a + -- mathematical perspective, so it made converting between arrays and + -- functions easier. + Char : constant Character := Str (Str'First); -- "'First" is a type + -- attribute. + + -- Ada 2022 includes the use of [] for array initialisation when using + -- containers, which were added in Ada 2012. + + -- Arrays are usually always defined as a type. + -- They can be any dimension. + type My_Array_1 is array (1 .. 4, 3 .. 7, -20 .. 20) of Integer; + + -- Yes, unlike other languages, you can index arrays with other discrete + -- types such as enumerations and modular types or arbitrary ranges. + type Axes is (X, Y, Z); + + -- You can define the array's range using the 'Range attribute from + -- another type. + type Vector is array (Axes'Range) of Float; + + V1 : constant Vector := (0.0, 0.0, 1.0); + + -- A record is the same as a structure in C, C++. + type Entities is record + Name : String (1 .. 10); -- Always starts at a positive value, + -- inclusive range. + Position : Vector; + end record; + + -- In Ada, array bounds are immutable. You therefore have to provide a + -- string literal with a value for every character. + E1 : constant Entities := ("Blob ", (0.0, 0.0, 0.0)); + + -- An alternative is to use an array aggregate and assign a default value + -- to every element that wasn't previously assigned in this aggregate. + -- "others" is used to indicate anything else that has not been + -- explicitly initialized. + E2 : constant Entities := (('B', 'l', 'o', 'b', others => ' '), + (0.0, 0.0, 0.0)); + + -- There are dynamic length strings (see references section) available in + -- the standard library. + + -- We can make an object be initialised to its default values with the box + -- notation, "<>". "others" is used to indicate anything else that has not + -- been explicitly initialized. + Null_Entity : constant Entities := (others => <>); + + -- Object-orientation is accomplished via an extension of record syntax, + -- tagged records, see link above in first paragraph. + + -- We can rename objects (aliases) to make readability a bit better. + package IO renames Ada.Text_IO; +begin + -- We can output enumerations as names. + IO.Put_Line ("Blue_Hue = " & -- & is the string concatenation operator. + Blue'Image); -- ' accesses attributes on objects. + -- The Image attribute converts a value to a string. + -- Ada 2022 has extended Image to custom types too. + -- Access this with -gnat2022 compiler flag. + IO.Put_Line ("Yellow_Hue = " & + -- We can use the type's attribute. + Primaries'Image (Yellow_Hue)); + + -- We can define local variables within a declare block, this can be made + -- more readable by giving it a label. + Enum_IO : declare + package Hue_IO is new IO.Enumeration_IO (Hues); + + -- Using a package makes everything inside that package visible within + -- this block, it is good practice to only do this locally and not on + -- a whole package within the context clause. + use Hue_IO; + begin + -- We can print out the enumeration values too. + Put (Purple); -- Note we don't have to prefix the Put procedure with + -- Hue_IO. + IO.New_Line; -- We still need to prefix with IO here. + Put (Red_Hue); + IO.New_Line; + end Enum_IO; + + -- Loops have a consistent form. "
loop ... end loop". + -- Where "form" can be "while" or "for" or missing as below, if + -- you place the "loop ... end loop;" construct on their own lines, + -- you can comment out or experiment with different loop constructs more + -- easily. + declare + Counter : Positive := Positive'First; -- This is 1. + begin + -- We can label loops so we can exit from them more easily if we need to. + Infinite : + loop + IO.Put_Line ("[Infinite loop] Counter = " & Counter'Image); + + Counter := Counter + 1; + + -- This next line implements a repeat ... until or do ... while loop construct. + -- Comment it out for an infinite loop. + exit Infinite when Counter = 5; -- Equality tests use a single "=". + end loop Infinite; -- Useful when implementing state machines. + end; + + declare -- We don't have to have a label. + Counter : Positive := Positive'First; -- This is 1. + begin + while Counter < 10 + loop + IO.Put_Line ("Counter = " & Counter'Image); + + Counter := Counter + 1; -- There is no explicit inc/decrement. + + -- Ada 2022 introduced @ for LHS, so the above would be written as + -- Counter := @ + 1; -- Try it, -gnat2022. + end loop; + end; + + declare + package Hue_IO is new IO.Enumeration_IO (Hues); + + -- We can have multiple packages on one line, but I tend to use one + -- package per line for readability. + use IO, Hue_IO; + begin + Put ("Hues : "); -- Note, no prefix. + + -- Because we are using the 'Range attribute, the compiler knows it is + -- safe and can omit run-time checks here. + for Hue in Hues'Range + loop + Put (Hue); + + -- Types and objects know about their bounds, their First .. Last + -- values. These can be specified as range types. + if Hue /= Hues'Last then -- The /= means "not equal to" like the + -- maths symbol ≠. + Put (", "); + end if; + end loop; + + IO.New_Line; + end; + + -- All objects know their bounds, including strings. + declare + C : Character := Str (50); -- Warning caused and exception raised at + -- runtime. + -- The exception raised above can only be handled by an outer scope, + -- see wikibook link below. + begin + null; -- We will never get to this point because of the above. + end; +exception + when Constraint_Error => + IO.Put_Line ("Caught the exception"); +end LearnAdaInY; +``` + +Now, that's a lot of information for a basic intro to Ada, and I've only touched the surface, there's much more to look at in the references section below. I haven't even touched on dynamic memory allocation which includes [pools](https://ada-lang.io/docs/arm/AA-13/AA-13.11), this is because for the most part, Ada programs don't need it, you can do a lot without it. + +As I stated above, Ada barely looks like Pascal and if you look at the original [Green specification](https://apps.dtic.mil/sti/trecms/pdf/ADB950587.pdf) (Warning: Huge 4575 page scanned PDF - starting on page 460), it looks nothing like it at all (page 505 of that PDF). + +The above source code will compile, but also will give warnings showing the power of the strong static type system. + +## Download this source + +If you already have the GNAT toolchain installed, you can cut and paste the above into a new file, e.g. ```learn-ada-in-y.ada``` and then run the following: + +```bash +$ gnatchop learn-ada-in-y.ada # This breaks the program into its specification ".ads" and body ".adb". +$ gnatmake empty.adb # gnatmake takes care of compilation of all units and linking. +$ gnatmake hello.adb +$ gnatmake learnadainy.adb +``` + +Or, download [Alire](https://alire.ada.dev), copy it to somewhere in your PATH and then do the following: + +**N.B.** Alire will automatically install the toolchain for you if you don't have one installed and will ask you to select which you want to use. + +```bash +$ alr search learnadainy +$ alr get learnadainy +$ cd learnadainy +$ alr run empty +$ alr run hello +$ alr run learnadainy +``` + +## Further Reading + +* [Ada Programming Language](https://ada-lang.io) +* [Ada 2022 Reference Manual](https://ada-lang.io/docs/arm) +* [Ada Style Guide](https://ada-lang.io/docs/style-guide/Ada_Style_Guide) +* [Learn more Ada/Spark at AdaCore's site](https://learn.adacore.com) + +## References from the source above + +1. [wikibook](https://en.wikibooks.org/wiki/Ada_Programming/Exceptions#Exception_handlers) +2. [C](https://ada-lang.io/docs/arm/AA-B/AA-B.3) +3. [Fortran](https://ada-lang.io/docs/arm/AA-B/AA-B.5/) +4. [COBOL](https://ada-lang.io/docs/arm/AA-B/AA-B.4/) +5. [dynamic length strings](https://ada-lang.io/docs/arm/AA-A/AA-A.4#Subclause_A.4.5) + +### Multi-line comments + +Multi-line comments are not allowed as they are error prone. + +> Such comments would require a closing comment delimiter and this would again raise the dangers associated with the (unintentional) omission of the closing delimiter: entire sections of a program could be ignored by the compiler without the programmer realizing it +> +> [Ada 83 Rationale](http://archive.adaic.com/standards/83rat/html/ratl-02-01.html#2.1) +