To facilitate the creation and management of separate code files for each example, we will set up the project
and use gprbuild
instead of the gnatmake
compiler. Here I will create a folder called learn-ada
in Documents
with the following structure:
1 2 3 4 5 6 | learn-ada ├── learn_ada.gpr ├── obj └── src └── main.adb |
The learn_ada.gpr
file is a declaration like the package.json
of NodeJS
-based project
, but has a much simpler structure:
1 2 3 4 5 6 7 8 9 10 11 12 | project Learn_Ada is for Languages use ("ada", "c"); for Source_Dirs use ("src/**"); for Main use ("main.adb"); -- for Library_Dir use "lib"; -- for Library_Name use "compiled_pkg"; -- for Library_Kind use "Dynamic"; for Object_Dir use "obj"; end Learn_Ada; |
- We have languages that can be used in the
project
ada
andc
. - All directories containing the code that we write will be placed in the
src
directory. - The program will start from the
main.adb
file located at the first level right in thesrc
directory. - The example
comment
lines for declaring additional use of a library that we write compiled into executables, include: directory name, library name, compiled library type calledDynamic
. - The directory containing the executables after compilation is complete is
obj
.
Now we need to copy/paste
the code of the Hello World
program:
1 2 3 4 5 6 7 8 9 | with Ada.Text_IO; use Ada.Text_IO; procedure Main is -- khu vực khai báo các tham số và các biến begin -- in "Hello, Ada !" ra cửa sổ dòng lệnh Put_Line ("Hello, Ada !"); end Main; |
In the command line, navigate to the working directory of Documents/learn-ada
.
1 2 | cd Documents && cd learn-ada |
Then run the compile command using the gprbuild
project manager and continue to run the main
executable generated by gprbuild
in the obj
directory.
1 2 3 | gprbuild -q -P learn_ada.gpr objmain |
1 2 3 | gprbuild -q -P learn_ada.gpr obj/main |
Running the compile command and the main
file will stay this way because we’ve set up the gpr
file to automatically find all the code files in the src
directory. In the examples from here on, I will only copy/paste
the result of running the main
file to reduce unnecessary iterations. And now we’ll go through all the common imperative
syntaxes.
Declare variable
The beginning is the operation of variable declaration and value assignment. We have variable names named in the form of sub-program
and package
, with the first letter of each word capitalized and words joined by an underscore _
.
Ada
‘s variable data type syntax is a descriptor suffix similar to Scala
, TypeScript
, Kotlin
, etc.. The variable name is followed by : Tên_Kiểu_Dữ_Liệu
. And the assignment operation uses the :=
notation like SQL
instead of the =
notation like most other languages.
1 2 3 4 5 6 7 8 9 10 11 12 | with Ada.Text_IO; use Ada.Text_IO; procedure Main is N : Integer; begin N := 0; Put_Line ("N is" & Integer'Image (N)); -- update value N := N + 1; Put_Line ("Now is" & Integer'Image (N)); end Main; |
1 2 3 | N is 0 Now is 1 |
Since we haven’t touched the standard libraries yet, we’ll keep in mind that the string concatenation is &
. Accompanied by the operation to convert integer N
to string type is Integer'Image (N)
. Compared to C
, the variable declaration part is defined by Ada
in its own area by the structure of the syntax. When writing programs in C
, the habit of good dev
to pass on is to focus on declaring in the first lines of sub-program
.
If.. Then.. Else
Ada
‘s serial if .. else
syntax is also very familiar compared to other Imperative
languages. Here we have the word then
used to end the conditional expression and in the next part else if
is written as elsif
phonetically.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Main is N : Integer; begin Put ("Enter : "); Get (N); if N = 0 or N = 360 then Put_Line ("Due North"); elsif N in 1 .. 89 then Put_Line ("North-East"); elsif N = 90 then Put_Line ("Due East"); elsif N in 91 .. 179 then Put_Line ("South-East"); elsif N = 180 then Put_Line ("Due South"); elsif N in 181 .. 269 then Put_Line ("South-West"); elsif N = 270 then Put_Line ("Due West"); elsif N in 271 .. 359 then Put_Line ("North-West"); else Put_Line ("Not in Range"); end if; end Main; |
By the way, we learned more about the Put (String)
unbroken string printing operation and the Get (N)
operation to read the user input and write to the N
variable. Conditional tests used in the example include:
- Check for equivalence value
=
. - The
or
keyword is equivalent to the symbol||
inC
andJavaScript
that we already know. - The
in
test looks for an element that belongs to a certain set of values.
1 2 3 | Enter : 0 Due North |
Indeed, in terms of high-level programming interface criteria, Ada
is much more user-friendly than C
If you notice, Ada
‘s built-in procedures all have very clear and complete names, not abbreviations like sub-program
in the C
standard library. For example, C
‘s any type-to-integer converter is named atoi()
– if fully understood, any_to_integer
.
The story is that the C
compiler will not automatically optimize the source files we write. That’s why when C
was originally designed to communicate at a contiguous level with the resources of low-level programming
systems, people always tried to minimize identifier names in the manipulation of naming variables and sub-program
. Perhaps that’s why C
is powerful, but using C
for general applications is very difficult compared to high-level programming languages. And Ada
, was probably made to perfect C
in this respect.
Case .. When
Instead of switch .. case
we have case .. when
which is very similar to SQL
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Main is N : Integer; begin Put ("Enter : "); Get (N); case N is when 0 | 360 => Put_Line ("Due North"); when 1 .. 89 => Put_Line ("North-East"); when 90 => Put_Line ("Due East"); when 91 .. 179 => Put_Line ("South-East"); when 180 => Put_Line ("Due South"); when 181 .. 269 => Put_Line ("South-West"); when 270 => Put_Line ("Due West"); when 271 .. 359 => Put_Line ("North-West"); when others => Put_Line ("Au revoir"); end case; end Main; |
Oh.. the or
in this syntax is replaced by the |
. symbol . I tried using this notation in place of or
in the if .. else
syntax, and I got an error. This is a point that we may need to keep in mind now and forever.
Ternary Operator
In addition to the branching command structures, in C
and JavaScript
we also have Ternary Operator
conditional expressions to test a condition and select the value assigned to the variable.
1 2 3 4 5 6 | <span class="token keyword">var</span> first <span class="token operator">=</span> <span class="token number">1</span> <span class="token keyword">var</span> second <span class="token operator">=</span> <span class="token number">12</span> <span class="token keyword">var</span> which <span class="token operator">=</span> <span class="token punctuation">(</span> first <span class="token operator">></span> second <span class="token punctuation">)</span> <span class="token operator">?</span> first <span class="token operator">:</span> second console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> which <span class="token punctuation">)</span> <span class="token comment">// result : 12</span> |
If first > second
then choose first
to assign to which
, otherwise choose second
. And in some other languages the symbols ?
and :
will be replaced by keywords with clearer meanings. And if so, then Ada
will definitely use the keywords, in the previous post they clearly introduced that.
1 2 3 4 5 6 7 8 9 | procedure Main is First, Second, Which : Integer; begin First := 1; Second := 12; Which := (if First > Second then First else Second); Put_Line ("Which :" & Integer'Image (Which)); end Main; |
The Elm
language introduced in the previous Sub-Series also had a similar if .. else
conditional expression. However, the difference is that in Ada
we will need to use a pair of parentheses ()
to enclose this expression. Probably because it’s easier to separate information when reading a long statement with elements separated by a space.
Loops
Compared to the popular Imperative
languages, Ada
does not have a do .. while
syntax, but instead has a bare-loop
with no limit of iterations. Here we will have to insert a statement that checks the condition and exits the loop at some point:
loop
– the keyword that starts the loopexit when .. ;
– statement that checks the condition to exit the loopend loop;
– loop end keyword
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Main is I : Integer; begin I := 0; loop Put (Integer'Image (I)); exit when I = 9; I := I + 1; end loop; end Main; |
1 2 | 1 2 3 4 5 6 7 8 9 |
The for .. in
loop syntax is quite similar to JavaScript
‘s for .. in/of
syntax.
1 2 3 4 5 6 7 8 9 10 11 | with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Main is -- begin for I in 1 .. 9 loop Put (Integer'Image (I)); end loop; end Main; |
And the while
loop syntax is also very familiar.
1 2 3 4 5 6 7 8 9 10 11 12 | with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Main is I : Integer := 1; begin while I <= 9 loop Put (Integer'Image (I)); I := I + 1; end loop; end Main; |
Next we will talk about sub-program
..
(unpublished) [Procedural Programming + Ada] Lesson 4 – Package & Sub-Program