170 likes | 309 Views
More Ada Constructs 7 Oct. 2002. Today’s Constructs. Derived types Record types Array types Visibility and scope Subprogram arguments Exception handling Case statement. Derived Types. Ada is a “strongly-typed” language No automatic conversions
E N D
Today’s Constructs • Derived types • Record types • Array types • Visibility and scope • Subprogram arguments • Exception handling • Case statement
Derived Types • Ada is a “strongly-typed” language • No automatic conversions • Different types can only interact using operations specifically defined for the types • To even add more strength to types, Ada allows the user to create new types derived from other types. type Meters_t is new Float; type Yards_t is new Float; Distance_To_Paris : Meters_t; Distance_To_NY : Yards_t; Distance_To_Paris := Distance_To_NY + 1000.0; -- Illegal! • However, explicit conversions can be performed Distance_To_Paris := Meters_t (Distance_To_NY * 0.9144) + 1000.0;
Record Types • Comparable to “structures” in other languages • One object contains components of various types type Vehicle_State is record Position : Position_type; Velocity : Velocity_type; Linear_Acceleration : Linear_Acceleration_type; Inertial_Attitude : Attitude_type; Attitude_Rate : Attitude_Rate_type; Att_Accel : Att_Accel_type; -- Yes, you can abbreviate end record; • Ada records also can have “discriminants”
Discriminated Records* type Matrix_t is array (Int_32_t range <>, Int_32_t range <>) of Single_Float_t; • Want to have a Trace function for a square matrix • Would need to check for non-square • Would need to check ranges (someone could have created an object My_Array : Matrix_t (1 .. 3, 0 .. 2); ) • Instead, create a discriminated record type: subtype Pos_32_t is Int_32_t range 1 .. Int_32_t’last; type Square_Matrix_t (Order : Pos_32_t := 3) is record Matrix : Matrix_t (1 .. Order, 1 .. Order); end record; • Now, the compiler will make sure the input is of the correct form Taken from “Programming in Ada95”, 2nd Edition, John Barnes
Variant Records • The discriminant can also be used to create different records depending on the value of the discriminant type Error_t is (None, RAM_Scrub, Exception); type One_Hz_Telem_Data_t (Error_Kind : Error_t := None) is record case Error_Kind is when None => null; when RAM_Scrub => Bad_Location : Address_t; when Exception => Exception_data : Exception_Info_t; end case; end record;
Discriminant Can Change Dynamically or Can be Constant • M : Square_Matrix_t := (3, (1 .. 3 => (1 .. 3 => 0.0))); • N : Square_Matrix_t (Order => 4) := (4, (1 .. 4 => (1 .. 4 => 1.0))); • . • . • . • M := N; -- Legal • N := M; -- Illegal (Order can not change for N)
Array Types • Array types are easy • Multidimensional arrays are allowed • Matrix_t seen previously • Arrays of any other types are allowed, including arrays • Different syntax • A (1,2) for 2-dim array • A (1) (2) for array of arrays • Very good idea to always have a well-constrained subtype for array types (or discriminated records with arrays) • M : Square_Matrix_t; -- How much memory will this take?
Visibility and Scope • Good News : Not every name used in multiple files must be global • In fact, only “Library-level” names are globally defined • Library-level names are packages and subprograms that are declared at the outermost level of a compilation unit • Almost all global names are packages • One notable exception: function Unchecked_Conversion • Bad News : Lots of typing to tell the compiler what you want • Ada.Text_IO.Integer_IO.Put • Not-so-bad News : “use” statement; “renames” statement with Ada.Text_IO; ... use Ada.Text_IO.Integer_IO; -- Makes all declarations in package -- locally visible
Scope Example* • procedure Level_1 is • Count, Index : INTEGER := 1; • procedure Level_2 is • Index, Count : INTEGER := 2; • procedure Level_3 is • Count : INTEGER := 3; • begin • Count := -- Count from line 6 • Level_1.Count; -- Count from line 2 • end Level_3; • procedure Level_3_Prime is • Data, Index, Count : INTEGER := 3; • Outer_Index : INTEGER renames Level_1.Level_2.Index; • begin • Count := Outer_Index -- Count from line 12 • + Level_1.Level_2.Count; -- Count from line 4 • end Level_3_Prime; • begin • null; • end Level_2; • . . . • end Level_1; • * http://www.swcp.com/~dodrill/controlled/ada83doc/ada83tutor.html
The “Use” Clause • Makes names visible without qualification • Extremely useful to make readable code • Biggest problem is enumeration literals package Drawing_Package is type Colors_t is (Red, Blue, Yellow); . . . with Drawing_Package; procedure Use_It is C : Drawing_Package.Colors_t := Drawing_Package.Red; -- Tedious • Somewhat bad in that it makes it more difficult to find things • Majority opinion – Use sparingly, so maintainers can easily find things • Minority opinion – Tools can help find things; Ada has enough necessary tedium; don’t impose more
Subprogram Arguments • Procedures can have arguments of 3 kinds • “in” means treat as a constant inside procedure • “out” means it must be written before it is read (similar to an uninitialized variable) • The value is given to the caller when the procedure exits • “in out” can be read and written • The value is copied in at the start, and copied out at the end • Note that copying or referencing is meant for example; the actual parameter passing mechanism is defined differently for different kinds of data, and in some cases is left up to the compiler
Exception Handling • Exceptions are handled at the innermost scope where there is a relevant exception handler, out to the task level • For the moment, assume only 1 task in the program • X := F(G(H(I(J(X))))); • If an exception occurs in function J, if J has an exception handler for the specific exception, it will be handled locally • None of the outer functions will know the exception occurred • If J does not have an exception handler for that exception, it is propagated to the next level
Exception Propagation with Ada.Text_IO; use Ada.Text_IO; procedure Exception_Test is type My_Int is range 1 .. 5; Y : My_Int; function Level_1 (X : My_Int) return My_Int is Y : My_Int; begin Y := X + 10; -- raises Constraint_Error . . . -- Does not matter. Never executes these statements return X; -- Does not execute this exception when Program_Error => return My_Int’Last; -- Attributes are useful when End_Error => return My_Int’First; end Level_1; begin Y := Level_1 (1); put (“Made it”); exception when Constraint_Error => Put (“Constraint_Error in Y”); -- Y has no value end Exception_Test;
Output Constraint_Error in Y Program exited normally
What Happens if no Exception Handler? raised CONSTRAINT_ERROR : exception_test.adb:8 • Exception propagated to outermost level of current task • Task (if no exception handler) ends • Up to runtime system what to do next • For GNAT, see above for single task case • For multi-task case, tasks just disappear • GVD allows breakpoint on any exception • AdaGIDE has option to print traceback • Shows the call stack when run inside AdaGIDE
Case Statement X : My_Positive := 1; . . . case (X) is when 1 => . . . -- Any sequence of statements (if X = 1) when 2 => . . . -- Any sequence of statements (if X = 2) when 3 .. 10 => . . . -- Any sequence of statements (if X = 3, 4, or 5) when others => . . . -- Any sequence of statements (X = anything else) end case • Note, no need for “break” statement; after relevant sequence of statements, jump to “end case”