Discussion of intro_all.adb
Introduction
- Goals for procedural programs (and Ada):
- Reliability and maintenance
- Program efficiency (time and space)
- Programming as a human activity (readability vs writability)
- Closeness to machine
- We will see examples of these in language design
- "Syntax matters more than you think"
- Topics:
- Comments, Program Structure, Context Clauses, Use Clause
- Main Program, Identifiers, Declarations
- Standard Types, Literals, IO Libraries
- Operators, Precedence, Strong Typing, Conversions, Attributes
- Control Structures
Comments, Program Structure, Context Clauses, Use Clause
Comments
- -- to end of line
- No multi-line comment (ie block comment)
- Why: reliability problems - what was the programmer's intention?
Problems with Block Comments
- Consider this:
/* x = 3; * /
y = 4;
/* z = 5; */
- Did you catch the error above? Now consider this:
/* Startup
x = 3;
/* Reset count */
count = 2 * x;
- And this:
/* x = 3;
y = 4;
/* Come back and think about z's value
* z = 5;
*/
- This C code ...
int i = 98;
int * p = & i; /* pointer p points to i */
i = i / *p;
i = /* say something about the expression here */
-4;
printf("%d\n", i); /* result is -4 */
- ... gives different results from this C code:
int i = 98;
int * p = & i;
i = i /*p; -- Starts a comment!!!
i = /* say something about the expression here */
-4;
printf("%d\n", i); /* result is 94 */
- Different results in C and C++ (from Stroustrup):
int b = a//* divide by 4 */4;
-a;
- Is nesting allowed?
- What does this mean:
int nest = /*/*/0*/**/1;
- If comments do NOT nest:
nest = 0 * 1;
- If comments do nest:
nest = 1;
- Same code, with some spaces:
int nest = /*/*/ 0 */**/ 1;
- You don't need to know C to see that lots of problems can arise!
- Some examples from Van Tassel, 2004 web paper
Program Structure: Three sections
-- 1. Context Clauses:
with ...
procedure intro_all ...
-- 2. Declaration Section
begin
-- 3. Executable section
end intro_all;
Context Clauses: With Statements and Packages
-
with Ada.Text_IO
is a context clause
- Informs compiler that package Ada.Text_IO is used in this file
- Packages are libraries of procedures and functions (ie methods),
types, constants
- All packages referenced in a file must be named in a context clause
- Exception: Package Standard is automatically available without a context clause. It
contains definitions of some basic types and operators.
- Packages referenced in
intro_all.adb
are:
-
Ada.Text_IO;
: IO of strings and characters
-
Ada.Integer_Text_IO;
: IO of Integers
-
Ada.Float_Text_IO;
: IO of Floats
- One package is automatically available: Standard
- Contains definitions of standard type, such as Boolean
- Similar to java.lang
- Notice: all dependencies specified at compile time
With Statement: Motivation and Comparison
- Why have a with statement?
- Provides a level of redundancy for the compiler
- Provides a simple way to find all packages used, without searching for
all library accesses
- Allows with and use (see below) as separate statements
- Facilitates separate dependencies of package specification and implementation (which are discussed
later)
- Nothing comparable in Java:
- In Java, any class that the compiler can find can be referenced
- Classes accessed may not be known until runtime
- Similar to C and C++
#include
statement, but include has
disadvantages:
- Include works by expansion
- It can have nesting
- It is much less reliable
Fully Qualified Names and Use Statements
- Access package members using the
fully qualified name:
Ada.Text_IO.Put("Hi")
- The use clause avoids need for using fully qualified name
- (eg
put("Hi");
vs Ada.Text_IO.put("Hi");
- Full name is still allowed (eg can say
Ada.Text_io.new_line
);
- Sometimes full name is needed to disambiguate overloaded functions
- Use can be placed within procedures for better control
- Some company policies don't allow
use
- it can hurt readability
- Use is similar to jave import:
- import allows access to class members without using fully
qualified names
- import is never required (if full names are used)
- import and use have nothing to do with anything beyond compilation
- Java has no equivalent to the with statement:
program can access any class file that the compiler can find
Main Program, Identifiers, Declarations
Procedure intro_all
-
procedure intro_all
-
intro_all
is the name of the main program
- Execution begins at corresponding
begin
- Name is chosen by user
- Main routine doesn't have to be
main
- main program name matches file name (for gnat compiler)
Compare and Contrast with Java
- These are comparable:
-
procedure hello1 is begin ... end hello1;
-
public static void main(String[] args){...}
- Begin/end used instead of brackets
- A procedure is similar to a void method
- No class needed to encapsulate
hello1
Rules for Identifiers
- Three simple rules for forming identifiers
- Begin with letter
- Followed by any number of letters, digits, underscores
- Underscore must be followed by a letter or digit
- Case Insensitive:
- hello, Hello, and HELLO all identify the same item
- Letters include 32 bit characters
- Example: π:
Constant := 3.141_59;
- Compare and Constrast with Java identifiers:
- Any number of Unicode character that are letters or digits, _, $
- Must not begin with digit
- Pros and cons:
- Pro: Less possibility of mixing up names
- Con: Smaller name space
Declarations: Variables, Constants, Named Numbers
- Everything must be defined before (ie above) it is used
- Name first, then type
- All declarations in declaration section
- Later we will see the declare block, which allows declarations anywhere
- Like Java, can declare constants of a specific type
- Constants must be initialized
- Can declare numeric constants without specified types, called named numbers
pi: constant := 3.141_592_5
Pros and cons of "variable: type":
- Pro: readability - easier to find declaration
- Con: writability
Standard Types, Literals, IO Libraries
Standard Types
- Standard types include:
- Integer (32 bit. Range: -2**31 .. 2**31-1)
- Float (32 bit)
- String - Must specify length, implicitly or explicitly
- Explicit: s: String(1..10);
- Implicit: s: String := "Hi"; -- Length 3
- Empty string is ""
- Represent " with double quote
- ie
put("This sentence, ""Madam, I'm Adam"", is a palindrome.")
- Character - 8 bit (16 and 32 bit characters also available)
- Boolean - True or False
- Pros and cons:
- None of these are reference types
- Less space to store
- Faster to access
- Modifible
- Fixed length is less flexible
- Principle: Don't pay cost if don't need feature
Range Constraints
- Used in
one_v3.adb
, not in intro_all.adb
- Example:
temp: integer range 0 .. 100;
...
get(temp); -- exception if out of range
Benefits:
- Express intention more clearly
- Program as contract: this variable will hold variables in this range
- Catch errors earlier
- Allows proving properties about programs
Types Natural and Positive
- Two useful built-in (sub)types:
- Natural (32 bit. Range: 0 .. 2**31-1)
- Positive (32 bit. Range: 1 .. 2**31-1)
- These are actually subtypes defined in Standard (don't redefine them youself!)
-
subtype Natural is Integer range 0 .. Integer'Last
-
subtype Positive is Integer range 1 .. Integer'Last
- Type checking: can be mixed with parent type without conversion:
-- Where can runtime errors occur?
i: Integer;
n: Natural;
begin
get(i)
n := i;
get(n)
i := n;
Catch errors earlier, etc
Literals
- Underscores can be used in numbers
- Example:
Pi: Constant :=
3.14159_26535_89793_23846_26433_83279_50288_41971_69399_37510;
- Floats must begin and end with a digit (eg ...)
- Is 0. an integer with a mistaken decimal, or a decimal with a missing fraction
- Different bases are possible:
- Binary: 2#1100_1000#
- Hex: 16#BF3F#
- Fractional: 2#11.01# is 3.25 decimal
- 2#11.01#E+3 is same as 2#11010#
- Compare with C: only octal is available
- Character and string literals:
- Character: use single quotes (eg 'b')
- String: use double quotes (eg "Hi Mom")
- No escape characters (ie no \n)
- Can use Ada.Characters.Latin_1.LF, .CR, .HT
- Principle: Programming as a human activity
New Literals: Enumerated Types
- New literals: used in enumerated types
- Example - define new literals for colors:
type color is (red, blue, green);
c: color := blue;
...
if c = red then ...
Programming as a human activity
- Use names, not numbers
- Allows better type checking
-
C: roomColor = red + 1; -- Error
More examples below
Ada.Text_IO: put_line and other I/O routines
-
Ada.Text_IO
contains many routines for I/O of text
- Routines from Ada.Text_IO:
-
put_line(s)
: output string s
and a new_line
-
put(s)
: outputs its character or string parameter s
, without a newline
-
new_line
: outputs a newline
-
new_line(n)
: outputs n
newlines
-
set_col(n)
: move output cursor to column n
-
end_of_file
: checks for end of file
-
get
: read a character or a fixed length string from the input
-
get_line
: read a string from the input
- Remember:
-
put
takes characters or strings
-
put_line
takes only strings
- Reliability: strong typing - force programmer to be use specific routine
Ada.Integer_Text_IO
- Ada.Integer_Text_io - IO of Integers as text
- put(i); -- output integer i with default width (eg width 11)
- 32 bits: plus or minus 2**31 =~ 10**10, so, 10 digits plus a sign = 11 digits
- put(i, w); - w is minimum width
- get(i);
- finds next integer in input
- Changes value of
i
to that integer
- get(i): skips white space (blanks, tabs, newlines)
- Data_error occurs if non-digit is found
- End_Error occurs if end of file is found
Keyword Parameters
Default Parameters
- Parameters can have default values
- Example: for new_line, the default is 1
procedure new_line(Count: Positive := 1) ...
For integer_text_io, the default width is 11 (big enough for 2 billion and a sign)
procedure put(Item: Integer; width: Natural := 11) ...
Ada.Float_Text_IO
- Ada.Float_Text_io - IO of Floats as text
- put(x); -- output float x in scientific notation
- put(x, f, a, e); - fore, aft, exponent
- get(x);
- finds next float in input
- Can read an integer and convert it to a float
- Changes value of
x
to that float
- get(i): skips white space (blanks, tabs, newlines)
- Data_error occurs if non-digit is found
- End_Error occurs if end of file is found
Operators, Precedence, Strong Typing, Conversions, Attributes
Operator Precedence and Associativity
Highest ** abs not
Multiplying * / rem mod
Unary adding + -
Binary adding + - &
Relational = /= < > <= > =
Logical and or xor
Associativity: left to right for operators at same level
Reliablility: small number of levels
Arithmetic Operators
- Basic Arithmetic:
+, -, *, /
- Each operates on two integers or two floats
- Division of two integers truncates the result
- Example: -7 / 2 = -3
- Absolute value: abs (Example:
x := abs y;
)
- Remainder and Modulus:
mod, rem
- Same for positive operands
- rem
- Same as java %
- Absolute value of result always the same
- Sign of result is sign of left operand
- Example: (-2) rem 12 = -2
- Equation (a/b)b + (a rem b) = a is true when a/b truncates toward 0
- mod
- Good for clock arithmetic
- Example: (1 - 3) mod 12 = 10
- Sign of result is sign of right operand
- Equation (a/b)b + (a mod b) = a is true when a/b truncates toward -∞
- Power:
**
- 2 ** 3 = 8
- 2.0 ** 3 = 8.0
- 2.0 ** -3 = 0.125 (ie 1/8)
- 2 ** -3 gives a compilation error
- Programming is a human activity: use names vs symbols
Not Equal
Boolean Operators
- Boolean: and, or, xor, not
- Parentheses required when using more than one of and, or, xor
- Improves reliability
Character and String Concatenation
- String concatenation: &
- Overloaded for characters: 'a' & 'b' = "ab"
- Overloaded for characters and strings: 'a' & "b" = "a" & 'b' = "ab"
Short Circuit Forms
- Short circuit: And then, Or else
- Only evaluate second operator if necessary
- Example: if x /= 0 and then y / x > 3.0 then
- Example: if x /= null and then x.data > 3.0 then
- Reliability
In Operator
- Examples:
-
if i in 1 .. 10 then -- inclusive
-
if i in 1 .. 10 | 15 | 21 .. 30 then
-
if i in Natural then
-
if f in 1.0 .. 10.0 then -- inclusive
- In case you're wondering how to do an exclusive range:
-
if f in float'adjacent(1.0, 2.0) .. float'adjacent(10.0, 9.0) then
- float'adjacent(x, y) returns the value adjacent to x in the
direction of y
- Nice to program with
- Improves readability and reliability
Unary Minus
- Sometimes extra parentheses are required for unary minus:
x := x + (-2);
x := x * (-2);
x := x mod (-2);
x := (-2) mod 12;
Notice that -2 ** 4 means -(2**4) and not (-2)**4.
Strong Type Checking
- Strong type checking:
- Ensures that operations have valid operands
- Occurs on assignment, procedure calls, and arithmetic operations
- Ada is more strongly typed than Java
// Java
int sum;
double av; // 64 bit floating point
// Assignment
av = 3; // Type mismatch, but compiles
av = sum / 3; // Type mismatch, but compiles
// Method calls
av = java.Math.sqrt(3); // Type mismatch, but compiles
// Arithmetic operations
av = sum / 3.0; // Type mismatch, but compiles
--------------------------------------
-- Ada
sum: Integer;
av: float; -- 32 bit floating point
-- Assignment
av := 3; -- Type mismatch. Does not compile
av := sum / 3; -- Type mismatch. Does not compile
-- Procedure parameters
Ada.Float_Text_IO.put(3); -- Type mismatch. Does not compile
-- Arithmetic operation
av := sum / 3.0; -- Type mismatch. Does not compile
Stronger type checking gives better reliability
Implicit and Explicit Conversions
- Java does implict conversion; Ada does not
- In the examples above, ints are implicitly converted to doubles
- The Java code below shows the equivalent explicit conversions
- The Ada code below shows the required explicit conversions
// Java
// Assignment
av = (double) 3; // Explicit conversion int to double
av = (double) (sum / 3); // Explicit conversion int to double
// Method calls
av = java.Math.sqrt((double)3); // Explicit conversion int to double
// Arithmetic operations
av = sum / 3.0; // Explicit conversion int to double
--------------------------------------
-- Ada
-- Assignment
av := float(3); -- Explicit conversion
av := float(sum / 3); -- Explicit conversion
-- Procedure parameters
Ada.Float_Text_IO.put(float(3)); -- Explicit conversion
-- Arithmetic operator
av := float(sum) / 3.0; -- Explicit conversion
Reliability
Caution: Conversions and Integer and Floating Point Conversion
- Make sure that you understand the difference between these two:
av := float(sum) / float(3);
av := float(sum / 3);
What happens in this Java code?
av = sum / 3;
Are these the same?
int_av = sum / 3; -- Truncate or round?
av = float(sum) / float(3);
int_av = integer(av); -- Truncate or round?
Summary:
- Integer division: both languages truncate
- Conversion: Java truncates, Ada rounds (away from 0)
Type Checking Rules
- Ada Type Checking Rules:
- Both sides of assignment must match
- Formal and actual parameters must match
- Function return type and value must match
- Operands of arithmetic operators must match (with a few exceptions)
- No implicit conversion between Integers and Floats
- Java does implicit widening conversion, Ada does not
- Explicit conversion is required
- Rules for subtypes are slightly different (discussed later)
Type Checking and I/O
- Must do IO with correct routine
-- Ada // Java
ada.integer_text_io.put(i); System.out.print(i);
ada.float_text_io.put(a); System.out.print(a);
Ada disambiguates using parameter type to choose correct version
Type Attributes
- Attributes provide several capabilities:
- Information about variables
- Information about types
- Functions that operate on types
- Attributes 'img and 'image
-
'img
and 'image
are called attributes
- These two attributes operate like toString: convert a value to a string
-
'img
is an attribute of a variable
-
'image
is an attribute of a type; it operates like a function
- 'img is provided by gnat, it's not standard Ada
- Most types allow 'img and 'image
- Some other attributes:
- Integer'value is inverse of 'image (eg Integer'value("456"))
- Integer'first - the smallest integer
- Integer'last - the largest integer
- Integer'range - the range from smallest to largest integer
- Character'val(65) - Character whose position is 65
- Character'pos('A') - position of 'A' in the set of Characters
- Boolean'val(0) - Boolean value at position 0 (ie false) in the
set of Boolean values
- Boolean'pos(true) - Position of true (ie 1)
- Example: attributes.adb and prettified
- Ceiling, floor, rounding
- f := Float'ceiling(1.1);
- f := Float'floor(1.9);
- f := Float'rounding(1.9);
- f := Float'rounding(1.5);
- f := Float'rounding(-1.5);
- Max and min:
- Integer'max(i, j);
- Float'min(a, b);
- Valid, width, size, 'Address, 'Access
- V'valid - returns true if the value of V is valid for V's type
- S'width - returns the size of the largest string needed for a value in type S
- S'size - returns the size in bits for value in type S
- V'Address and V'Access - return addresses (of different types)
- Provide closeness to machine
Enumerated Type
- Type made up of new set of values
- Can assign, compare, etc
- Can loop over type
- Can specify ranges and subtypes
- 'img attribute converts to string
- Need Enumeration_IO for input and output of new values
Type Boolean
- Has literals
true
and false
- Provided in package Standard (available to all programs)
- In package Standard:
type Boolean is (True, False);
Control Structures
For Loops
More on For Loops
- Other increments: Some options
- Use a while loop
- Increment another variable in a for loop
- Reverse loop: output 10, 9, ..., 1
for i in reverse 1 .. 10 loop
put(i);
end loop;
Can have an empty range (eg for i in low .. hi, where low
> hi)
Three Kinds of Loops
- For loop
- While loop
- General loop
- All three have structure
loop
...
end loop;
While Loops
C: Character;
...
-- Echo characters, but not newlines
while not end_of_file loop
get(c)
put(c);
end loop;
General Loops
C: Character;
...
-- Echo characters, but not newlines
-- Exit when x is entered
loop
get(c)
exit when Ada.Characters.Handling.to_upper(c) = 'x';
put(c);
end loop;
Loop and a Half
- Example loop:
get(c)
done := false
done := Ada.Characters.Handling.to_upper(c) = 'x';
while not done loop
put(c);
get(c)
done := Ada.Characters.Handling.to_upper(c) = 'x';
end loop;
- Rewritten using a loop and a half structure:
loop
get ...
exit when ...
process ...
end loop;
-- get, test, process, get, test, process, ...
- Avoid exiting loop in multiple places
- Some say to never exit a loop from the middle
If Statements
- Parens not needed around condition
- Explicit
then
keyword
- Syntax:
if ... elsif ... else ... end if
-
elsif
and else
are optional
- Can have 0 or more
elsif
- Can have 0 or 1
else
-
End if
required, even if body has one statement
Compound Parts of If Statements
- Compound parts don't need explicit brackets
- Count grades in Ada:
if g >= 90 then
put_line("found an A");
numA := numA + 1;
elsif g > 80 then
put_line("found an B");
numB := numB + 1;
elsif g > 70 then
put_line("found an C");
numC := numC + 1;
else
put_line("found another");
numOther := numOther + 1;
end if;
In java compound parts require brackets:
if (g >= 90){
S.o.p("found an A");
numA++;
}
else if (g >= 80){
S.o.p("found a B");
numB++;
}
else if (g >= 70){
S.o.p("found a C");
numC++;
}
else {
S.o.p("found another grade");
numOther++;
}
Or like this:
if (g >= 90)
{
S.o.p("found an A");
numA++;
}
else
if (g >= 80)
{
S.o.p("found a B");
numB++;
}
else
if (g >= 70)
{
S.o.p("found a C");
numC++;
}
else
{
S.o.p("found another grade");
numOther++;
}
Java we use else if
instead of elsif
Contrast elsif and else if
- An if is a single statement, and so it can be used in the else part of a Java if
statement without brackets
- What would Java look like if brackets were required:
if (g >= 90){
S.o.p("found an A");
numA++;
}
else { if (g >= 80"){
S.o.p("found a B);
numB++;
}
else { if (g >= 70"){
S.o.p("found a C);
numC++;
}
else {
S.o.p("found another grade");
numOther++;
}}} // Careful with the braces!
Or like this:
if (g >= 90){
S.o.p("found an A");
numA++;
}
else {
if (g >= 80"){
S.o.p("found a B);
numB++;
}
else {
if (g >= 70"){
S.o.p("found a C);
numC++;
}
else {
S.o.p("found another grade");
numOther++;
}
}
} // Careful with the braces!
Languages that require closing brackets tend to use elsif
- Examples: Ada and perl use elsif; python uses elif
Case Statement
case i is
when -1 =>
when -7 | -11 => ...
when -5 .. -3 => ...
when Natural => ...
...
when others => ...
end case;
Does not fall through like Java
Overlap not allowed
Must account for each value in type of i
- when others is required if all values not otherwised listed