mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-23 17:41:41 +00:00
[language/en] Add ada (#4821)
* Add initial Ada docs. * Change wording. * Update Empty. * Remove old comments which have been added to the code. Have one code block now. * Update source. * Add bash to the code block so I get syntax colouring in vscode. * Add extra on context clauses. * Update source. * Add loops. * Add a warning about the source. * Update source. * Add real-time to the description. * Add info on aspects/contracts. * Add links to RM. * Add string/character/array. * Update source. * Add new package. * Add extra info on what's left from Pascal. * Add fixed/floats. * Add link to the RM. Change wording. * Add distributed with link. * Fix typo. * Add a statement on package use. * Add extra info re the warnings. * Add more context re Pascal. * Separate paragraphs. * More clarification. * Fix typo. * Change aspect-oriented to contract-based. * Add about having to download the gnat toolchain. * Rejig paragraph. * Add the extra run commands. * Add Fer's changes. * Fix typo. * Remove extraneous ---, don't know how that got there. * Fix filename. * Remove extra comment. * Remove another empty comment. * Add back in the generic Swap which was removed for some reason. * Correction on style. GNAT definition added. * Fix definition of starting index of strings. * Add extra context and examples for String initialisation. * Remove line to install the toolchain. Add note about this. * Add https://learn.adacore.com as a link. * Add Fabien's contributor link for the extra context added in the previous commits. * Fix typos. Add better explanations. * Add info on limited types. * Fix typos. * Add explanation of the generic parameter. * Add a location of where I referenced OOP. * Fix text. * Remove markdown from comments. * Remove comma.
This commit is contained in:
parent
a57c72103d
commit
bfee8bccc6
416
ada.html.markdown
Normal file
416
ada.html.markdown
Normal file
@ -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. "<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)
|
||||
|
Loading…
Reference in New Issue
Block a user