programming in the small: c/c++/java pitfalls & ada benefits franco gasperoni...
TRANSCRIPT
Programming in the Small:C/C++/Java Pitfalls
& Ada Benefits
Franco [email protected]
http://libre.adacore.com/Software_Matters
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 3
Suggested Reading
C Traps and Pitfalls• by Andrew Koenig (Addison Wesley)
Guidelines for the Use of the C Language in Vehicle Based Software
• Purchasing info at http://www.misra.org.uk/misra-c.htm
Multilanguage Programming on the JVM: The Ada 95 Benefits
• http://libre.act-europe.fr/Why_Ada/ada-on-jvm.pdf
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 5
Lecture Summary
In this lecture we concentrate on programming in the small
We go over some Ada basic constructs• Procedures, functions, types, loops, if and case statements exceptions,
etc.
We show some C/C++/Java pitfalls
We show how Ada avoids them
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 12
Programming in the Small with C
C makes the following assumption:• Trust the programmers, they never make mistakes• Favor program conciseness over its readability
But:• Programmers do make mistakes• Programs are written once but read many times
The C foundation of C++ & Java leads to fragile software• Software where it is easy to make mistakes• Software that is hard to read• Software that is hard to change
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 14
Note on the Ada Development Environment
In this course we use GNAT GAP Edition
GNAT is widely available• You can download the sources of GNAT• Pre-built GNAT binaries available for: Linux, Solaris, Windows
GNAT GPL Edition available at • http://libre.adacore.com
Background on Ada ProgrammingA Simple Example
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 16
Procedure Main
Procedure Main• Stored in file main.adb• Technically this is called a compilation unit
A compilation unit can be the body or the spec (specification) of a:
• procedure• function• package (see next lecture)
Spec = precise list of services exported
Body = implementation details
In GNAT: • 1 compilation unit per file • File name matches unit name• 2 file extensions possible
.adb = Ada Body .ads = Ada Spec
with Text_IO;
procedure Main isLength : Integer := 8265;Width : Integer := 0252;Height : Integer := 8292;
beginText_IO . Put_Line (Length'img);Text_IO . Put_Line (Width'img);Text_IO . Put_Line (Height'img);
end Main;
with Text_IO;
procedure Main isLength : Integer := 8265;Width : Integer := 0252;Height : Integer := 8292;
beginText_IO . Put_Line (Length'img);Text_IO . Put_Line (Width'img);Text_IO . Put_Line (Height'img);
end Main;
Note: Ada is case insensitiveNote: Ada is case insensitive
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 17
Inside Procedure Main
Declarative part: Contains the declaration of:• Variable, types, nested procedures, nested
functions, ... used in procedure Main
with Text_IO;
procedure Main isLength : Integer := 8265;Width : Integer := 0252;Height : Integer := 8292;
beginText_IO . Put_Line (Length'img);Text_IO . Put_Line (Width'img);Text_IO . Put_Line (Height'img);
end Main;
with Text_IO;
procedure Main isLength : Integer := 8265;Width : Integer := 0252;Height : Integer := 8292;
beginText_IO . Put_Line (Length'img);Text_IO . Put_Line (Width'img);Text_IO . Put_Line (Height'img);
end Main;
Procedure statements
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 18
with Text_IO;
List of compilation units whose services are used in procedure Main
Text_IO is the predefined Ada text Input/Output library
with Text_IO;
procedure Main isLength : Integer := 8265;Width : Integer := 0252;Height : Integer := 8292;
beginText_IO . Put_Line (Length'img);Text_IO . Put_Line (Width'img);Text_IO . Put_Line (Height'img);
end Main;
with Text_IO;
procedure Main isLength : Integer := 8265;Width : Integer := 0252;Height : Integer := 8292;
beginText_IO . Put_Line (Length'img);Text_IO . Put_Line (Width'img);Text_IO . Put_Line (Height'img);
end Main;
Procedures declared in library Text_IO and used in Main
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 19
use Text_IO;
By putting a use clause you can (but don't have to) omit the Text_IO prefix inside Main
with Text_IO; use Text_IO;
procedure Main isLength : Integer := 8265;Width : Integer := 0252;Height : Integer := 8292;
beginText_IO . Put_Line (Length'img);Text_IO . Put_Line (Width'img);Text_IO . Put_Line (Height'img);
end Main;
with Text_IO; use Text_IO;
procedure Main isLength : Integer := 8265;Width : Integer := 0252;Height : Integer := 8292;
beginText_IO . Put_Line (Length'img);Text_IO . Put_Line (Width'img);Text_IO . Put_Line (Height'img);
end Main;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 20
The ' img Attribute
' img is a predefined GNAT attribute • Given an integer or floating point number X,
X ' img returns its string representation• More on attributes later on
with Text_IO; use Text_IO;
procedure Main isLength : Integer := 8265;Width : Integer := 0252;Height : Integer := 8292;
beginText_IO . Put_Line (Length ' img);Text_IO . Put_Line (Width ' img);Text_IO . Put_Line (Height ' img);
end Main;
with Text_IO; use Text_IO;
procedure Main isLength : Integer := 8265;Width : Integer := 0252;Height : Integer := 8292;
beginText_IO . Put_Line (Length ' img);Text_IO . Put_Line (Width ' img);Text_IO . Put_Line (Height ' img);
end Main;
Structure of an Ada Program
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 22
General Structure of an Ada Program
with …;procedure Some_Main is
…begin
…end Some_Main;
with …;procedure Some_Main is
…begin
…end Some_Main;
with …; with …;
with …; with …;
with …; with …;
with …; with …;
with …; with …;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 23
A Simple Example
with Display;with Fact;procedure Display_Fact isbegin
for K in 1 .. 4 loopDisplay ("Factorial", K, Fact (K));
end loop;end Display_Fact;
with Display;with Fact;procedure Display_Fact isbegin
for K in 1 .. 4 loopDisplay ("Factorial", K, Fact (K));
end loop;end Display_Fact;
with Text_IO; use Text_IO;procedure Display (S : String; X, Y : Integer) isbegin
Put_Line (S & " (" & X'img & ") = " & Y'img);end Display;
with Text_IO; use Text_IO;procedure Display (S : String; X, Y : Integer) isbegin
Put_Line (S & " (" & X'img & ") = " & Y'img);end Display;
function Fact (N : Integer) return Integer isbegin
if N <= 1 thenreturn 1;
elsereturn N * Fact (N - 1);
end if;end Fact;
function Fact (N : Integer) return Integer isbegin
if N <= 1 thenreturn 1;
elsereturn N * Fact (N - 1);
end if;end Fact;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 24
Building & Executing Display_Fact
GNAT has an automatic "make" facility: gnatmake
Gnatmake• Will compile or recompile the Ada
sources that need to be compiled• It will bind and link them
A make file is not necessary
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 25
Note on the Concatenation Operator &
with Text_IO; use Text_IO;procedure Display (S : String; X, Y : Integer) isbegin
Put_Line (S & " (" & X'img & ") = " & Y'img);end Display;
with Text_IO; use Text_IO;procedure Display (S : String; X, Y : Integer) isbegin
Put_Line (S & " (" & X'img & ") = " & Y'img);end Display;
&& ==
1 dimensional arrays1 dimensional arrays
11 22 33 44 55 AA BB 11 22 33 44 55 AA BB
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 26
with Display;with Fact;procedure Display_Fact isbegin
for K in 1 .. 4 loopDisplay ("Factorial", K, Fact (K));
end loop;end Display_Fact;
with Display;with Fact;procedure Display_Fact isbegin
for K in 1 .. 4 loopDisplay ("Factorial", K, Fact (K));
end loop;end Display_Fact;
Note on For Loops
In for loops, the loop variable (K in the example) is implicitly declared
The loop variable cannot be modified inside the for loop
The loop variable ceases to exist just after the loop
Numeric Pitfallin C/C++/Java
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 28
#include <stdio.h>
int main () {int length = 8265;int width = 0252;int height = 8292;
printf ("length = %d\n", length);printf ("width = %d\n", width);printf ("height = %d\n", height);
}
#include <stdio.h>
int main () {int length = 8265;int width = 0252;int height = 8292;
printf ("length = %d\n", length);printf ("width = %d\n", width);printf ("height = %d\n", height);
}
What is the Program Output ?
This program compiles fine
What is its output?
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 29
Surprised ?
Was this the programmer’s intent ?Was this the programmer’s intent ?
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 30
Numbers in C/C++/Java
In C/C++/Java numbers starting with 0 are octal numbers
This is a bad choice • Error-prone• Hard-to-read
There is no way to specify numbers in base 2• Very surprising giving the fact that C was meant for to be a low-level
systems language
Never use octal numbers
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 31
The Ada Version
with Text_IO;
procedure Main isLength : Integer := 8265;Width : Integer := 0252;Height : Integer := 8292;
beginText_IO . Put_Line (Length ' img);Text_IO . Put_Line (Width ' img);Text_IO . Put_Line (Height ' img);
end Main;
with Text_IO;
procedure Main isLength : Integer := 8265;Width : Integer := 0252;Height : Integer := 8292;
beginText_IO . Put_Line (Length ' img);Text_IO . Put_Line (Width ' img);Text_IO . Put_Line (Height ' img);
end Main;
No surprises in Ada
No surprises in Ada
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 32
Length : Integer := 8265;Width : Integer := 0252; -- regular decimal numberWidth_8 : Integer := 8#252#; -- octal number
B_Mask : Integer := 2#1100_1011#; -- binary number -- you can use “_” to separate digitsW_Mask : Integer := 16#FFF1_A4B0#; -- Hexadecimal number
Length : Integer := 8265;Width : Integer := 0252; -- regular decimal numberWidth_8 : Integer := 8#252#; -- octal number
B_Mask : Integer := 2#1100_1011#; -- binary number -- you can use “_” to separate digitsW_Mask : Integer := 16#FFF1_A4B0#; -- Hexadecimal number
Numbers in Ada
If no base is specified the number a decimal number
In Ada you can specify any base from 2 to 16 (for both integer and real
(floating point) numbers
Use the “_” to separate digits for clarity• 1_000_000_000
Lexical & Syntactic Pitfallsin C/C++/Java
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 34
#include <limits.h>
/* If *y is zero and x > 0 set *k to the biggest positive integer. * If *y is zero and x <=0 leave *k unchanged. * If *y is not zero set *k to be x divided by *y and increment *y by 1. */void check_divide (int *k, int x, int *y) {
if (*y = 0)if (x > 0)
*k = INT_MAX;else
*k = x / *y /* it is safe to divide by *y since it cannot be 0 */;*y++;
}
#include <limits.h>
/* If *y is zero and x > 0 set *k to the biggest positive integer. * If *y is zero and x <=0 leave *k unchanged. * If *y is not zero set *k to be x divided by *y and increment *y by 1. */void check_divide (int *k, int x, int *y) {
if (*y = 0)if (x > 0)
*k = INT_MAX;else
*k = x / *y /* it is safe to divide by *y since it cannot be 0 */;*y++;
}
Is the Following Code Correct ?
This program compiles fine, but has a number of problems. Which ones?
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 35
There are 4 Bugs
= versus ==• Using “=“ for assignment and “==“ for equality is a poor choice• Use a compiler that warns you when you use “=“ inside tests• This is a hard problem because C++ style encourages the use of “=“
inside tests:
Dangling else problem• Always bracket everything
Nested y++
Bad operator precedence *y++ means *(y++)• When in doubt use parentheses or separate tokens with white spaces ...
while (*s1++ = *s2++); while (*s1++ = *s2++);
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 36
What about Java?
= versus ==• This problem exists in Java for boolean,
but has been fixed for other data types
Dangling else problem• Problem is still there
Bad operator precedence *j++ means *(j++)
• No * operator in Java. This Problem has been solved
boolean safety_flag;boolean danger_flag;…if (safety_flag = danger_flag) {
sound_alarm ();}
boolean safety_flag;boolean danger_flag;…if (safety_flag = danger_flag) {
sound_alarm ();}
This is OK in Java but is often a bugThis is OK in Java but is often a bug
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 37
#include <limits.h>
/* If *y is null and x > 0 set *k to the biggest positive integer. * If *y is null and x <=0 leave *k unchanged. * If *y is non null set *k to be x divided by *y and increment *y by 1. */void check_divide (int *k, int x, int *y) {
if (*y == 0) {if ( x > 0)
*k = INT_MAX;}else {
*k = x / *y /* it is safe to divide by *y since it cannot be 0 */;(*y)++; /* or *y ++ */
}}
#include <limits.h>
/* If *y is null and x > 0 set *k to the biggest positive integer. * If *y is null and x <=0 leave *k unchanged. * If *y is non null set *k to be x divided by *y and increment *y by 1. */void check_divide (int *k, int x, int *y) {
if (*y == 0) {if ( x > 0)
*k = INT_MAX;}else {
*k = x / *y /* it is safe to divide by *y since it cannot be 0 */;(*y)++; /* or *y ++ */
}}
The Correct Version
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 38
-- If Y = 0 and X > 0 set K to the biggest positive integer.-- If Y = 0 and X <= 0 leave K unchanged.-- If Y /= 0 set K to be X divided by Y and increment Y by 1.
procedure Check_Divide (K : in out Integer; X : Integer; Y : in out Integer) isbegin
if Y = 0 thenif X > 0 then
K := Integer’Last; -- K is set to the largest Integer end if; else K := X / Y; -- it is safe to divide by Y since it cannot be 0
Y := Y + 1; end if;end Check_Divide;
-- If Y = 0 and X > 0 set K to the biggest positive integer.-- If Y = 0 and X <= 0 leave K unchanged.-- If Y /= 0 set K to be X divided by Y and increment Y by 1.
procedure Check_Divide (K : in out Integer; X : Integer; Y : in out Integer) isbegin
if Y = 0 thenif X > 0 then
K := Integer’Last; -- K is set to the largest Integer end if; else K := X / Y; -- it is safe to divide by Y since it cannot be 0
Y := Y + 1; end if;end Check_Divide;
Ada Solves all the Previous Pitfalls
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 39
-- If Y = 0 and X > 0 set K to the biggest positive integer.-- If Y = 0 and X <= 0 leave K unchanged.-- If Y /= 0 set K to be X divided by Y and increment Y by 1.
procedure Check_Divide (K : in out Integer; X : Integer; Y : in out Integer) isbegin
if Y = 0 and then X > 0 thenK := Integer’Last; -- K is set to the largest Integer
elsif Y /= 0 then K := X / Y; -- it is safe to divide by Y since it cannot be 0
Y := Y + 1;end if;
end Check_Divide;
-- If Y = 0 and X > 0 set K to the biggest positive integer.-- If Y = 0 and X <= 0 leave K unchanged.-- If Y /= 0 set K to be X divided by Y and increment Y by 1.
procedure Check_Divide (K : in out Integer; X : Integer; Y : in out Integer) isbegin
if Y = 0 and then X > 0 thenK := Integer’Last; -- K is set to the largest Integer
elsif Y /= 0 then K := X / Y; -- it is safe to divide by Y since it cannot be 0
Y := Y + 1;end if;
end Check_Divide;
Simpler Ada Version: "elsif" "and then"
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 40
Lexical & Syntactic Clarity in Ada
= means equality while := means assignment• If you use one instead of the other you get a compiler error
No dangling else in Ada•
• If it isn't then you get a compiler error
In Ada comments start with -- and go to the end of the line. No other type of comment
No ++ operators in Ada
No need for a * operator in Ada
if … then … -- Must be terminated by an end if;end if;
if … then … -- Must be terminated by an end if;end if;
Side Note on Ada Attributes
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 45
Attributes
Ada types, objects, and other entities can have attributes
An attribute is a property of the type, object, etc
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 46
Example of Scalar Attributes
Given T some scalar type (Integer, Float, etc)
Given X an object of type T
T ' First Smallest value in T
T ' Last Largest value in T
T ' image (X) String representation of X
In GNAT you can use X ' img instead of T ' image (X)
In GNAT you can use X ' img instead of T ' image (X)
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 47
procedure Check_Divide_And_Increment (K : in out Integer; X : Integer; Y : in out Integer) isbegin
if Y = 0 thenif X > 0 then
K := Integer’Last; -- K is set to the largest Integer end if; else K = X / Y; -- it is safe to divide by Y since it cannot be 0
Y := Y + 1; end if;end Checked_Divide;
procedure Check_Divide_And_Increment (K : in out Integer; X : Integer; Y : in out Integer) isbegin
if Y = 0 thenif X > 0 then
K := Integer’Last; -- K is set to the largest Integer end if; else K = X / Y; -- it is safe to divide by Y since it cannot be 0
Y := Y + 1; end if;end Checked_Divide;
Example of Integer ' Last
More C/C++/Java Syntactic Pitfalls
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 49
// If the signal ahead is clear then increase the speed.
void increase_speed_if_safe (int speed, int signal) {if (signal == CLEAR);
increase_speed ();}
// If the signal ahead is clear then increase the speed.
void increase_speed_if_safe (int speed, int signal) {if (signal == CLEAR);
increase_speed ();}
Is the Following Code Correct ?
This program compiles fine, but has a problem. Which one?
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 51
// If the signal ahead is clear then increase the speed.
void increase_speed_if_safe (int speed, int signal) {if (signal == CLEAR);
increase_speed ();}
// If the signal ahead is clear then increase the speed.
void increase_speed_if_safe (int speed, int signal) {if (signal == CLEAR);
increase_speed ();}
Be Careful of Spurious Semicolons
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 52
-- If the signal ahead is clear then increase the speed.
procedure increase_speed_if_safe (speed : integer; signal : integer) isbegin
if signal = CLEAR then increase_speed;
end if;end increase_speed_if_safe;
-- If the signal ahead is clear then increase the speed.
procedure increase_speed_if_safe (speed : integer; signal : integer) isbegin
if signal = CLEAR then increase_speed;
end if;end increase_speed_if_safe;
The Ada Version is Always Safe
If you writeif signal = CLEAR then ;
• You get a compiler error
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 53
More Bad Luck in C/C++/Java:Enumerations and Switch Statements
enum Alert_Type {LOW, MEDIUM, HIGH, VERY_HIGH};// C or C++. Java does not have enumerations, you have to use ints instead
void handle_alert (enum Alert_Type alert) {switch (alert) {
case LOW:activate_camera ();
case MEDIUM:send_guard ();
case HIGH:sound_alarm ();
}}
void process_alerts () {handle_alert (2);…
enum Alert_Type {LOW, MEDIUM, HIGH, VERY_HIGH};// C or C++. Java does not have enumerations, you have to use ints instead
void handle_alert (enum Alert_Type alert) {switch (alert) {
case LOW:activate_camera ();
case MEDIUM:send_guard ();
case HIGH:sound_alarm ();
}}
void process_alerts () {handle_alert (2);…
This program compiles fine, but has a number of problems. Which ones?
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 54
Defects in the Previous Code
void handle_alert (enum Alert_Type alert) {switch (alert) {
case LOW:activate_camera ();break;
case MEDIUM:send_guard ();break;
case HIGH:sound_alarm ();break;
case VERY_HIGH:alert_police ();break;
}}void process_alerts () {
handle_alert (HIGH);
void handle_alert (enum Alert_Type alert) {switch (alert) {
case LOW:activate_camera ();break;
case MEDIUM:send_guard ();break;
case HIGH:sound_alarm ();break;
case VERY_HIGH:alert_police ();break;
}}void process_alerts () {
handle_alert (HIGH);
Don't forget break statements
C/C++/Java do not check that you have treated all cases in the switch
case labels can be integers or (values of) any enum type, not just enum Alert_Type which in most cases will be an error
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 55
Ada is Safer (and Less Verbose)
type Alert_Type is (LOW, MEDIUM, HIGH, VERY_HIGH);
procedure Process_Alert (Alert : Alert_Type) isbegin
case Alert iswhen LOW =>
Activate_Camera;when MEDIUM =>
Send_Guard;when HIGH =>
Sound_Alarm;when VERY_HIGH =>
Alert_Police;end case;
end Process_Alert;
type Alert_Type is (LOW, MEDIUM, HIGH, VERY_HIGH);
procedure Process_Alert (Alert : Alert_Type) isbegin
case Alert iswhen LOW =>
Activate_Camera;when MEDIUM =>
Send_Guard;when HIGH =>
Sound_Alarm;when VERY_HIGH =>
Alert_Police;end case;
end Process_Alert;
No break statements
Ada will check that you have treated all cases in the case statement
You can only use an object of type Alert_Type
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 56
Combining Cases
procedure Process_Alert (Alert : Alert_Type) isbegin
case Alert iswhen LOW =>
Activate_Camera;when MEDIUM =>
Send_Guard;when HIGH
| VERY_HIGH =>Sound_Alarm;Alert_Police;
end case;end Process_Alert;
procedure Process_Alert (Alert : Alert_Type) isbegin
case Alert iswhen LOW =>
Activate_Camera;when MEDIUM =>
Send_Guard;when HIGH
| VERY_HIGH =>Sound_Alarm;Alert_Police;
end case;end Process_Alert;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 57
Using a Default Clause
procedure Process_Alert (Alert : Alert_Type) isbegin
case Alert iswhen LOW =>
Activate_Camera;when MEDIUM =>
Send_Guard;when others =>
Sound_Alarm;Alert_Police;
end case;end Process_Alert;
procedure Process_Alert (Alert : Alert_Type) isbegin
case Alert iswhen LOW =>
Activate_Camera;when MEDIUM =>
Send_Guard;when others =>
Sound_Alarm;Alert_Police;
end case;end Process_Alert;
Ada "when others" is equivalent to C/C++/Java "default", and takes away most of the benefit of the checking for all cases covered
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 58
Using a Range
procedure Process_Alert (Alert : Alert_Type) isbegin
case Alert iswhen LOW =>
Activate_Camera;when MEDIUM .. VERY_HIGH =>
Send_Guard;Sound_Alarm;Alert_Police;
end case;end Process_Alert;
procedure Process_Alert (Alert : Alert_Type) isbegin
case Alert iswhen LOW =>
Activate_Camera;when MEDIUM .. VERY_HIGH =>
Send_Guard;Sound_Alarm;Alert_Police;
end case;end Process_Alert;
A range is a set of ordered values• MEDIUM .. VERY_HIGH = MEDIUM, HIGH, VERY_HIGH
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 59
Enumeration Types in Ada
Enumerations are true types in Ada
In C enums are just integers
In C++ enums are implicitly converted to ints (not from ints)
type Alert is (LOW, MEDIUM, HIGH, VERY_HIGH);
procedure P (B : Integer) isA : Alert;
beginA := B;
type Alert is (LOW, MEDIUM, HIGH, VERY_HIGH);
procedure P (B : Integer) isA : Alert;
beginA := B; Compilation errorCompilation errorCompilation errorCompilation error
// C++enum Alert {LOW, MEDIUM, HIGH, VERY_HIGH};
int k = LOW; // accepted by C++Alert a = 1; // rejected by C++
// C++enum Alert {LOW, MEDIUM, HIGH, VERY_HIGH};
int k = LOW; // accepted by C++Alert a = 1; // rejected by C++
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 61
Ada Enumeration Types and Attributes
Alert_Type ' First LOW
Alert_Type ' Last VERY_HIGH
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 62
Predefined Enumerations in Ada
type Boolean is (False, True);
type Character is (…, 'a', 'b', 'c', …);
type Boolean is (False, True);
type Character is (…, 'a', 'b', 'c', …);
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 63
Predefined Enumerations: Examples
function Is_Letter (C : Character) return Boolean isbegin
return (C in 'a' .. 'z') or (C in 'A' .. 'Z');end Is_Letter;
function Is_Letter (C : Character) return Boolean isbegin
return (C in 'a' .. 'z') or (C in 'A' .. 'Z');end Is_Letter;
function Is_Arithmetic_Operator (C : Character) return Boolean isbegin
case C iswhen '+' | '-' | '*' | '/' =>
return True;when others =>
return False;end case;
end Is_Arithmetic_Operator;
function Is_Arithmetic_Operator (C : Character) return Boolean isbegin
case C iswhen '+' | '-' | '*' | '/' =>
return True;when others =>
return False;end case;
end Is_Arithmetic_Operator;
C/C++/Java Type System
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 71
What is a Type?
A type is characterized by:
The set of values an expression of that type can take
The operations that can be applied to those values
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 72
Pre-Defined and User-Defined Types
Some types can be pre-defined by the language• E.g. booleans, integers, characters, strings, etc
Pre-defined types come with pre-defined operations• E.g. for integers: additions, subtractions, etc.
Languages typically allow user-defined types and operations• User-defined operations are provided in the form of procedures and
functions
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 78
Typing Problems Common to C/C++/Java
typedef in C/C++ is a shorthand it does not define a new type
No user-defined types• Scalars (characters, integers, reals)• Pointers (e.g. there can only be a single pointer to an int type) • Arrays (e.g. there can only be a single array of int type)
Implicit conversions from integers to reals
Weak overflow semantics rules for signed integers
Missing types• Enumerations in Java (not full types in C/C++)• Character types in C/C++• Fixed points• Unsigned integers in Java• Pointers to functions in Java
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 80
C/C++ Example
The program to the left compiles fine
There is something wrong with it
What ?
typedef int Time;typedef int Distance;typedef int Speed; …const Speed SAFETY_SPEED = 120;…void increase_speed (Speed s);…void check_speed (Time t, Distance d) {
Speed s = d/t;if (s < SAFETY_SPEED)
increase_speed (t);}void perform_safety_checks () {
Time t = get_time ();Distance d = get_distance ();…check_speed (d, t);
}
typedef int Time;typedef int Distance;typedef int Speed; …const Speed SAFETY_SPEED = 120;…void increase_speed (Speed s);…void check_speed (Time t, Distance d) {
Speed s = d/t;if (s < SAFETY_SPEED)
increase_speed (t);}void perform_safety_checks () {
Time t = get_time ();Distance d = get_distance ();…check_speed (d, t);
}
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 82
What's Wrong with C/C++
Program compiles fine but has 2 serious flaws that go undetected
FLAW 1: • t is a Time• increase_speed() takes a Speed
parameter• Time and Speed are conceptually
different, they should not be mixed up
FLAW 2: • Distance and Time parameters have been
inverted• Time and Distance are conceptually
different, they should not be mixed up
C/C++ provide NO HELP to the programmer in detecting these mistakes
typedef int Time;typedef int Distance;typedef int Speed; …const Speed SAFETY_SPEED = 120;…void increase_speed (Speed s);…void check_speed (Time t, Distance d) {
Speed s = d/t;if (s < SAFETY_SPEED)
increase_speed (t);}void perform_safety_checks () {
Time t = get_time ();Distance d = get_distance ();…check_speed (d, t);
}
typedef int Time;typedef int Distance;typedef int Speed; …const Speed SAFETY_SPEED = 120;…void increase_speed (Speed s);…void check_speed (Time t, Distance d) {
Speed s = d/t;if (s < SAFETY_SPEED)
increase_speed (t);}void perform_safety_checks () {
Time t = get_time ();Distance d = get_distance ();…check_speed (d, t);
}
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 83
Things are Even Worse in Java
There are no typedef in Java
Everything must be an int
typedef are useful for documentation purposes
typedef could be used to perform sanity checks during code walkthroughs or with simple tools
This problem is particularly severe in Java given that many API calls have several indistinguishable int parameters:
• AdjustmentEvent (Adjustable source, int id, int type, int value)
final int SAFETY_SPEED = 120;…void check_speed (int t, int d) {
int s = d/t;if (s < SAFETY_SPEED)
increase_speed (t);}void increase_speed (int s) { … }void perform_safety_checks () {
int t = get_time ();int d = get_distance ();…check_speed (d, t);
}
final int SAFETY_SPEED = 120;…void check_speed (int t, int d) {
int s = d/t;if (s < SAFETY_SPEED)
increase_speed (t);}void increase_speed (int s) { … }void perform_safety_checks () {
int t = get_time ();int d = get_distance ();…check_speed (d, t);
}
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 84
What About Ada?
You can write the same buggy code in Ada, but …
… Ada has two lines of defense that do not exist in C/C++ or Java to protect the programmer• User defined types• Parameter associations
-- Buggy code. DON'T write this
SAFETY_SPEED : constant Integer := 120;…procedure Increase_Speed (S : Integer);…procedure Check_Speed (T : Integer; D : Integer) is
S : Integer := D / T;begin
if S < SAFETY_SPEED thenIncrease_Speed (T);
end if;end Check_Speed;
procedure Perform_Safety_Checks isT : Integer := Get_Time;D : Integer := Get_Distance;
begin…Check_Speed (D, T);
end Perform_Safety_Checks;
-- Buggy code. DON'T write this
SAFETY_SPEED : constant Integer := 120;…procedure Increase_Speed (S : Integer);…procedure Check_Speed (T : Integer; D : Integer) is
S : Integer := D / T;begin
if S < SAFETY_SPEED thenIncrease_Speed (T);
end if;end Check_Speed;
procedure Perform_Safety_Checks isT : Integer := Get_Time;D : Integer := Get_Distance;
begin…Check_Speed (D, T);
end Perform_Safety_Checks;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 85
Defining New Types in Ada
Users can define their own types in Ada
In C/C++/Java users can only define struct/union/class types• No user-defined scalar, pointer or array types
-- Example of integer type definition in Ada
type Time is range 0 .. 3_600;
type Distance is range 0 .. 1_000;
type Speed is range 0 .. 4_000;
-- Example of integer type definition in Ada
type Time is range 0 .. 3_600;
type Distance is range 0 .. 1_000;
type Speed is range 0 .. 4_000;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 86
User Defined Integer Types in Ada
Each user defined integer type introduces a new type
This new type is NOT a synonym of Integer
Each user defined integer type gives its bounds, i.e. the values any object of this type can take
• Time ' First = 0• Time ' Last = 3_600
type Time is range 0 .. 3_600;
type Distance is range 0 .. 1_000;
type Speed is range 0 .. 4_000;
type Time is range 0 .. 3_600;
type Distance is range 0 .. 1_000;
type Speed is range 0 .. 4_000;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 87
Ada is Strongly Typed (1 of 2)
When you define the proper types the Ada compiler catches the errors
To mix different types you must use explicit conversions in Ada
D is of type Distance, T is of type Time, S is of type Speed
• Only objects of the same type can be mixed together in this fashion
Increase_Speed is expecting a Speed parameter not a Time
type Time is range 0 .. 3_600;type Distance is range 0 .. 1_000;type Speed is range 0 .. 4_000;
SAFETY_SPEED : constant Speed := 120;
procedure Increase_Speed (S : Speed);
procedure Check_Speed (T : Time; D : Distance) isS : Speed := D / T;
beginif S < SAFETY_SPEED then
Increase_Speed (T);end if;
end Check_Speed;…
type Time is range 0 .. 3_600;type Distance is range 0 .. 1_000;type Speed is range 0 .. 4_000;
SAFETY_SPEED : constant Speed := 120;
procedure Increase_Speed (S : Speed);
procedure Check_Speed (T : Time; D : Distance) isS : Speed := D / T;
beginif S < SAFETY_SPEED then
Increase_Speed (T);end if;
end Check_Speed;…
Compilation Compilation errorerror
Compilation Compilation errorerror
Compilation Compilation errorerror
Compilation Compilation errorerror
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 88
Ada is Strongly Typed (2 of 2)
Parameters switched
type Time is range 0 .. 3_600;type Distance is range 0 .. 1_000;type Speed is range 0 .. 4_000;…procedure Check_Speed (T : Time; D : Distance); …procedure Perform_Safety_Checks is
T : Time := Get_Time;D : Distance := Get_Distance;
begin…Check_Speed (D, T);
end Perform_Safety_Checks;
type Time is range 0 .. 3_600;type Distance is range 0 .. 1_000;type Speed is range 0 .. 4_000;…procedure Check_Speed (T : Time; D : Distance); …procedure Perform_Safety_Checks is
T : Time := Get_Time;D : Distance := Get_Distance;
begin…Check_Speed (D, T);
end Perform_Safety_Checks;
Compilation Compilation errorerror
Compilation Compilation errorerror
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 89
The Correct Ada Version
You must convert D and T to Integer to perform the division
And then convert the result to type Speed
type Time is range 0 .. 3_600;type Distance is range 0 .. 1_000;type Speed is range 0 .. 4_000;
SAFETY_SPEED : constant Speed := 120;procedure Increase_Speed (S : Speed);
procedure Check_Speed (T : Time; D : Distance) isS : Speed := Speed ( Integer(D) / Integer (T));
beginif S < SAFETY_SPEED then
Increase_Speed (S);end if;
end Check_Speed;procedure Perform_Safety_Checks is
T : Time := Get_Time;D : Distance := Get_Distance;
begin…Check_Speed (T, D);
end Perform_Safety_Checks;
type Time is range 0 .. 3_600;type Distance is range 0 .. 1_000;type Speed is range 0 .. 4_000;
SAFETY_SPEED : constant Speed := 120;procedure Increase_Speed (S : Speed);
procedure Check_Speed (T : Time; D : Distance) isS : Speed := Speed ( Integer(D) / Integer (T));
beginif S < SAFETY_SPEED then
Increase_Speed (S);end if;
end Check_Speed;procedure Perform_Safety_Checks is
T : Time := Get_Time;D : Distance := Get_Distance;
begin…Check_Speed (T, D);
end Perform_Safety_Checks;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 90
But What About?
How do you know it wasSafe_Copy (X, Y)
and notSafe_Copy (Y, X)
You don't. That's why Ada provides name parameters
type A_Type is …;
procedure Safe_Copy (Source : A_Type; Target : A_Type);
procedure Try isX : A_Type := …;Y : A_Type := …;
beginSafe_Copy (X, Y);…
end Try;
type A_Type is …;
procedure Safe_Copy (Source : A_Type; Target : A_Type);
procedure Try isX : A_Type := …;Y : A_Type := …;
beginSafe_Copy (X, Y);…
end Try;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 91
Ada has Named Parameters
type A_Type is …;
procedure Safe_Copy (Source : A_Type; Target : A_Type);
procedure Try isX : A_Type := …;Y : A_Type := …;
beginSafe_Copy (Source => X, Target => Y);…
end Try;
type A_Type is …;
procedure Safe_Copy (Source : A_Type; Target : A_Type);
procedure Try isX : A_Type := …;Y : A_Type := …;
beginSafe_Copy (Source => X, Target => Y);…
end Try;
Named parameterNamed parameterNamed parameterNamed parameter
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 92
Avoiding Parameter Confusion in Ada
Summary: Two lines of defense
User defined types
Named parameters
Example of C/C++/Java Type System Weakness
Signed Integer Overflow Semantics
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 94
Overflow in C/C++/Java
In C/C++ signed integer overflow is undefined, anything can happen• All known implementations "wrap around"
In Java wrap around semantics are part of the language
#include <limits.h>
void compute () {int k = INT_MAX;
k = k + 1;}
#include <limits.h>
void compute () {int k = INT_MAX;
k = k + 1;}
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 95
Overflow in Ada
EVERY time there is an integer overflow in Ada an exception is raised
procedure Compute isK : Integer := Integer'Last;
beginK := K + 1;
end Compute;
procedure Compute isK : Integer := Integer'Last;
beginK := K + 1;
end Compute;
Exception raised Exception raised at execution at execution
timetime
Exception raised Exception raised at execution at execution
timetime
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 96
Example: Overflow in Action in Ada
In GNAT you have to use the switch -gnato to ask for integer overflow checking
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 97
The Pernicious Effects of Wrap-Around Semantics: A Java Example
The program to the left compiles fine, and runs …
… But there is something wrong with it. What ?
final int RADIO_PORT = …;
void open (int port) {…}void send (int port, byte data) {…}void close (int port) {…}
void send_bytes (byte first_byte, byte last_byte) {open (RADIO_PORT);for (byte b = first_byte; b <= last_byte; b++) {
send (RADIO_PORT, b);}close (RADIO_PORT);
}
final int RADIO_PORT = …;
void open (int port) {…}void send (int port, byte data) {…}void close (int port) {…}
void send_bytes (byte first_byte, byte last_byte) {open (RADIO_PORT);for (byte b = first_byte; b <= last_byte; b++) {
send (RADIO_PORT, b);}close (RADIO_PORT);
}
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 98
Infinite Loop when last_byte == 127
Two problems:
Wrap around semantics of type byte• When last_byte = b = 127 we execute the loop, we do b++ and b wraps to -128
There is no real for loop instruction in C/C++/Javafor (x; y; z) {…}
• Meansx; while (y) { …; z; }
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 99
The Ada Version is Safe
The code on the left runs fine
There is a true for loop in Ada (unlike C/C++/Java)
type Port is range 0 .. 255;type Byte is range -128 .. 127;
RADIO_PORT : constant Port := …;
procedure Open (P : Port);procedure Send (P : Port; B : Byte);procedure Close (P : Port);
procedure Send_Bytes (First : Byte; Last : Byte) isbegin
Open (RADIO_PORT);for B in First .. Last loop
Send (RADIO_PORT, B);end loop;Close (RADIO_PORT);
end Send_Bytes;
type Port is range 0 .. 255;type Byte is range -128 .. 127;
RADIO_PORT : constant Port := …;
procedure Open (P : Port);procedure Send (P : Port; B : Byte);procedure Close (P : Port);
procedure Send_Bytes (First : Byte; Last : Byte) isbegin
Open (RADIO_PORT);for B in First .. Last loop
Send (RADIO_PORT, B);end loop;Close (RADIO_PORT);
end Send_Bytes;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 100
Checks and Overflows Summary
In Ada• Every integer overflow raises an exception in Ada• Every division by zero raises an exception in Ada• Every array index overflow raises an exception in Ada• Etc.• You can disable all the Ada checks for deployment if you wish
In Java• Java adopted most of the Ada checks except for integer overflow which
wraps around in Java• Cannot disable checks in Java
In C/C++• No checks
Side Notes on Ada Types
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 102
Unsigned Integers
Ada has the choice of two sorts of integer types:• Signed integers (an exception is raised in case of an overflow)• Unsigned integers (wrap-around semantics)
-- Example of unsigned integers in Ada
procedure Try istype Hash_Index is mod 1023;H : Hash_Index := 1022;
beginH := H + 1;-- H is equal to zero here
end Try;
-- Example of unsigned integers in Ada
procedure Try istype Hash_Index is mod 1023;H : Hash_Index := 1022;
beginH := H + 1;-- H is equal to zero here
end Try;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 103
Subtypes
Sometimes you want to add additional constraints to a type without creating a new type
Ada provides the notion of subtype for that
-- Example of unsigned integers in Ada
procedure Try istype Day is (Mon, Tue, Wed, Thu, Fri, Sat, Sun);subtype Working_Day is Day range Mon .. Fri;
D : Day := Mon;WD : Working_Day;
beginWD := D; -- This is OKWD := Sun; -- This raises an exception
end Try;
-- Example of unsigned integers in Ada
procedure Try istype Day is (Mon, Tue, Wed, Thu, Fri, Sat, Sun);subtype Working_Day is Day range Mon .. Fri;
D : Day := Mon;WD : Working_Day;
beginWD := D; -- This is OKWD := Sun; -- This raises an exception
end Try;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 104
Predefined Ada Subtypes
subtype Natural is Integer range 0 .. Integer ’ Last;
subtype Positive is Natural range 1 .. Natural ’ Last;
subtype Natural is Integer range 0 .. Integer ’ Last;
subtype Positive is Natural range 1 .. Natural ’ Last;
Exceptions in Ada
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 106
When a Check Fails an Exception is Raised in Ada
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 107
Ada Predefined Exceptions
The following predefined exceptions are raised when something goes wrong in an Ada program
Constraint_ErrorConstraint_Errorinteger overflow, computation error (divide by zero), array index out of range, null pointer dereferencing, …
Storage_ErrorStorage_Error no more memory available
Program_ErrorProgram_Errorfundamental program error (e.g. end of function with no return statement)
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 108
Creating Your Own Exceptions
procedure Checks isInternal_Error : Exception;
procedure Foo isbegin
raise Internal_Error;end Foo;
procedure Bar isbegin
Foo;end Bar;
begin -- of ChecksBar;
end Checks;
procedure Checks isInternal_Error : Exception;
procedure Foo isbegin
raise Internal_Error;end Foo;
procedure Bar isbegin
Foo;end Bar;
begin -- of ChecksBar;
end Checks;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 109
What Happens at Execution Time?
procedure Checks isInternal_Error : Exception;
procedure Foo isbegin
raise Internal_Error;end Foo;
procedure Bar isbegin
Foo;end Bar;
begin -- of ChecksBar;
end Checks;
procedure Checks isInternal_Error : Exception;
procedure Foo isbegin
raise Internal_Error;end Foo;
procedure Bar isbegin
Foo;end Bar;
begin -- of ChecksBar;
end Checks;
11
22
ExceptionExceptionraisedraised33
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 110
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 111
Displaying the Traceback(How you Got There)
with Ada.Exceptions; use Ada.Exceptions;with GNAT.Traceback.Symbolic; use GNAT.Traceback.Symbolic;with Text_IO; use Text_IO;
procedure Checks isInternal_Error : Exception;
procedure Foo isbegin
raise Internal_Error;end Foo;
procedure Bar isbegin
Foo;end Bar;
begin -- of ChecksBar;
exceptionwhen E : others =>
Put_Line ("Raised exception : " & Exception_Name (E)); Put_Line (Symbolic_Traceback (E));end Checks;
with Ada.Exceptions; use Ada.Exceptions;with GNAT.Traceback.Symbolic; use GNAT.Traceback.Symbolic;with Text_IO; use Text_IO;
procedure Checks isInternal_Error : Exception;
procedure Foo isbegin
raise Internal_Error;end Foo;
procedure Bar isbegin
Foo;end Bar;
begin -- of ChecksBar;
exceptionwhen E : others =>
Put_Line ("Raised exception : " & Exception_Name (E)); Put_Line (Symbolic_Traceback (E));end Checks;
Exception HandlerException Handler
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 112
-cargs: Compiler arguments:-g: debugging on-gnatl: print out a program listing-gnato: overflow checks on
-cargs: Compiler arguments:-g: debugging on-gnatl: print out a program listing-gnato: overflow checks on
-bargs: Program binder arguments:-E: give exception tracebacks
-bargs: Program binder arguments:-E: give exception tracebacks
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 113
What Happens at Execution Time
with Ada.Exceptions; use Ada.Exceptions;with GNAT.Traceback.Symbolic; use GNAT.Traceback.Symbolic;with Text_IO; use Text_IO;
procedure Checks isInternal_Error : Exception;
procedure Foo isbegin
raise Internal_Error;end Foo;
procedure Bar isbegin
Foo;end Bar;
begin -- of ChecksBar;
exceptionwhen E : others =>
Put_Line ("Raised exception : " & Exception_Name (E)); Put_Line (Symbolic_Traceback (E));end Checks;
with Ada.Exceptions; use Ada.Exceptions;with GNAT.Traceback.Symbolic; use GNAT.Traceback.Symbolic;with Text_IO; use Text_IO;
procedure Checks isInternal_Error : Exception;
procedure Foo isbegin
raise Internal_Error;end Foo;
procedure Bar isbegin
Foo;end Bar;
begin -- of ChecksBar;
exceptionwhen E : others =>
Put_Line ("Raised exception : " & Exception_Name (E)); Put_Line (Symbolic_Traceback (E));end Checks;
aa
bb
dd
cc
ee
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 114
Catching a Predefined Exception
with Text_IO; use Text_IO;procedure Checks is A : Integer := Integer ’ First;begin A := A - 1;exception when Constraint_Error => Put_Line (“Overflow occurred”);end Checks;
with Text_IO; use Text_IO;procedure Checks is A : Integer := Integer ’ First;begin A := A - 1;exception when Constraint_Error => Put_Line (“Overflow occurred”);end Checks;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 115
Catching Your Own Exceptionswith Text_IO; use Text_IO;procedure Checks is
Internal_Error : Exception;
procedure Foo isbegin
raise Internal_Error;end Foo;
procedure Bar isbegin
Foo;end Bar;
begin -- of ChecksBar;
exceptionwhen Internal_Error =>
Put_Line (“problem occurred”); when others => Put_Line (“some other exception”); end Checks;
with Text_IO; use Text_IO;procedure Checks is
Internal_Error : Exception;
procedure Foo isbegin
raise Internal_Error;end Foo;
procedure Bar isbegin
Foo;end Bar;
begin -- of ChecksBar;
exceptionwhen Internal_Error =>
Put_Line (“problem occurred”); when others => Put_Line (“some other exception”); end Checks;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 116
procedure Checks is…
begin -- of Checks:::::::::::::::
end Checks;
procedure Checks is…
begin -- of Checks:::::::::::::::
end Checks;
Catching an Exception Where You Want
to catch someto catch someexception in a regionexception in a regionof code without exitingof code without exitingfrom the subprogram from the subprogram you can use a declare blockyou can use a declare block
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 117
procedure Calc (A, B : Float) is C, D : Float;begin
…
declareOld_C : Float := C;
begin C := A * B; D := C ** 2; exception when Constraint_Error => C := Old_C;
D := 0.0; end;
…
end Calc;
procedure Calc (A, B : Float) is C, D : Float;begin
…
declareOld_C : Float := C;
begin C := A * B; D := C ** 2; exception when Constraint_Error => C := Old_C;
D := 0.0; end;
…
end Calc;
Example of a Declare Block
Array Pitfalls in C
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 129
Arrays in Ada
Ada has real arrays (1-dimensional and multi-dimensional)
Ada array can have its size determined at run-time• Local variable length arrays are allowed in the latest C standard (C99)
Ada array bounds can be arbitrary, lower bound does not have to start at 0
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 130
One of a Kind Arrays
In Ada Arrays can have arbitrary bounds
The bounds can be dynamic values
procedure Compute (N : Integer) is
A : array (1 .. N) of Float;
begin…
end Compute;
procedure Compute (N : Integer) is
A : array (1 .. N) of Float;
begin…
end Compute;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 131
procedure Compute (N : Integer) istype Arr is array (Integer range <>) of Float;
A : Arr (1 .. N) := (others => 9);B : Arr := A;C : Arr (11 .. 20) := (1, 2, others => 0);
beginC := A;C (15 .. 18) := A (5 .. 8);
end Compute;
procedure Compute (N : Integer) istype Arr is array (Integer range <>) of Float;
A : Arr (1 .. N) := (others => 9);B : Arr := A;C : Arr (11 .. 20) := (1, 2, others => 0);
beginC := A;C (15 .. 18) := A (5 .. 8);
end Compute;
Typed Arrays
B takes its bounds from A
If C'Length /= A'Length then Constraint_Error is raised
If A'Last < 8 then Constraint_Error is raised
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 132
Arrays in Ada are Safe
If you try to index a non-existent arry position, a Constraint_Error exception is raised
procedure Checks isA : array (1 .. 100) of Integer;
beginA (101) := 1;
end Checks;
procedure Checks isA : array (1 .. 100) of Integer;
beginA (101) := 1;
end Checks;Exception raisedException raised
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 133
Example of 1-Dim Array Attributes
Given A some array object• A : array (10 .. 99) of Integer;
A ' First 10
A ' Last 99
A ' Length 90
A ' Range 10 .. 99
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 134
procedure Calc istype Vector is array (Natural range <>) of Float;
function Max (V : Vector) return Float is M : Float := Float ’ First;
begin for K in V ’ Range loop if V (K) > M then M := V (K); end if; end loop; return M;
end Max;
V1 : Vector := (1.0, 2.0, 3.0); -- V'First = 0 and V'Last = 2V2 : Vector (1 .. 100) := (1.0, 2.0, others => 5.0);
X : Float := Max (V1); -- X = 3.0Y : Float := Max (V2); -- Y = 5.0
begin…
end Calc;
procedure Calc istype Vector is array (Natural range <>) of Float;
function Max (V : Vector) return Float is M : Float := Float ’ First;
begin for K in V ’ Range loop if V (K) > M then M := V (K); end if; end loop; return M;
end Max;
V1 : Vector := (1.0, 2.0, 3.0); -- V'First = 0 and V'Last = 2V2 : Vector (1 .. 100) := (1.0, 2.0, others => 5.0);
X : Float := Max (V1); -- X = 3.0Y : Float := Max (V2); -- Y = 5.0
begin…
end Calc;
Ada Arrays are Powerful: No Need to Pass Array Bounds as in C/C++/Java
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 135
Ada String Predefined Array Type
type String is array (Positive range <>) of Character;
R : String (1 .. 10);
S : String := (‘H’, ‘e’, ‘l’, ‘l’, ‘o’);T : String := “Hello”;
Q : String := S & “ “ & T & “ you”;-- Q = "Hello Hello you"
type String is array (Positive range <>) of Character;
R : String (1 .. 10);
S : String := (‘H’, ‘e’, ‘l’, ‘l’, ‘o’);T : String := “Hello”;
Q : String := S & “ “ & T & “ you”;-- Q = "Hello Hello you"
Records and Pointers in Ada
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 137
Record Types
type Date is record Day : Positive range 1 .. 31; Month : Positive range 1 .. 12; Year : Integer;end record;
D : Date := (3, 9, 1975);
A : Date := (Day => 31, Month => 12, Year => 1999);
B : Date := A;
Y : Integer := B . Year;
type Date is record Day : Positive range 1 .. 31; Month : Positive range 1 .. 12; Year : Integer;end record;
D : Date := (3, 9, 1975);
A : Date := (Day => 31, Month => 12, Year => 1999);
B : Date := A;
Y : Integer := B . Year;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 138
type Node;type Node_Ptr is access Node;
type Node is record D : Date := (1, 1, 1900); Next : Node_Ptr;end record;
P1 : Node_Ptr := new Node;P2 : Node_Ptr := new Node ’ ((3, 9, 1975), P1);
type Node;type Node_Ptr is access Node;
type Node is record D : Date := (1, 1, 1900); Next : Node_Ptr;end record;
P1 : Node_Ptr := new Node;P2 : Node_Ptr := new Node ’ ((3, 9, 1975), P1);
Memory
1
1
1900
null
3
9
1975
Pointers and Records
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 139
N : Node := ((31, 12, 1999), null);
P3 : Node_Ptr := new Node ’ (N);
Memory
31
12
1999
null
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 140
Accessing Record Fields: A Simple Rule
If P is a pointer to a record then
P.all points to the WHOLE record
P.Field points to Field in the record
Note: P.Field is the same as P.all.Field
type Node is record D : Date := (1, 1, 1900); Next : Node_Ptr;end record;
P : Node_Ptr := new Node;
A_Date : Date := P.D;A_Node : Node_Ptr := P.Next;
type Node is record D : Date := (1, 1, 1900); Next : Node_Ptr;end record;
P : Node_Ptr := new Node;
A_Date : Date := P.D;A_Node : Node_Ptr := P.Next;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 141
Parametrized Records: Discriminants
type Q_Array (Positive range <>) of Integer;
type Queue (Max_Size : Positive) is record First : Positive := 1; Last : Positive := 1; Size : Natural := 0; Q : Q_Array (1 .. Max_Size);end record;
X : Queue (4); -- X.Max_Size = 4
Y : Queue;
type Q_Array (Positive range <>) of Integer;
type Queue (Max_Size : Positive) is record First : Positive := 1; Last : Positive := 1; Size : Natural := 0; Q : Q_Array (1 .. Max_Size);end record;
X : Queue (4); -- X.Max_Size = 4
Y : Queue; Compilation ErrorCompilation ErrorValue for Max_Size missingValue for Max_Size missing
Parameter Passing in C, Java and Ada
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 147
Three Parameter Passing Modes in Adaprocedure Open_File (X : String);
procedure Open_File (X : in String); in
• It's the default mode, the in can be omitted
• Inside the procedure or function X is a constant initialized by the value of the actual parameter
• Functions can only have parameters of mode i
function Log (X : Float) return Float;
function Log (X : in Float) return Float;
procedure Increment (X : in out Float);
in out
• Inside the procedure X is a variable initialized by the value of the actual parameter
• The actual parameter is updated with the last value of X when the procedure terminates.
procedure Copy (Y : Float; X : out Float);
out
• Inside the procedure X is an uninitialized variable
• The actual parameter is updated with the last value of X when the procedure terminates
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 148
Example: Mode "in"
function Log (X : Float) return Float isbegin
X := 1.0;…
end Log;
function Log (X : Float) return Float isbegin
X := 1.0;…
end Log;
Compilation errorCompilation errorX is a constant inside LogX is a constant inside Log
Compilation errorCompilation errorX is a constant inside LogX is a constant inside Log
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 149
procedure A_Test is
procedure Increment (X : in out Float) isbegin
X := X + 1.0;end Increment;
Value : Float := 9.0;
begin-- Value = 9.0 hereIncrement (Value);-- Value = 10.0 here
end A_Test;
procedure A_Test is
procedure Increment (X : in out Float) isbegin
X := X + 1.0;end Increment;
Value : Float := 9.0;
begin-- Value = 9.0 hereIncrement (Value);-- Value = 10.0 here
end A_Test;
Example: Mode "in out"
NoteNote: In Ada You can nest : In Ada You can nest functions & proceduresfunctions & procedures
NoteNote: In Ada You can nest : In Ada You can nest functions & proceduresfunctions & procedures
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 150
procedure A_Test is
procedure Copy (Y : Float; X : out Float) isbegin
X := Y;end Copy;
Value : Float;
begin-- Value is uninitialized hereCopy (10.0, Value);-- Value = 10.0 here
end A_Test;
procedure A_Test is
procedure Copy (Y : Float; X : out Float) isbegin
X := Y;end Copy;
Value : Float;
begin-- Value is uninitialized hereCopy (10.0, Value);-- Value = 10.0 here
end A_Test;
Example: Mode "out"
Ada Offers a Comprehensive Scheme for Safe Low-Level Programming
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 152
PSW Example
Represent the following program status word (PSW):
PSW is 24 bits
Bits 0 to 7 contain a 7 bit system mask
Bits 12 to 15 contain a 4 digit protection key
Bits 20 to 24 contain the status flags of the machine for the program• The fours flags are called: A, M, W and P
All other bits are unused
System Mask unused Protection Key unused Machine
State0 7 8 11 12 15 16 19 20 23
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 153
The PSW Type in Ada
type State is (A, M, W, P);type Byte_Mask is array (0 .. 7) of Boolean;type State_Mask is array (State) of Boolean;
type Program_Status_Word is recordSystem_Mask : Byte_Mask;Protection_Key : Integer range 0 .. 15;Machine_State : State_Mask;
end record;
for Program_Status_Word use recordSystem_Mask at 0 range 0 .. 7;Protection_Key at 0 range 12 .. 15;Machine_State at 0 range 20 .. 23;
end record;
for Program_Status_Word ' Size use 3 * System.Storage_Unit;
type State is (A, M, W, P);type Byte_Mask is array (0 .. 7) of Boolean;type State_Mask is array (State) of Boolean;
type Program_Status_Word is recordSystem_Mask : Byte_Mask;Protection_Key : Integer range 0 .. 15;Machine_State : State_Mask;
end record;
for Program_Status_Word use recordSystem_Mask at 0 range 0 .. 7;Protection_Key at 0 range 12 .. 15;Machine_State at 0 range 20 .. 23;
end record;
for Program_Status_Word ' Size use 3 * System.Storage_Unit;
System Mask unused Protection Key unused Machine
State0 7 8 11 12 15 16 19 20 23
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 154
Accessing PSW Fields in Ada is …
Simple
Safe
Efficient
PSW : Program_Status_Word := …;
Key : Integer := PSW . Protection_Key;M_State : Boolean := PSW . Machine_State (M);Mask_3 : Boolean := PSW . System_Mask (3);
PSW : Program_Status_Word := …;
Key : Integer := PSW . Protection_Key;M_State : Boolean := PSW . Machine_State (M);Mask_3 : Boolean := PSW . System_Mask (3);
…type Program_Status_Word is record
System_Mask : Byte_Mask;Protection_Key : Integer range 0 .. 15;Machine_State : State_Mask;
end record;…
…type Program_Status_Word is record
System_Mask : Byte_Mask;Protection_Key : Integer range 0 .. 15;Machine_State : State_Mask;
end record;…
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 155
There is more in Ada to help with safe and efficient
low-level programming than just the previous example
Summary: Better Safe than Sorry
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 161
Language Safety and Security
C++C++CC JavaJava AdaAdaunsafeunsafe safesafeassemblyassembly
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 162
Summary
A good programming language • Encourages the writing of correct software• Helps in detecting errors
C/C++/Java• Encourage the writing of concise code not correct software• C/C++ provide no help in detecting errors• Java provides some help
Ada (and other languages such as Eiffel)• Encourage the writing of correct software• Provide help in detecting errors