❌ About FreshRSS

Normal view

There are new articles available, click to refresh the page.
Before yesterdayAda – The Craft of Coding

Ada is defensive by default

By: spqr
4 February 2022 at 20:40

The type system of Ada is not merely strongly typed, but sometimes referred to as being super-strongly typed, because it does not allow for any level of implicit conversions. None. Consider the following code in C:

#include <stdio.h>
int main(void) {
   float e;
   int a;
   e = 4.7631;
   a = e;
   printf("%d\n", a);
   return 0;
}

This is valid code that will compile, run and produce the expected result – the result printed out is 4. C has no issues performing an implicit conversion. Ada on the other hand won’t even compile similar code. Here is the Ada equivalent:

with ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure testtyped is
    a : integer;
    e : float;
begin
   e := 4.7631;
   a := e;
   put(a);
end testtyped;

When an attempt is made to compile this, the following error will occur:

testtyped.adb:8:09: expected type "Standard.Integer"
testtyped.adb:8:09: found type "Standard.Float"

The problem here is that a and e are clearly not the same. Instead, one has to explicitly convert between types, which promotes good design by preventing the mixing of types. In this case, Line 9 in the above code becomes:

a := integer(e);

Also at run-time, errors such as illegal memory accesses, buffer overflows, range violations, off-by-one errors, and array access are tested. These errors can then be handled safely instead of the way languages like C do. For example, consider the following C code:

#include <stdio.h>
int main(void) {
   int x[100];
   x[101] = 1;
   printf("%d\n", x[101]);
   return 0;
}

Again, this is valid code that will compile, run and produce unexpected results. A value is actually stored outside the array x. Consider the same code written in Ada:

with ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure testarrOOB is
    x : array (1..100) of integer;
begin
   x(101) := 1;
   put(x(101));
end testarrOOB;

Compiling the program will result in the following warnings:

testarroob.adb:6:06: warning: value not in range of subtype of "Standard.Integer" defined at line 4
testarroob.adb:6:06: warning: "Constraint_Error" will be raised at run time
testarroob.adb:7:10: warning: value not in range of subtype of "Standard.Integer" defined at line 4
testarroob.adb:7:10: warning: "Constraint_Error" will be raised at run time

It does produce an executable, but running the executable results in an exception being triggered:

raised CONSTRAINT_ERROR : testarroob.adb:6 range check failed

Why is this important? Because in real-time systems, errors such as this have to be avoided. Now ask yourself why it is possible the F-35 code written in C++ does work as intended.

Ada is defensive by default

By: spqr
4 February 2022 at 20:40

The type system of Ada is not merely strongly typed, but sometimes referred to as being super-strongly typed, because it does not allow for any level of implicit conversions. None. Consider the following code in C:

#include <stdio.h>
int main(void) {
   float e;
   int a;
   e = 4.7631;
   a = e;
   printf("%d\n", a);
   return 0;
}

This is valid code that will compile, run and produce the expected result – the result printed out is 4. C has no issues performing an implicit conversion. Ada on the other hand won’t even compile similar code. Here is the Ada equivalent:

with ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure testtyped is
    a : integer;
    e : float;
begin
   e := 4.7631;
   a := e;
   put(a);
end testtyped;

When an attempt is made to compile this, the following error will occur:

testtyped.adb:8:09: expected type "Standard.Integer"
testtyped.adb:8:09: found type "Standard.Float"

The problem here is that a and e are clearly not the same. Instead, one has to explicitly convert between types, which promotes good design by preventing the mixing of types. In this case, Line 9 in the above code becomes:

a := integer(e);

Also at run-time, errors such as illegal memory accesses, buffer overflows, range violations, off-by-one errors, and array access are tested. These errors can then be handled safely instead of the way languages like C do. For example, consider the following C code:

#include <stdio.h>
int main(void) {
   int x[100];
   x[101] = 1;
   printf("%d\n", x[101]);
   return 0;
}

Again, this is valid code that will compile, run and produce unexpected results. A value is actually stored outside the array x. Consider the same code written in Ada:

with ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure testarrOOB is
    x : array (1..100) of integer;
begin
   x(101) := 1;
   put(x(101));
end testarrOOB;

Compiling the program will result in the following warnings:

testarroob.adb:6:06: warning: value not in range of subtype of "Standard.Integer" defined at line 4
testarroob.adb:6:06: warning: "Constraint_Error" will be raised at run time
testarroob.adb:7:10: warning: value not in range of subtype of "Standard.Integer" defined at line 4
testarroob.adb:7:10: warning: "Constraint_Error" will be raised at run time

It does produce an executable, but running the executable results in an exception being triggered:

raised CONSTRAINT_ERROR : testarroob.adb:6 range check failed

Why is this important? Because in real-time systems, errors such as this have to be avoided. Now ask yourself why it is possible the F-35 code written in C++ does work as intended.

spqr

❌
❌