It is time to get serious about strong data types - one of the key strengths of Ada. We got a flavor of this with Strings of fixed length. In this chapter new data types which are application appropriate will be explored. In particular mechanisms to protect variables of strong data types will be studied.
7.1 Learning Objectives
Strong Real data types.
Checking values against type specifications
Fixed Point data types
Exceptions and their handling
Record types
7.2 Projectlet - foods
Taking advantage of Strong Typing starts with application meaningful data types.
A base type Glycemic_Index is defined. Different ranges within this base type are sub classes. Also defined are several constants in this basic type. Similarly:
~/bin/codemd ../Prj/hello/src/foods.adb -x StrongType2 -l~/bin/codemd ../Prj/hello/src/foods.adb -x Vars -l
0032 | type Glycemic_Load is range 0 .. 100;
0033 | subtype Low_GL is Glycemic_Load range 0 .. 10;
0034 | subtype Medium_GL is Glycemic_Load range 11 .. 19;
0035 | subtype High_GL is Glycemic_Load range 20 .. 100;
0085 | breakfast : Glycemic_Load;
0086 | lunch : Glycemic_Load;
0087 | snack : Glycemic_Load;
0088 | dinner : Glycemic_Load;
And computations and assignments involving these variables:
However, assignments cannot be arbitrary. For example, in the following, the compiler has enough information to prevent invalid assignments and will not compile the code. No quiet promotions or conversions of constants/variable types is probably difficult in the beginning but produces reliable softtware at the end.
0103 |
0104 | -- error: invalid operand types for operator "+"
0105 | -- error: left operand has type "Glycemic_Load" defined at line 30
0106 | -- error: right operand has type "Glycemic_Index" defined at line 15
0107 | -- lunch := Spaghetti_GL + Soyabeans_GI ;
0108 |
0112 |
0113 | -- error: invalid operand types for operator "*"
0114 | -- error: left operand has type "Glycemic_Load" defined at line 30
0115 | -- error: right operand has type universal real
0116 | -- lunch := breakfast * 2.0 ;
0117 |
In addition, it is also very straightforward to ascertain the variable value ranges at runtime:
0018 | type Glucose_Concentration_Type is new Float range 0.0 .. 1_000.0;
0019 | subtype Hyperglycemic_Glucose_Type is
0020 | Glucose_Concentration_Type range 140.0 .. 1_000.0;
0021 | subtype Hypoglycemic_Glucose_Type is
0022 | Glucose_Concentration_Type range 0.0 .. 70.0;
0023 | subtype Euglycemic_Glucose_Type is
0024 | Glucose_Concentration_Type range 70.0 .. 140.0;
0025 |
0026 | my_glucose : Glucose_Concentration_Type := 139.999_991;
0027 | good_glucose_value : Euglycemic_Glucose_Type;
0028 | hypo_value : Hypoglycemic_Glucose_Type;
0029 | Hyper_value : Hyperglycemic_Glucose_Type;
It is based on the basic float data type but Glucose_Concentration_Type is a new and distinct data type implying all the variable protections. In addition, with ranges specified for subtypes which are essentially different classes, the protection is a runtime expectation.
Hypoglycemia Range is glucose levels below 7.00000E+01
Hyperglycemia Range is glucose levels above 1.40000E+02
My Glucose Level is 1.40000E+02
My Glucose levels are good
Assigning good_glucose_value to hypo_value
blood_chem.adb:62 range check failed
Assigning hypo_value to hyper_value
blood_chem.adb:71 range check failed