Ada Language Fundamentals
Example 0: sayhi.adb
-- Simple Ada program
-- in file sayhi.adb
with Ada.Text_IO;
procedure sayHi is
begin
Ada.Text_IO.put("Hi!"); -- Output some text!
end sayHi;
Program Structure
- In Java, to run a program you execute a
- method
- named
main
- that is nested in a class
- In Ada, to run a program you execute a
- procedure
- that can have any name that you want
- and that is not nested inside anything
- Procedures and methods are similar
Comments
- Comments are marked with
--
to end of line
- Only one kind
- No multiline comment
- Why? What happens here in Java?
/* This is a comment * /
int x = a * b; // What about this line?
/* Another comment */
- Less of a problem with IDEs
Program Structure
Package Ada.Text_IO
-
ada.text_io
: package that contains
routines for i/o of text
- put_line: procedure for string output
- Outputs newline after string
- Some other routines in Ada.Text_IO:
- put: Outputs a string, without a newline
- new_line: outputs a newline character
- new_line(3): outputs 3 newline characters
With Statement
-
with Ada.Text_IO
statement: allows
procedure sayHi
to
refer to routines in package Ada.Text_IO
- If a routine accesses something that is in a package,
the routine must have a
with
statement for that package
-
With
is different from Java
import
, which causes the Java compiler to
automatically search available classes for a feature
Use Statement
with ada.text_io;
use ada.text_io;
procedure sayMore.adb is
begin
put_line("Hi");
put("Good to ");
put("see you friends!");
new_line;
end sayMore;
Use statement allows access to routines without using the
fully qualified name
- Compiler will automatically search ada.text_io for
put_line, put, and new_line
- with statement: tells compiler that the package will be used
- use statement: tells compiler that the package should be
automatically searched, and that the fully qualified name
is not required, although it can be used
Similar to Java import
Make sure you understand the difference between
with
and use
Identifiers and Case Sensitivity
- sayHi and sayMore: procedure names chosen by user
- Identifiers: begin with letters and have any number of
letters, digits, and underscores (underscores must appear
between two non-underscores)
-
Reserved words
cannot be used as identifiers
- Predefined types and values can be used as
identifiers (not recommended
- donteverdothis.adb
- Ada is NOT case sensitive:
- Example: sayhi, sayHi and SAYHI all refer to
the same variable
- Conventions:
- Variable names: camel notation (eg someName)
- Procedures and functions: camel notation (eg
someProc)
- Types: capitalized (eg Integer)
- Packages: capitalized (eg Ada.Text_IO)
- Warning: Operating systems can be case sensitive,
so watch file names
- For gnatmake, file name must be same as procedure name,
but must be all lower case: sayhi.adb, not sayHi.adb
Literals
- A Literal is a value that is
expressed directly in a program
- Example: In the expression (2 + 3), the "2" and the "3"
are literals that represent the obvious values.
The expression itself represents the value 5, but the
literal "5" does not itself appear in the expression.
- String literal: enclosed in double quotes (eg "Hi Mom!", "")
- Character literal: enclosed in single quotes (eg 'H')
- Numeric Literals
- Can contain underscores (eg
1_000_000_000,
1_000.000_1
)
- Underscores must be between 2 digits
- Floating point numbers require digits on each side of decimal
point (eg 0.1, not .1 and not 0.
- Bases 2 to 16:
- binary:
2#0011_1010#
- hexadecimal:
16#3A#
- Exponents are represented using letter E:
10E3
is 10_000
1.0E3
is 1_000.0
2#110#E5
is 6 * 2**5
- Enumerated types
- Later we will see how to create new literals for a new type
- Example:
type color is (red, blue, green);
c: color := blue;
Some Java literals: Numbers.java
Example 1: Table of Squares and Cubes
- This program prints a table of squares and cubes of the
integers from 2 to 10: table1.adb
(prettified version)
- It shows the following concepts:
- if and for loop statements
- Variable declaration
- Assignment
- Integer output
Assignment Statement
- Assignment symbol is
:=
- Equality represented by
=
, as in math
if a = b then
c := d;
elsif e /= f then
g := h;
end if;
Avoids assignment errors found in C/Java family
Assignment in Java and C
boolean a = false;
boolean b = true;
d = 1;
if (a = b)
d = 2;
What about C?
i = 3;
j = 4;
d = 1;
if (i = j)
d = 2;
In C/Java, an assignment operator returns a value. The Ada
assignment symbol does not return a value.
Initialization
- The initial value of a variable is the current contents of its memory cell, unless it is initialized!
with ada.integer_text_io;
procedure initialize is
data1: Integer;
begin
put(data1);
end initialize;
- Outputs whatever value happens to be in memory at that location
- No definite assignment as in java.
- Watch out for subtle errors here: what happens to be in memory can
vary from compiler to compiler and run to run!
Constants
- An identifier that is declared to be a constant
- must be initialized
- cannot appear on the left side of an assignment
- Example:
procedure constants is
data1: Integer;
data2: Constant Integer := 2;
-- data3: Constant Integer; -- Compile error
begin
data1 := 1;
-- data2 := 2; -- Compile error
end initialize;
Is this true in Java?
For Loop Statement
- No brackets: Mark end of loop with
end loop;
-
end loop;
is required even if the loop
body contains only one statement
- Loop variable does not need to be declared
- Loop variable hides variable with same name (Not
recommended)
- Loop variable cannot be modified
- for loop includes range
start .. finish
- if start = finish, execute 1 time
- if start > finish, execute 0 times
- What does this do:
for i in reverse 1 .. 10 loop
- What happens here: JavaFor.java
- What does the Ada version look like?
Three Kinds of Loops
for i in 1 .. 10 loop
...
end loop;
While loop
i := 1;
while i <= 10 loop
...
i := i + 1;
end loop;
General loop (infinite loop that can have an exit)
i := 1;
loop
exit when i = 10;
...
i := i + 1;
end loop;
Loop and a Half
- Is exiting from the middle of a loop a good idea?
- How to code input, test, process, input, test, process, input, ...
- Contrast this:
input i
while i /= flagValue loop
process i
input i
end loop;
With this:
loop
input i
exit when i = flagValue;
process i
end loop;
Which is shorter, clearer, more error prone
Guidelines for using exit:
- Use exit when rather than if C then exit
- If possible, use only one exit statement
- Keep multiple exit statements together
Named Loops
- Loops can be named
- Example:
Search: -- Name the loop
for i in 1 .. 10 loop
for j in 1 .. 20 loop
...
exit when ... -- Exits inner loop
...
exit Search when ... -- Exits outer loop
end loop;
end loop Search;
If Statements
- No parens around condition
-
then
required
-
end if;
is required, even if body has only
a single statement
- keyword
elsif
- allows multiple conditions in single if
- avoids nesting
- Can have as many
elsif
statements as
desired
-
else
statement optional
- Remember: if and for statements have
end if;
and
end for;
- Remember goal: concern for programmer
Case Statement - Multiway Selection
- Java version - what is the output?
i = 3;
switch (i){
case 4: System.out.println("****");
case 3: System.out.println("***");
case 2: System.out.println("**");
case 1: System.out.println("*");
default: ;
}
Ada version - what is the output?
i := 3;
case i is
when 4 => put_line("****");
when 3 => put_line("***");
when 2 => put_line("**");
when 1 => put_line("*");
when others => null;
end case;
Ada does not fall through to next case
when others
required if all values not accounted for
Ada uses null;
instead of solely ;
Case Statement - Multiple-Value Selection
- Multiple value selection in Ada and Java:
-- Ada:
case i is
when 4|3 => put_line("****");
when 2|1 => put_line("**");
when others => null;
end case;
// Java
switch (i){
case 4:
case 3: System.out.println("****"); break;
case 2:
case 1: System.out.println("**"); break;
default: ;
} // End of break
Common Java Errors Avoided
if (a == b)
c = d;
else
e = f;
g = h;
When is Sop(i)
executed?
while (i++ <= 10);
System.out.println(i);
Is the indentation correct on these?
When is i = j
executed?
if (a == b)
c = d;
if (e == f)
g = h;
else
i = j;
///////////// /////////////
if (a == b)
if (e == f)
g = h;
else
i = j;
Some test code
and a
prettified version
How to code these in Ada?
Example Program
- Let's get some practice by writing a simple program
- Let's start by reading and printing a name
- Now let's sum a group of integers and calculate and print their average
- First we'll input the number of numbers and read that many numbers
- Can we format the average of the numbers
- What if the numbers are floating point?
- Let's make sure the number of numbers is non-negative
- Now let's read until eof
- Can we let the name be of any length?
Integer'Image - An Attribute of type Integer
- Similar to Java
toString()
method
- Resulting string includes a leading blank
- 'Image is an attribute of the type Integer
- Most built-in types have 'Image attribute
Package Ada.Integer_Text_IO
- Integer input and output routines
- Name comes from outputing an integer as text
- Routine
put
is overloaded (ie same name
but different parameters)
- Ada.Text_IO.put("HI");
- Ada.Integer_Text_IO.put(i);
- If two packages have the same routine with the
same parameter list, then the package name must
be used to disambiguate the routines
- Can a single package have two routines with
the same name and same parameter list?
- Minimum width - eg put(i, 1)
- If given 2 parameters, the second is the minimum
width
- Pads on left with blanks if needed
- Examples:
i := 37;
--12345678901
put(i, 5); -- 37
put(i, 1); --37
put(i); -- 37
-- Default width is 11
Integer Types
- Type Integer is a primitive type
- like java int
- Variable stores a value, rather than a reference to
a value
- Sizes of Integer types:
- Sizes of types are NOT defined by the language
(unlike Java)
- Values of type Integer are typically 32 bits
- Values of type Long are typically 64 bits
Floating Point Types
- Type
Float
- 32 bits on gnat
- Type
Long_Float
- 64 bits on gnat
- Primitive types
- Floating point types trade precision for range
- 32 bit Integer has 10 significant digits in range
± 1010
- 32 bit Float has about 7 significant digits for numbers as
small as ± 10-44 and as large as ±
1038
Package Ada.Float_Text_IO
- Contains routines for IO of floating point types
- put(x)
- default format: scientific notation
- put(x, 3, 4, 1): fore, aft, exp
- fore: minimum digits to left of decimal point
- aft: digits to right of decimal point
- exp: digits in exponent - 0 means no exponent
Primitive Types
- Integer and Float are primitive types (ie built in)
- Other built in types include
- Character: 8 bit (Wide_Characters are 16 bit Unicode)
- Boolean: values
true
and false
- Positive: range 1 .. Integer'Last
- Natural: range 0 .. Integer'Last
- String
- Later we will see that
- Character and Boolean are Enumerated types
- Positive and Natural are actually subtypes of Integer
- String is an array of characters
- Ada variables are not reference types (ie pointers)
unless special steps are taken
Types and Type Checking
- Ada has different and generally stronger type checking
rules than Java
- Types of right and left sides of assignment must match
- x: Float := 3; -- Compile error
- Java would do an implicit conversion
- Arithmetic operators must have the same types on both sides
- y := 2 + 3.0; -- Compile error
- Java would do an implicit conversion
- Later we will see numeric subtypes that have more flexible
rules: Ada will do implicit conversion on subtypes (eg from natural to integer)
Explicit Type Conversion
- Example - this won't compile - it contains type mismatch:
i: Integer;
f, g: Float;
...
g := f + i;
Ada will not do an implicit conversion between integer and float
Example - will compile - the explicit type conversion fixes the type mismatch:
i: Integer;
f, g: Float;
...
i := 99;
...
g := f + Float(i);
-- float(i) returns the value of i as a float
-- that is, it returns 99.0
In general, a type conversion uses the name of a type as if it were a function
that takes a value of one type and returns a value of a different, related type
Similar to a java type cast (eg g = f (float) i;)
Implicit and Explicit Type Conversion
- Ada will not do an implicit type conversion from integer to float
- Java will do an implicit type conversion from integer to float
- C will do an implicit type conversion from integer to float and float to integer
- C++ will do an implicit type conversion from integer to float
- C++ will do an implicit type conversion from float to integer and give a
warning
- Ada will do an implicit type conversion between a subtype of a type and the
type (eg from natural to integer, and integer to natural)
- A constraint error is raised if the value of the parent type is not
valid for the subtype
- Java has rules for subtypes and parent types with inheritance
- Parent myP; Child myC;
- myP = myC; //??
- myC = myP; //??
Operators: Precedence and Associativity
Highest | ** abs not | exponent, absolute value,
logical negation |
Multiplying | * / mod rem | mod and rem
differ for negative numbers |
Unary adding | + - | |
Binary adding | + - & | &
is string concatenation |
Relational | = /= < <= > >= | Note:
not equal is /= rather than != |
Boolean (Lowest) | and or xor |
xor is exclusive or |
- All operators are (generally) left associative (but
sometimes parens are required)
- Later we will see: in, and then, or else
- They are used like operators but they are not called
operators
Examples using Arithmetic Operators
- 6 / 2 yields 3
- 6.0 / 2.0 yields 3.0
- 6.0 / 2 does not compile
- most operators require operands to be of the same type
- 2.0 ** 3 yields 8.0
- 2.0 ** (-3) yields 0.125 (ie 1/8)
Rem and Mod Operators
- Summary of Behavior
- x rem y and x mod y give the same result when x and y have
the same sign
- rem and mod differ when x and y have different signs :
- Example:
- 13 mod 4 = 13 rem 4 = 1
- -13 mod -4 = -13 rem -4 = -1
- (-13) mod 4 yields 3
- 13 mod (-4) yields -3
- (-13) rem 4 yields -1
- 13 rem (-4) yields 1
- Sign and magnitude of the result:
- The sign of the result:
- sign of (x mod y) = sign of y;
- sign of (x rem y) = sign of x;
- The magnitude of the result - the results make these
formula true:
- x = y * floor(x/y) + (x mod y)
- floor truncates toward negative infinity (eg
trunc(-1.1) = -2)
- eg -13 = 4 * floor(-13/4) + -13 mod 4 = -16 + 3
- Another desired characteristic of mod: 0 ≤
x/y - floor(x/y) = (x mod y)/y < 1
- x = y * trunc(x/y) + (x rem y)
- trunc truncates toward zero (eg trunc(-1.1) =
-1)
- eg -13 = 4 * trunc(-13/4) + -13 rem 4 = -12 + -1
- Motivation:
- rem is useful because computer arithmetic operates
like trunc (ie it rounds toward 0)
- mod gives the behavior we want for modular arithmetic
(eg clock arithmetic) such as this:
(X1 + X2) mod Y = ((X1 mod Y) + (X2 mod Y)) mod Y
How about Java?
Finally, note that rem and mod have higher precedence
than unary minus so -3 mod 4 means -(3 mod 4)
Examples using Relational and Boolean Operators
- When
and
and or
are mixed, parens
are required (ie user must specify order of
evaluation)
- Example:
if (a < b or c < d) and e <
f then
- Parens are also required if multiple relational operators are
used:
- Example:
if (a < b) = true then
Example using String Concatenation Operator
put_line("Hello, this certainly is a "
& "really long line!");
Short Circuit: and then, or else
-
and then
and or else
are short circuit versions of and
and or
- Short circuit control forms don't evaluate the right operand if the result
is known from the left operand
- Non-Short circuit operators always evaluate both operands
- Examples:
if d /= 0 and then (n / d) > 3 then ...
if x = null or else x.value = probe then ...
Good for processing linked data structures!
Java: What do these do?
if (a == b && c++ == d) ...
if (a == b & c++ == d) ...
in Membership Test
if i in 1 .. 10 then