Table of Contents Section 1 Tutorial..................................................................................................................... 1 1.1 Introduction...................................................................................................................................1 1.2 Overview of Ada...........................................................................................................................2 1.3 Hello, Ada!....................................................................................................................................2 1.4 Control Structures.........................................................................................................................4 1.5 Subro!ra"s.................................................................................................................................# 1.$ %&es and Subt&es......................................................................................................................' 1.# Arra&s and (ecords.....................................................................................................................14 1.) *ac+a!es......................................................................................................................................1) 1.' Abstract ,ata %&es....................................................................................................................22 1.1- Strin!s.........................................................................................................................................24 1.11 ./cetions...................................................................................................................................24 1.12 ,iscri"inated %&es...................................................................................................................2$ 1.13 0enerics......................................................................................................................................2$ 1.14 Access %&es and ,&na"ic 1e"or& Allocation.......................................................................2) 1.15 Co""and 2ine Ar!u"ents and 3ile Handlin!...........................................................................31 1.1$ Ob4ect Oriented *ro!ra""in!....................................................................................................31 1.1# %as+in!........................................................................................................................................31 1.1) Container 2ibrar&........................................................................................................................33 1.1' 2ow 2evel *ro!ra""in!............................................................................................................33 Section 2 Case Study: Huffman Encoding............................................................................33 1.2- %5e Al!orit5".............................................................................................................................33 1.21 I"le"entation 6otes.................................................................................................................3$ Section 3 References............................................................................................................... 37 SECTION 1 TUTORIAL 1.1 Introduction My name is Peter Chapin. Welcome to my tutorial on the Ada programming language! The pur- pose of this tutorial is to give you an overview of Ada so that you can start writing Ada programs quicly. This tutorial does not cover the entire language. Ada is very large so complete coverage of all its features would tae many more pages than are contained in this document. !owever" it is my hope that after reading this tutorial you will have a good sense of what Ada is lie" appreci - ate some of its nicer features" and feel interested in learning more. The references section at the end of this tutorial points you to several good Ada resources that you can use to further your study of this fine language. This tutorial assumes you are already familiar with one or more languages in the C family# C" C$ $" %ava" C&" or something similar. 't is not my intention to teach you how to program. ' assume *a!e 1 of 3# you already understand the concepts of loops" data types" functions" and so forth. 'nstead this tu- torial descri(es how to use these things in Ada. 'n cases where Ada provides features that might (e unfamiliar to you )such as su(types" discriminated types" and tasing* ' will discuss those fea- tures a (it more comprehensively. 1.2 Oerie! of Ada Ada is a powerful language designed to address the following issues# The development of very large programs (y multiple" loosely connected teams. The lan- guage has features to help manage a large num(er of program components" and to help ensure those components are used consistently. The development of long lived programs that spend most of their time in the maintenance phase of the software life cycle. The language is designed to promote the reada(ility of programs. +ou may find Ada code to (e rather ver(ose and tedious to write. !owever" that e,tra wor pays off later (y maing the code clearer and easier to read when (ugs must (e fi,ed or enhancements written. The development of ro(ust programs where correctness" security" and relia(ility are priori- ties. The language has features designed to mae programming safer and less error prone. -ome of these features involve e,tra run time checing and thus entail a performance penalty. !owever" Ada.s design is such that the performance penalty is normally not e,- cessive. The development of em(edded systems where low level hardware control" multiple concur- rent tass" and real time requirements are common. The language has features designed to support these things while still retaining as much safety as feasi(le. 1." #ello$ Ada% Whenever you (egin to study a new language or software development environment you should start (y writing the most trivial program possi(le in that language or environment. /oing this will e,ercise your a(ility to get programs entered into the system and to get them compiled and e,e- cuted. Thus we will (egin this tutorial with a short (ut complete program that displays the string 0!ello" Ada!1 on the console. 2igure 3 shows the program. 't starts with what is called a context clause. The conte,t clause specifies the pacages that will (e used in this particular compilation unit. Most of the code in an Ada program is in pacages. The standard li(rary components are in child packages of the pac- age Ada. 'n this case we will (e using facilities in the child pacage Ada.Text_IO. The main program is a procedure named !ello. The precise name used for the main program can (e anything4 e,actly which procedure is used as the program.s entry point is specified when the program is compiled. The procedure consists of two parts# the part (etween is and begin is called the declarative region. Although empty in this simple case" it is here where you would de- *a!e 2 of 3# with Ada.Text_IO; procedure Hello is begin Ada.Text_IO.Put_Line(Hello Ada!"#; end Hello; Figure 1: A Trivial Ada Program clare local varia(les and other similar things. The part (etween the begin and the end constitute the e,ecuta(le statements of the procedure. 'n this case" the only e,ecuta(le statement is a call to procedure Put_Line in pacage Ada.Text_IO. As you can pro(a(ly guess from its name" Put_Line prints the given string onto the program.s standard output device. 't also terminates the output with an appropriate end-of-line indication. 5otice how the name of the procedure is repeated at the end. This is optional" (ut considered good practice. 'n more comple, e,amples the reada(ility is improved (y maing it clear e,actly what is ending. 5otice also the semicolon at the very end of the procedure definition. C family lan- guages do not require a semicolon here so you might accidentally leave it out. -pelling out the full name Ada.Text_IO.Put_Line is rather tedious. 'f you wish to avoid it you can include a use statement for the Ada.Text_IO pacage in the conte,t clause. After doing this" the names in that pacage (ecome directly visible and can (e used without qualification. The con- te,t clause (ecomes as shown in 2igure 6. Many Ada programmers do this to avoid having to write long pacage names all the time. !ow- ever" indiscriminate use of use can mae it difficult to understand your program (ecause it can (e hard to tell in which pacage a particular name has (een declared. Ada is a case insensitive language. Thus identifiers such as Hello" hello" and h$lLo all refer to the same entity. 't is traditional in modern Ada source code to use all lower case letters for re- served words. 2or all other identifiers" capitali7e the first letter of each word and separate multiple words with an underscore. The Ada language does not enforce this convention (ut it is a well es- ta(lished standard in the Ada community so you should follow it. 8efore continuing ' should descri(e how to compile the simple program a(ove. ' will assume you are using the free 95AT compiler. This is important (ecause 95AT requires specific file naming conventions that you must follow. These conventions are not part of the Ada language and are not necessarily used (y other Ada compilers. !owever" 95AT depends on these conventions in order to locate the files containing the various compilation units of your program. The procedure Hello should (e stored in a file named hello.adb. 5otice that the name of the file must (e in lower case letters and must agree with the name of the procedure stored in that file. The adb e,tension stands for 0Ada (ody.1 This is in contrast with Ada specification files that are given an e,tension of ads. +ou will see Ada specifications when ' tal a(out pacages later in this tutorial. ' will descri(e other 95AT file naming requirements at that time. To compile hello.adb" open a console )or terminal* window and use the gnat%a&e command as follows gnat%a&e hello.adb The gnat%a&e command will compile the given file and lin the resulting o(:ect code into an e,e- cuta(le producing" in the a(ove e,ample" hello.exe )on Windows*. +ou can compile Ada pro- grams without gnat%a&e (y running the compiler and liner separately. There are sometimes good reasons to do that. !owever" for the programs you will write as a (eginning Ada program- *a!e 3 of 3# with Ada.Text_IO; use Ada.Text_IO; procedure Hello is begin Put_Line(Hello Ada!"#; end Hello; Figure 2: Context Clause Including use mer" you should get into the ha(it of using gnat%a&e. 5ote that 95AT comes with a graphical Ada programming environment named 9P- )95AT Pro- gramming -tudio*. 9P- is similar to other modern integrated development environments such as Microsoft.s ;isual -tudio or <clipse. 2eel free to e,periment with 9P- if you are interested. !ow- ever" the use of 9P- is outside the scope of this tutorial. When the compilation has completed successfully you will find that several additional files have (een created. The files hello.o and hello.exe )on Windows* are the o(:ect file and e,ecuta(le file respectively. The file hello.ali is the Ada li(rary information file. This file is used (y 95AT to implement some of the consistency checing required (y the Ada language. 't is a plain te,t file4 feel free to loo at it. !owever" you would normally ignore the ali files. 'f you delete them" they will simply (e regenerated the ne,t time you compile your program. Exercises 3. <nter the trivial program in 2igure 3 )or 2igure 6* into your system. Compile and run it. 6. Mae a minor modification to the trivial program that results in an error. Try compiling the program again. Try several different minor errors. This will give you a feeling for the inds of error messages 95AT produces. =. <,periment with the use statement. Try calling Put_Line without specifying its pacage" (oth with and without the use statement. 1.& Control Structures Ada contains all the usual control structures you would e,pect in a modern language. The pro- gram in 2igure = illustrates a few of them" along with several other features. This program accepts an integer from the user and checs to see if it is a prime num(er. This procedure declares a local varia(le named 'u%ber of type Integer in its declarative region. 5otice that the type appears after the name (eing declared )the opposite of C family languages*" separated from that name with a colon. *a!e 4 of 3# Procedure (et from pacage Ada.Integer_Text_IO is used to read an integer from the console. 'f the value entered is less than two an error message is displayed. 5otice that there are two differ- ent Put procedures (eing used# one that outputs a string and another that outputs an integer. >ie C$$ and some other modern languages" Ada allows procedure names to (e overloaded dis- tinguishing one procedure from another (ased on the parameters. )'n this case the two different Put procedures are also in different pacages.* 'f the value entered is two or more" the program uses a )or loop to see if any value less than the given num(er divides into it evenly )produces a 7ero remainder after division*. Ada )or loops scan over the given range assigning each value in that range to the inde, varia(le )named I in this case* one at a time. 5otice that it is not necessary to e,plicitly declare the inde, varia(le. The compiler deduces its type (ased on the type used to define the loop.s range. 't is also important to understand that if the start of the range is greater than the end of the range" the result is an empty range. 2or e,ample" the range * .. + contains no mem(ers and a loop using that range won.t e,ecute at all. 't does not e,ecute starting at two and counting down to one. +ou need to use the word re,erse to get that effect# )or I in re,erse + .. * loop 5otice also that i) statements require the word then and that each end is decorated (y the name of the control structure that is ending. 2inally notice that a single equal sign is used to test for equality. There is no -- operator in Ada. 2igure ? shows a program that counts the vowels in the te,t at its standard input. +ou can feed this program te,t using '@A redirection. This program illustrates while loops and case structures )similar to C.s switch statement*. There are quite a few things to point out a(out this program. >et.s loo at them in turn. *a!e 5 of 3# with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Pri%e is 'u%ber . Integer; begin Put(/$nter an integer. /#; (et('u%ber#; i) 'u%ber 0 * then Put(/The ,alue /#; Put('u%ber 1#; Put_Line(/ is bad./#; else Put(/The ,alue /#; Put('u%ber 1#; )or I in * .. ('u%ber 2 +# loop i) 'u%ber %od I - 1 then Put_Line(/ is not pri%e./#; return; end i); end loop; Put_Line(/ is pri%e./#; end i); end Pri%e; Figure 3: A Prime Number Checker 3. ;aria(les can (e initiali7ed when they are declared. The .- operator is used to give a vari- a(le its initial value )and also to assign a new value to a varia(le*. Thus lie C family lan- guages" Ada distinguishes (etween test for equality )using -* and initiali7ation@assignment )using .-*. Bnlie C family languages you.ll never get them mi,ed up (ecause the compiler will catch all incorrect usage as an error. 6. 'n this program the condition in the while loop involves calling the function $nd_O)_3ile in pacage Ada.Text_IO. This function returns True if the standard input device is in an end- of-file state. 5otice that Ada does not require )or even allow* you to use an empty parame- ter list on functions that tae no parameters. This means that function $nd_O)_3ile loos lie a varia(le when it is used. This is considered a feature4 it means that read-only vari - a(les can (e replaced (y parameterless functions without requiring any modification of the source code that uses that varia(le. =. The sample program uses the logical operator not. There are also operators and and or that can (e used in the e,pected way. ?. The case statement (ranches to the appropriate when clause depending on the value in the varia(le Letter. The two when clauses in this program show several alternatives separated (y vertical (ars. 'f any of the alternatives match" that clause is e,ecuted. +ou can also specify ranges in a when clause# when + .. +1 -4 etc. C. Ada has what are called 0full coverage rules.1 'n a case statement you must account for every possi(le value that might occur. Providing when clauses for :ust the vowels would (e an error since you would not have fully covered all possi(le characters. 'n this program ' want to ignore the other characters. To do this" ' provide a when others clause that e,e- cutes the null statement. This lets future readers of my program now that ' am intention- ally ignoring the other characters. *a!e $ of 3# with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure 5owels is Letter . 6haracter; 5owel_6ount . Integer .- 1; begin while not $nd_O)_3ile loop (et(Letter#; case Letter is when 7A787$787I787O78797 -4 5owel_6ount .- 5owel_6ount : +; when 7a787e787i787o787u7 -4 5owel_6ount .- 5owel_6ount : +; when others -4 null; end case; end loop; Put(/Total nu%ber o) ,owels - /#; Put(5owel_6ount#; end 5owels; Figure : !o"el Counting Program Exercises 3. The prime num(er checing program in 2igure = is not very efficient. 't can (e improved (y taing advantage of the following o(servation# 'f 'u%ber is not divisi(le (y any value less than I" then it can.t (e divisi(le (y any value greater than 'u%ber;I. Thus the upper (ound of the loop can (e reduced as I increases. Modify the program to use this o(serva- tion to improve its performance. 5ote# +ou will have to change the )or loop to a while loop )try using a )or loop first and see what happens*. 6. Modify the prime num(er checing program so that it loops repeatedly accepting num(ers from the user until the user types -3. +ou can program an infinite loop in Ada as shown in 2igure C. !ave your program print out different error messages for negative num(ers )other than -3* than for the values 7ero and one. Bse an i) ... elsi) chain )note the spell- ing of elsi)*. Write a version that uses a case statement instead of an i) ... elsi) chain. +ou can use Integer73irst in a range definition to represent the first )smallest* 'nteger value the compiler can represent. 1.' Sub(ro)ra*s Bnlie C family languages" Ada distinguishes (etween procedures and functions. -pecifically" func- tions must return a value and must (e called as part of a larger e,pression. Procedures never re- turn a value )in the sense that functions do* and must (e called in their own statements. Collec- tively procedures and functions are called subprograms in situations where their differences don.t matter. -u(programs can (e defined in any declarative region. Thus it is permissi(le to nest su(program definitions inside each other. A nested su(program has access to the parameters and local vari- a(les in the enclosing su(program that are defined a(ove the nested su(program. The scope rules are largely what you would e,pect. 2igure D shows a variation of the prime num(er checing pro- gram that introduces a nested function Is_Pri%e that returns True if its argument is a prime num(er. 'n this case Is_Pri%e has (een declared to tae a parameter ' of type Integer. 't could have also accessed the local varia(le 'u%ber directly. !owever" it is usually (etter style to pass param- eters to su(programs in cases where it maes sense. ' also wanted to illustrate the synta, for pa- rameter declarations. 5ote that (ecause Is_Pri%e is a function a return type must (e specified and it must (e called in the conte,t of an e,pression )in 2igure D" it is called in the condition of an i) statement*. Procedure declarations are similar e,cept that no return type is mentioned. Also when a procedure is called it must not (e part of an e,pression" (ut rather stand (y itself as a sin- gle statement. -ee the calls to procedures Put and Put_Line in the e,amples so far. *a!e # of 3# loop ... exit when condition; ... end loop; Figure #: An In$inite %oo& 'ith an (&tional )xit Condition The program a(ove also shows the form of a comment. Ada comments start with 22 and run to the end of the line. As you now" it is good to include comments in your program. !owever" the e,amples in this tutorial do not include many comments in order to save space )and (ecause the programs are e,plained in the te,t anyway*. Procedures also differ from functions in that they support several parameter 0modes.1 2igure E shows the definition of a procedure that illustrates this. 5otice that a semi-colon is used to sepa- rate parameter declarations and not a comma as is done in C family languages. The first parameter declared in 2igure E has mode in. Parameters with this mode are initiali7ed with the argument provided (y the caller" (ut treated as constants inside the procedure. They can (e read" (ut not modified. The second parameter has mode out. Parameters with this mode are in an uninitiali7ed state when the procedure (egins" (ut they can (e used otherwise as ordinary vari - a(les inside the procedure. Whatever value is assigned to an out parameter (y the time the pro- cedure ends is sent (ac to the calling environment. The third parameter has mode in out. Pa- rameters with this mode are initiali7ed with the argument provided (y the caller" and can also (e modified inside the procedure. The changed value is then returned to the caller to replace the original value. Feep in mind that" unlie in C" modifications to parameters in Ada )when allowed (y the parameter mode* affect the arguments used when the procedure is called. *a!e ) of 3# with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Pri%e* is 'u%ber . Integer; 22 This )unction returns True i) ' is pri%e; 3alse otherwise. )unction Is_Pri%e(' . Integer# return <oolean is begin )or I in * .. (' = +# loop i) ' %od I - 1 then return 3alse; end i); end loop; return True; end Is_Pri%e; begin Put(/$nter an integer. /#; (et('u%ber#; i) 'u%ber 0 * then Put(/The ,alue /#; Put('u%ber 1#; Put_Line(/ is bad./#; else Put(/The ,alue /#; Put('u%ber 1#; i) Is_Pri%e('u%ber# then Put_Line(/ is pri%e./#; else Put_Line(/ is not pri%e./#; end i); end i); end Pri%e*; Figure *: Prime Number Checker 'ith a Nested Function The mode in is the default. 2unctions parameters can only have mode in and thus it is common to leave the mode specification off when defining function parameters 3 . My recommendation" how- ever" is to always specify the mode when declaring procedure parameters. >ie C$$" Ada also allows you to define default values for su(program parameters. This is accom- plished (y initiali7ing the parameter )using the .- operator* when the parameter is declared. 'f no argument is provided for that parameter when the su(program is called the default value is used instead. Ada also allows you to call su(programs using named parameter associations. This method allows you to associate arguments with the parameters in any order" and it can also greatly improve the reada(ility of your codeparticularly if you.ve chosen good names for the parameters. 2igure G shows how the procedure defined in 2igure E might (e called. Assume that the varia(les Accu%u2 lator" '" and Output have (een previously declared as integers. 5otice that the order in which the arguments are provided is not the same as the order in which the parameters are declared. When named association is used" the order is no longer significant. 5otice also that you can use any e,pression as the argument associated with an in parameter. !owever" out and in out parameters must (e associated with varia(les and not ar(itrary e,pres- sions )since putting a value into the result of an e,pression doesn.t really mae sense*. Exercises 3. Write a procedure 6ount_Pri%es that accepts a range of integers and returns the num(er of primes" the smallest prime" and the largest prime in that range. +our implementation should use out parameters to return its results. 't should also mae use of the Is_Pri%e function defined in 2igure D. Wrap your procedure in a main program that accepts input values from the user and outputs the results. Bse named parameter association when call - ing 6ount_Pri%es. 6. 'mplement 6ount_Pri%es from the previous question as a function )or a collection of func- tions* instead. What are the advantages and disadvantages of each approachH 1.+ T,(es and Subt,(es 'n the e,amples so far you have seen the Ada types 'nteger" Character" and 8oolean. Ada also has a type 2loat for storing floating point values and a type -tring" which is an array of charac- ters. Ane important characteristic of Ada that sets it apart from many languages is its strong typ- 1 In t5e uco"in! Ada 2-12 standard t5is li"itation on function ara"eter "odes 5as been re"oved. *a!e ' of 3# procedure >ode_$xa%ple (? . in Integer; @ . out Integer; A . in out Integer# is begin ? .- +; 22 $rror. 6an7t %odi)B an in para%eter. @ .- ?; 22 O&aB. 6an read ? and %odi)B @. A .- A : +; 22 O&aB. 6an read and write an in out para%eter. end >ode_$xa%ple; Figure +: Procedure ,e$inition Illustrating Parameter -odes >ode_$xa%ple(A -4 Accu%ulator ? -4 ':+C @ -4 Output#; Figure .: Calling Procedure )xam&le "ith Named Association ing. There is no precise definition of this term" (ut for our purposes we will say that a strongly typed language is one which does no )or very few* automatic type conversions. Bnlie C" Ada will not convert integers to floating point values or visa-versa without e,plicit instruction from the pro- grammer. 2igure I illustrates this. 'f you are not used to strong typing you may find it e,cessively pedantic and annoying. !owever" it e,ists for a reason. <,perience has shown that many (ugs first manifest themselves as confu- sion a(out types. 'f you find yourself mi,ing types in your program" it may mean that you have a logical error. /oes it mae sense to put a value representing velocity into a varia(le that holds a passenger countH -trong typing can catch errors lie this and thus it promotes software relia(ility. 'n fact" Ada allows you to define your own scalar types. 8y creating a new type for each logically distinct set of values in your program" you ena(le the compiler to find logical errors that it might otherwise miss. 2or e,ample" consider a procedure Put_6har that prints a single character onto the terminal at a given row and column location. 'nstead of declaring the row and column param- eters as integers" you might introduce two distinct types for those concepts. 2igure 3J shows how it could loo. -uppose the main program declared D as type Dow_TBpe and 6 as type 6olu%n_TBpe. 5ow a call such as Put_6har(6 D 7x7# would (e detected (y the compiler as an error (ecause the types used for the first two arguments don.t match the types declared for those parameters. Acciden- tally switching the row and column arguments in a call lie this is an easy error to mae. Ada.s strong typing" together with the use of appropriate user defined types" allows the compiler to catch this error rather than waiting until testing to )may(e* find it. -trong typing can also find errors in ordinary e,pressions. 2or e,ample" consider the assignment statement D .- *E6 : +. The e,pression on the right hand side has type 6olu%n_TBpe (ut the *a!e 1- of 3# procedure Ftrong_TBping_$xa%ple is I . Integer; 3 . 3loat; begin I .- +; 22 O&aB. I .- +.1; 22 $rror. 6an7t assign a 3loat to an Integer. 3 .- +; 22 $rror. 6an7t assign an Integer to a 3loat. 3 .- +.1; 22 O&aB. 3 .- I; 22 $rror. I .- 3; 22 $rror. 3 .- 3loat(I#; 22 O&aB. $xplicit con,ersion. I .- Integer(3#; 22 O&aB. $xplicit con,ersion. end Ftrong_TBping_$xa%ple; Figure /: ,emonstration o$ 0trong T1&ing tBpe Dow_TBpe is range + .. *C; tBpe 6olu%n_TBpe is range + .. G1; procedure Put_6har (Dow . Dow_TBpe; 6ol . 6olu%n_TBpe; Letter . 6haracter# is begin 22 etc end Put_6har; Figure 12: 3sing 0trong T1&ing to )nhance )rror Checking varia(le on the left hand side has type Dow_TBpe. 't pro(a(ly doesn.t mae sense to (e assigning a column value to a row varia(le and Ada will flag this statement as an error. 'f it is really your in- tention to use this computed column value for a row num(er" you need to include an e,plicit con- version. The result is D .- Dow_TBpe(*E6 : +#. +ou might (e wondering what happens in the a(ove e,ample if the result of *E6 : + is a value outside the allowed range specified for type Dow_TBpe. 't is important to understand that Ada never allows a value to (e assigned to a varia(le that is outside the set of values for that vari - a(le.s type. 'n this case a run time error would occur )an e,ception would (e raised*. /efining your own types also helps you write porta(le programs. The only integer type compilers must support is Integer. The num(er of (its used (y type Integer is implementation defined and varies from compiler to compiler. Most compilers support additional" non-standard integer types such as Long_Integer and Long_Long_Integer. !owever" the names of these additional types" and even their e,istence" varies from compiler to compiler. Kather than deal with this comple,ity directly you can :ust specify the range of values you desire and the compiler will select the most appropriate underlying type. 2or e,ample tBpe <loc&_6ounter_TBpe is range 1 .. +_111_111_111; ;aria(les of type <loc&_6ounter_TBpe may (e represented as Integer or Long_Integer or some other type as appropriate. !owever" in any case they will (e constrained to only hold values (e- tween 7ero and one (illion inclusive. 'f the compiler does not have a (uilt-in integer type with a large enough range it will produce an error message. 'f the compiler accepts your type definition you will not get any surprises. 5otice also how Ada allows you to em(ed underscores in large num(ers to improve their reada(ility. Ada also allows you to define modular types. These types are unsigned and have 0wrap-around1 semantics. 'ncrementing (eyond the end of an ordinary type causes an e,ception" (ut increment- ing (eyond the end of a modular type wraps around to 7ero. 'n addition the operators not" and" or" and xor can (e used on modular types to do (itwise manipulation. 2igure 33 demonstrates. !ere a modular type O))set_TBpe is introduced to hold 36 (it offsets. The varia(le O))set is mased so that only the lower 3J (its are retained. The snippet in 2igure 33 also demonstrates Ada.s e,ponentiation operator and how num(ers in (ases other than 3J can (e written. 8ecause Ada was designed for use in em(edded systems" its support for low level (it manipulation is good. Enumeration Types 'n many cases you want to define a type that has only a small num(er of allowed values and you want to name those values a(stractly. 2or e,ample" the definition tBpe HaB_TBpe is (Fun >on Tue Ied Thu 3ri Fat#; introduces HaB_TBpe as an enumeration type. ;aria(les of type HaB_TBpe can only tae on the values listed in the type definition. These values are called enumerators. This is useful for writing your program in a(stract terms that are easy to understand. 8ecause the compiler treats enumer- ation types as distinct from integer types )and from each other* you will not (e allowed to mi, un- *a!e 11 of 3# tBpe O))set_TBpe is %od *EE+*; ... O))set . O))set_TBpe; ... O))set .- O))set and +JKL33K; Figure 11: ,emonstration o$ -odular T1&es related concepts without compile time errors. Discrete Types The integer types and enumeration types are discrete types (ecause they each represent only a finite set of )ordered* values. All discrete types share some common properties and it is enlight- ening to descri(e those properties in a uniform way. Ada maes e,tensive use of attributes. +ou reference an attri(ute of a type using an apostrophe )or 0tic1* immediately following the type name. 2or e,ample" HaB_TBpe73irst represents the first value in the HaB_TBpe enumeration and Integer73irst represents the first )smallest* al- lowed value of Integer. There is also a Last attri(ute to access the last allowed value. -ome at- tri(utes (ehave lie functions. 2or e,ample HaB_TBpe7Fucc(Fun# returns >on" the successor of Fun in the HaB_TBpe enumeration. There is also a Pred attri(ute for finding the predecessor value. 'n addition there is a Pos attri(ute that returns the integer position of a particular enumerator and a 5al attri(ute that does the reverse. 2or e,ample HaB_TBpe7Pos(>on# is one )the position values start at 7ero* and HaB_TBpe75al(+# is >on. We will see other attri(utes later in this tutorial. Kanges of discrete types can (e defined in a uniform way and used" for e,ample" as cases in case statements and ranges of for loops. 2igure 36" shows a contrived e,ample. 5otice that despite Ada.s full coverage rules it is not necessary to specify a case for Fat. This is (ecause the compiler can see HaB is limited to Fun .. 3ri and thus will never tae on the value Fat. Kecall that the loop inde, varia(le of a for loop can not (e modified inside the loop so there is no possi(ility of the programmer setting HaB to Fat (efore the case statement is reached. Subtypes When a new type is defined using tBpe" the compiler regards it as distinct from all other types. This is strong typing. !owever" sometimes it is (etter to define a constraint on an e,isting type rather than introduce an entirely new type. There are several different inds of constraints one might define depending on the type (eing constrained. 'n this section ' will tal a(out range con- straints on discrete types. As an e,ample" the definition subtBpe Iee&daB is HaB_TBpe range >on .. 3ri; introduces a subtype named Iee&daB that only contains the values >on through 3ri. 't is impor- tant to understand that a su(type is not a new type" (ut :ust a name for a constrained version of the parent type. The compiler allows varia(les of a su(type to (e mi,ed freely with varia(les of the parent type. Kun-time checs are added if necessary to verify that no value is ever stored in a varia(le with a su(type that is outside the range of the su(type. 'f an attempt is made to do so" the 6onstraint_$rror e,ception is raised. 2igure 3= shows an e,ample *a!e 12 of 3# )or HaB in Fun .. 3ri loop case HaB in when Fun -4 etc... when >on 8 Tue -4 etc... when Ied .. 3ri -4 etc... end case; end loop; Figure 12: ,emonstration o$ ,iscrete 4anges 'n this e,ample a su(type Inter,al is defined in the procedure.s declarative region. The varia(le ? of type Inter,al is given Inter,al.s first value. Mi,ing Inter,al and HaB_TBpe varia(les in the later assignment statements is allowed (ecause they are really (oth of the same type. 8ecause Inter,al is a su(type of HaB_TBpe the assignment of ? to HaB must succeed. Thus the compiler does not need to include any run time checs on the value of ?. !owever" the value of HaB might (e outside the allowed range of the su(type and so the compiler will need to insert a run time chec on HaB.s value (efore assigning it to ?. 'f that chec fails" the 6onstraint_$rror e,ception is raised. Bnder no circumstances can an out of (ounds value (e stored in a varia(le. ' should point out that in this particular )simplistic* e,ample the compiler.s optimi7er may (e a(le to see that the value in HaB will (e in (ounds of the su(type since in the assignment :ust (efore it was given a value from the su(type. 'n that case the compiler is allowed and encouraged to optimi7e away the run time chec that would normally (e required. This e,ample also illustrates another important aspect of su(types# they can (e dynamically de- fined. 5otice that the range on the su(type is taen from the procedure.s parameters. <ach time the procedure is called that range might (e different. 'n contrast the range specified on full type definitions must (e static )nown to the compiler*. A range such as +..+1 is really an a((reviation for the specification of a su(type Integer range +..+1. Thus a for loop header such as )or I in +..+1 is really :ust an a((reviation for the more specific )or I in Integer range +..+1. 'n general the for loop specifies a su(type over which the loop inde, varia(le ranges. This is why in 2igure 36 it was not necessary to provide a case for Fat. The loop inde, varia(le HaB implicitly declared in the loop header has the su(type HaB_TBpe range Fun..3ri. The case statement contains alternatives for all possi(le values in that su(type so the full coverage rules are satisfied. The Ada environment predefines two important and useful su(types of Integer. Although you never have to e,plicitly define these types yourself" the compiler (ehaves as if the following two su(type definitions were always directly visi(le. subtBpe 'atural is Integer range 1 .. Integer7Last; subtBpe Positi,e is Integer range + .. Integer7Last; The su(type 'atural is often useful for counters of various inds. -ince counts can.t (e negative the run time checing on 'atural.s range constraint can help you find program errors. The su(- type Positi,e is useful for cases where 7ero is a nonsensical value that should never arise. Never Use Integer 'n Ada you should avoid using the type Integer )or 3loat* directly in your program. 'nstead it is (etter practice to introduce your own types or su(types to name the scalar types you need. 'n ad- *a!e 13 of 3# procedure He%onstrate_FubtBpes (Lower 9pper . in HaB_TBpe; HaB . in out HaB_TBpe# is subtBpe Inter,al is HaB_TBpe range Lower .. 9pper; ? . Inter,al .- Inter,al73irst; begin HaB .- ?; 22 'o run ti%e chec&. Iill de)initelB succeed. ? .- HaB; 22 Dun ti%e chec&. HaB %ight be out o) range. $nd He%onstrate_FubtBpes; Figure 13: 0ubt1&e ,emonstration dition to documenting your program (etter" this practice allows the compiler or" in the case of su(types the runtime system" to catch many logical errors in your code. Ada is designed to help you write relia(le programs" and its strong typing is a ma:or feature in that regard. !owever" if you simply declare all your numeric scalar varia(les as Integer uniformly you are largely negat- ing any (enefits strong typing might provide. 'n this tutorial Integer is used frequently in the e,amples. This is largely (ecause the e,amples are isolated snippets of code that are not really part of a larger program. <,amples also often use short and meaningless varia(le names for the same reason. 'n real programs you should use good varia(le names and" in Ada" well considered type definitions that em(ody as many aspects of your program.s design as possi(le. Exercises 3. Bsing the definition of HaB_TBpe presented earlier would you guess that the following wors or produces a compiler error# )or HaB in HaB_TBpe loop ... H Write a short pro- gram to see how the compiler (ehaves when presented with a loop lie this. 6. Ane of the e,amples a(ove introduced separate Dow_TBpe and a 6olu%n_TBpe definitions. What disadvantage is there to eeping these concepts distinctH Would it (e (etter to use a single Fcreen_6oordinate_TBpe for (oth row and column coordinates insteadH 1.- Arra,s and Records Bnlie C family languages" arrays in Ada are first class o(:ects. This means you can assign one ar- ray to another" pass arrays into su(programs and return arrays from functions. <very array has a type" however" this type does not need to (e named. 2or e,ample Ior&space . arraB(+ .. +1*M# o) 6haracter; defines Ior&space to (e an array of characters inde,ed using the integers 3 through 3J6?. 5ote that although Ior&space has an array type" the name of that type is not specified. 'n fact" you can define arrays using any discrete su(type for the inde, )recall that +..+1*M is re- ally an a((reviation for an integer su(type specification*. 't is not possi(le to access an array out of (ounds for e,actly the same reason it.s not possi(le to store an out of (ounds value into a vari - a(le. The compiler raises the 6onstraint_$rror e,ception in precisely the same way. 2igure 3? shows an e,ample illustrating many important features. 3. Arrays are accessed using parenthesis and not square (racets as in C family languages. Thus array access has a synta, similar to that of a function call. An array of constant val- ues and can (e replaced with a function later without clients needing to (e edited. *a!e 14 of 3# 6. Any discrete su(type" including enumeration su(types" can (e used for an array inde,. 'n 2igure 3? the array Ior&_Hours has elements Ior&_Hours(Fun# and so forth. =. The nested function AdNust_O,erti%e uses a type defined in the enclosing procedure. This is perfectly accepta(le. The visi(ility of all names is handled uniformly. ?. 't is possi(le to use array aggregates in e,pressions where an array is e,pected. Ior&_Hours is assigned a value that specifies every element of the array in one step. The compiler deduces the type of the aggregate from its conte,t. C. 5otice that the same su(type is used for (oth the loop inde, varia(le and the array inde,. This is a common situation and it means the compiler can optimi7e out the run time checs normally required when accessing an array element. -ince the value of HaB can.t possi(ly (e outside the range of allowed array inde,es" there is no need to chec that Ior&_Hours(HaB# is in (ounds. 'n some cases it is appropriate to give a name to a particular array type. This is desira(le if you plan on declaring many arrays that are intended to have the same type. When the type definition is in only one place" updating it later is easier. Also you can.t assign one array to another unless they have the same type and in that case the type has to (e named. 2igure 3C illustrates. 8ecause su(types are defined dynamically the si7e and (ounds of an array can also (e defined dy- namically. 2or e,ample a declaration such as A . arraB(+..'# o) 'atural is allowed even if the value of ' is not nown at compile time )for e,ample" it could (e a su(program parameter*. This *a!e 15 of 3# procedure $xa%ple is tBpe HaB_TBpe is (Fun >on Tue Ied Thu 3ri Fat#; Ior&_Hours . arraB(HaB_TBpe# o) 'atural; )unction AdNust_O,erti%e (HaB . HaB_TBpe; Hours . 'atural# return 'atural is begin 22 'ot shown. end AdNust_O,erti%e; begin Ior&_Hours .- (1 G G G G 1#; )or HaB in HaB_TBpe loop Ior&_Hours(HaB# .- AdNust_O,erti%e(HaB Ior&_Hours(HaB##; end loop; end $xa%ple; Figure 1: Arra1 )xam&le procedure $xa%ple is tBpe <u))er_TBpe is arraB(1..+1*L# o) 6haracter; <+ . <u))er_TBpe; <* . <u))er_TBpe; <L . arraB(1..+1*L# o) 6haracter; begin <+ .- <*; 22 3ine. $ntire arraB assigned. <+ .- <L; 22 $rror. TBpes don7t %atch. <L has anonB%ous tBpe. end $xa%ple; Figure 1#: Named vs Anon1mous Arra1 T1&es feature means that many places where dynamic allocation is necessary in" for e,ample" C$$ can (e handled in Ada without the use of e,plicit memory allocators. Unconstrained Array Types Ane pro(lem with the standard definition of Pascal 6 is that it is not possi(le to write a procedure that taes an array of unnown si7e. At first glance it appears that Ada would also have that pro(- lem. Arrays of different si7es have different types and strong typing will prevent them from (eing mi,ed. This would (e a serious limitation. To get around this pro(lem Ada has the concept of un- constrained array types. -uch a type does not specify the (ounds on the array" allowing arrays with different (ounds to (e in the same type. !owever" the (ounds must (e specified when an ac- tual array o(:ect is declared so the compiler nows how much memory to allocate for the o(:ect. 2igure 3D shows an e,ample. Again there are several points to mae a(out this e,ample. 3. The sym(ol 04 )pronounced 0(o,1* is intended to (e a placeholder for information that will (e filled in later. 'n this case it specifies that the inde, (ounds on the array type <u))er_TBpe is unconstrained. 6. 't is illegal to declare a varia(le with an unconstrained type without providing constraints. This is why the declaration of <+ is an error. !owever" the missing array (ounds are speci- fied in the other declarations. 5otice that it is not necessary for array (ounds to start at 7ero or one. Any particular value is fine as long as it is part of the inde, type mentioned in 2 Standard *ascal is not usable for serious ro!ra""in!. Co""ercial *ascal co"ilers rovide e/tensions to address t5e s5ortco"in!s in t5e standard version of t5e lan!ua!e. *a!e 1$ of 3# procedure 9nconstrained_ArraB_$xa%ple is tBpe <u))er_TBpe is arraB(Integer range 04# o) 6haracter; <+ . <u))er_TBpe; 22 $rror. >ust speci)B arraB bounds. <* . <u))er_TBpe( 1..+C#; 22 O&aB. <L . <u))er_TBpe( 1..+C#; <M . <u))er_TBpe(+J..L+#; 22 3ine. <C . <u))er_TBpe( 1..JL#; 22 'o proble%. procedure Process_<u))er(<u))er . in <u))er_TBpe# is begin )or I in <u))er7Dange loop 22 Ho so%ething with <u))er(I# end loop; end Process_<u))er; begin <* .- <L; 22 3ine. TBpes %atch and bounds co%patible. <* .- <M; 22 3ine! TBpes %atch and lengths identical. <* .- <C; 22 6onstraint_$rror. Lengths don7t %atch. Process_<u))er(<*#; 22 3ine. Process_<u))er(<M#; 22 3ine. Process_<u))er(<C#; 22 3ine. end 9nconstrained_ArraB_$xa%ple; Figure 1*: 3nconstrained Arra1 T1&es the array declaration. =. 't is fine to declare a su(program" such as Process_<u))er" taing an unconstrained array type as an parameter. !owever" such a su(program can.t safely access the elements of the given array using specific inde, values lie 3 or 6 (ecause those values might not (e legal for the array. 'nstead one needs to use special array attri(utes. 2or e,ample" <u)2 )er73irst is the first inde, value that is valid for array <u))er" and similarly for <u)2 )er7Last. The attri(ute Dange is shorthand for <u))er73irst..<u))er7Last and is quite useful in for loops as the e,ample illustrates. ?. +ou might find it surprising that the assignment <* .- <M is legal since the array (ounds do not match. !owever" the two arrays have the same length so corresponding elements of the arrays are assigned. This is called sliding semantics )(ecause you can imagine slid- ing one array over until the (ounds do match*. C. All the calls to Process_<u))er are fine. 'nside the procedure <u))er7Dange adapts itself to whatever array it is given and" provided the code is written with this in mind" the proce- dure wors for arrays of any si7e. Records 'n C family languages composite o(:ects containing components with different types are called structures. 'n Ada )and many other languages* they are called records. All record types must have a name and thus must (e declared (efore any o(:ects of that type can (e created. 2igure 3E shows an e,ample. This procedure defines a type Hate as a collection of three named components. 5otice that the HaB and >onth components are defined as su(types of Integer without the (other of naming the su(types involved )anonymous su(types are used*. TodaB is declared to (e a Hate and initiali7ed with a record aggregate. 'n this case named association is used to mae it clear which component gets which initial value" however positional association is also legal. Kecords can (e assigned as entire units and their components accessed using the dot operator. 5otice that if To%orrow.HaB : + creates a value that is outside the range +..L+" a 6onstraint_$rror e,ception will (e raised" as usual when that out of (ounds value is assigned to To%orrow.HaB. A(viously a more sophisticated procedure would chec for this and ad:ust the month as necessary )as well as deal with the fact that not all months are =3 days long*. *a!e 1# of 3# procedure $xa%ple is tBpe Hate is record HaB . Integer range + .. L+; >onth . Integer range + .. +*; @ear . 'atural; end record; TodaB . Hate .- (HaB -4 + >onth -4 O @ear -4 *11O#; To%orrow . Hate; begin To%orrow .- TodaB; To%orrow.HaB .- To%orrow.HaB : +; end $xa%ple; Figure 1+: 4ecord T1&es 1.. /ac0a)es A pacage is a named container into which you can place su(programs" type definitions" and other entities that are related to each other. Pacages can even contain other pacages. 'n Ada pac- ages are the primary way to organi7e and manage the various parts of a program. Pacages have two parts# a specification that declares the entities that are visi(le to the rest of the program" and a body that contains the implementation of those entities. The (ody can also contain private entities that can only (e used inside the pacage. 'n most cases the specification is stored in a separate file from the (ody and can even (e compiled separately. This maes the separation (etween a pacage.s interface and implementation more rigorous in Ada than in many languages" encouraging the programmer to separate the process of software design from con- struction. This formal separation maes it easier for different groups of people to wor on the de- sign and construction of a program since those groups would (e woring with different sets of source files. At least this is the ideal situation. Alas" pacage specifications can have a private sec- tion" discussed later" that is technically part of the pacage.s implementation. Thus" in some cases at least" interface and implementation end up in the same file after all. As an e,ample" consider a simple pacage for displaying te,t on a character mode terminal. 2ig- ure 3G shows what the specification might loo lie. When using the 95AT compiler" pacage specifications are stored in files with a .ads e,tension using the same (ase name as the name of the pacage. 'n this case" the file would (e screen.ads. There is no e,ecuta(le code in the specification4 it only contains declarations. The e,ample shows a few types (eing declared and then some procedures that mae use of those types. Pacages can also contain functions. Ance the specification has (een written code that maes use of the pacage can (e compiled. -uch a compilation unit contains a statement such as 0with Fcreen1 in its conte,t clause. 't can then" for e,ample" refer to the type Fcreen.Dow_TBpe and call procedure Fcreen.Print as you might e,pect. 5ote that a pacage specification can contain a conte,t clause of its own if it needs" for e,ample" types defined in some other pacage. The pacage (ody" stored in a .adb file" contains the implementation of the various su(programs *a!e 1) of 3# pac&age Fcreen is tBpe Dow_TBpe is range +..*C; tBpe 6olu%n_TBpe is range +..G1; tBpe 6olor_TBpe is (<lac& Ded (reen <lue Ihite#; procedure Fet_6ursor_Position (Dow . in Dow_TBpe; 6olu%n . in 6olu%n_TBpe#; procedure (et_6ursor_Position (Dow . out Dow_TBpe; 6olu%n . out 6olu%n_TBpe#; procedure Fet_Text_6olor(6olor . in 6olor_TBpe#; procedure (et_Text_6olor(6olor . out 6olor_TBpe#; procedure Print(Text . Ftring#; end Fcreen; Figure 1.: )xam&le Package 0&eci$ication declared in the specification. The Ada compiler checs for consistency (etween the specification and the (ody. +ou must implement all su(programs declared in the specification and you must even use e,actly the same names for the parameters to those su(programs. 'n addition" the (ody can define types and su(programs that are not declared in the specification. -uch entities can only (e used inside the pacage (ody4 they are not visi(le to the users of the pacage. 2igure 3I shows an a((reviated version of screen.adb. The pacage (ody does not need to include a with clause for its own specification" however it can with other pacages as necessary in order to gain access to the resources provided (y those pacages. When (uilding a large program the pacage specifications can all (e written first" (efore any real coding starts. The specifications are thus the final output of the design phase of the software de- velopment life cycle. These specifications can (e compiled separately to verify that they are free from synta, errors and that they are internally consistent. The compiler can verify that all the necessary dependencies are e,plicitly declared via appropriate with statements" and that all types are used in a manner that is consistent with their declarations. Ance the specifications are in place" the (odies can (e written. 8ecause a pacage (ody only de- pends on the specifications of the pacages it uses" the (odies can all (e written in parallel" (y dif- ferent people" without fear of inconsistency creeping into the program = . Programmers could (e for(idden to modify any specification files )for e,ample (y using appropriate access control fea- tures on a file server or version control system*" requiring any such modifications to first (e cleared (y a designer. -urprisingly few programming languages en:oy this level of rigor in the management of code" (ut Ada was designed for large software pro:ects and so its features are strong in this area. Package Initialiation Pacages sometimes contain internal varia(les that need to (e initiali7ed in some comple, way 3 Inconsistenc& at one level of abstraction, t5at is. %5ere is still t5e ossibilit& t5at t5e semantics of a subro!ra" in one ac+a!e "i!5t be inconsistent fro" t5at e/ected b& t5e subro!ra"7s caller in a different ac+a!e. *a!e 1' of 3# pac&age bodB Fcreen is 22 'ot declared in the spec. This is )or internal use onlB. procedure Helper is begin 22 I%ple%entation not shown. end Helper; 22 All subprogra%s declared in spec %ust be i%ple%ented. procedure Fet_6ursor_Position (Dow . in Dow_TBpe; 6olu%n . in 6olu%n_TBpe# is begin 22 I%ple%entation not shown. end Fet_6ursor_Position; 22 etc... end Fcreen; Figure 1/: )xam&le Package 5od1 (efore the pacage can (e used. The pacage author could provide a procedure that does this ini - tiali7ation" (ut then there is a ris that it won.t get called when it should. 'nstead" a pacage can define some initiali7ation code of ar(itrary comple,ity (y introducing an e,ecuta(le section in the pacage (ody. 2igure 6J shows how this can (e done. 'n this e,ample" an internal varia(le 6ounter is initiali7ed (y calling a function in a supporting pacage Other. This initiali7ation is done when the pacage (ody is elaborated. 5otice that it is necessary in this e,ample for the (ody of pacage Other to (e ela(orated first so that its initial- i7ation statements )if any* e,ecute (efore the ela(oration of the (ody of pacage $xa%ple. 'f that were not the case" then function Loo&up_Initial might not wor properly. To prevent undefined things from happening" an Ada program will instead raise the e,ception Progra%_$rror at run time if pacages get ela(orated in an inappropriate order. To address this potential pro(lem )since you don.t really want the e,ception either* a pragma is included in the conte,t clause of pacage $xa%ple.s (ody. Pragmas are commands to the compiler that control the way the program is (uilt. The Ada standard defines several pragmas and imple- mentations are allowed to define others. 'n this case the use of pragma $laborate_All forces the (odies of pacage Other and any pacages that pacage Other uses to (e ela(orated (efore the (ody of pacage $xa%ple. 5ote that the with clauses will automatically cause the specifications of the withed pacages to (e ela(orated first" (ut not necessarily the (odies. 'n this case it is essen- tial to control the order in which the pacage (odies are ela(orated. !ence the pragma is neces- sary. 5otice that Ada does not provide any facilities for automatically cleaning up a pacage with the program terminates. 'f a pacage has shutdown requirements a procedure must (e defined for this purpose" and arrangements must (e made to call that procedure at an appropriate time. 'n em(edded systems" one of the ma:or target application areas for Ada" programs are often never end. Thus the asymmetric handling of pacage initiali7ation and cleanup is reasona(le in that con- te,t. Ather programming languages do provide 0module destructors1 of some ind to deal with this matter more uniformly. !"ild Packages 8eing a(le to put code into various pacages is useful" (ut in a large program the num(er of pac- *a!e 2- of 3# with Other; prag%a $laborate_All(Other#; pac&age bodB $xa%ple is 6ounter . Integer; 22 Internal ,ariable. procedure Fo%e_Operation is begin 22 I%ple%entation not shown. end Fo%e_Operation; begin 6ounter .- Other.Loo&up_Initial(/database.,tc.,sc.edu/#; end $xa%ple; Figure 22: Package 'ith Initiali6ation 0ection ages might also (e large. To cope with this Ada" lie many languages" allows its pacages to (e organi7ed into a hierarchy of pacages" child pacages" grand child pacages" and so forth. This allows an entire li(rary to (e contained in a single pacage and yet still allows the various compo- nents of the li(rary to (e organi7ed into different pacages )or pacage hierarchies* as well. This is an essential facility for any language that targets the construction of large programs. As an e,ample" consider a hypothetical data compression li(rary. At the top level we might de- clare a pacage 6o%press to contain the entire li(rary. Pacage 6o%press itself might (e empty with a specification that contains no declarations at all )and no (ody*. Alternatively one might in- clude a few li(rary-wide type definitions or helper su(programs in the top level pacage. Ane might then define some child pacages of 6o%press. -uppose that 6o%press.Algo contains the compression algorithms and 6o%press.9tilitB contains utility su(programs that are used (y the rest of the li(rary (ut that are not directly related to data compression ? . 2urther child pac- ages of 6o%press.Algo might (e defined for each compression algorithm supported (y the li(rary. 2or e,ample" 6o%press.Algo.LAI might provide types and su(programs related to the >LW com- pression algorithm and 6o%press.Algo.Hu))%an might provide types and su(programs related to the !uffman encoding compression algorithm. 2igure 63 shows a procedure that wishes to use some of the facilities of this hypothetical li(rary. 'n this e,ample ' assume the >LW pacage provides a type LAI_$ngine that contains all the infor- mation needed to eep trac of the compression algorithm as it wors )presuma(ly a record of some ind*. ' also assume that the pacage provides a procedure Process that updates the com- pressed data using the given string as input. Clearly a pacage hierarchy with many levels of child pacages will produce very long names for the entities contained in those deeply nested pacages. This can (e awward" (ut Ada provides two ways to deal with that. +ou have already met one way# the use statement. 8y including use 6o%press.Algo.LAI in the conte,t clause" the contents of that pacage are made directly visi(le and the long prefi,es can (e deleted. !owever" Ada also allows you to rename a pacage to something shorter and more convenient. 2igure 66 shows how it could loo. The pacage FPueeQe is not a real pacage" (ut rather :ust a shorter" more convenient name for an e,isting pacage. This allows you to reduce the length of long prefi,es without eliminating them entirely. Although the Ada community encourages the use of long" descriptive names in Ada programs" names that are local to a single procedure can sensi(ly (e fairly short since they have limited scope. Bsing the renaming facility of the language you can introduce a((reviated names for pacages )or other inds of entities* with limited scope without compromising the overall read- a(ility of the program. 4 It "i!5t be aroriate to "a+e suc5 a ac+a!e a &rivate &ackage, but t5at feature is not discussed 5ere. *a!e 21 of 3# with 6o%press.Algo.LAI; procedure Hello is 6o%pressor . 6o%press.Algo.LAI.LAI_$ngine; begin 6o%press.Algo.LAI.Process(6o%pressor /6o%press >e!/#; end Hello; Figure 21: 0keleton Program 3sing 71&othetical Com&ress %ibrar1 5otice that the optimal names to use for entities in a pacage will depend on how the pacage it- self is used. 'n the e,ample a(ove the pacage LAI provides a type LAI_$ngine. 'n cases )such as shown* where fully qualified names are used the 0>LW1 in the name 0>LWM<ngine1 is redun- dant and distracting. 't might mae sense to :ust name the type 0<ngine1 yielding a fully qualified name of 6o%press.Algo.LAI.$ngine. An the other hand" if use statements are used the name 0<ngine1 (y itself is rather am(iguous )what ind of engine is thatH*. 'n that case it maes more sense to eep the name 0>LWM<ngine.1 /ifferent programmers have different ideas a(out how much name qualification is appropriate and it leads to differences in the way names are selected. The pro(lem is that the programmer who write a pacage is often different from the programmer who uses it and so incompati(le naming styles can arise. Ada.s renaming facility gives the using programmer a certain degree of control over the names that actually appear in his or her code" despite the names selected (y the author of a li(rary. 2igure 6= shows an e,ample of a more radi- cal approach to renaming. 5otice that while pacages and su(programs )and also o(:ects* can (e renamed" types can not (e renamed in this way. 'nstead you can introduce a su(type without any constraints as a way of ef- fectively renaming a type. 'n this simple e,ample" the renaming declarations (ul up the code more than they save. !ow- ever" in a longer and more comple, situation they can (e useful. An the other hand" you should use renaming declarations cautiously. People reading your code may (e confused (y the new names if it is not very clear what they represent. 1.1 Abstract 2ata T,(es Aften it is desira(le to hide the internal structure of a type from its users. This allows the designer of that type to change its internal structure later without affecting the code that uses that type. Ada supports this concept (y way of private types. A type can (e declared as private in the visi(le part of a pacage specification. Bsers can then create varia(les of that type and use the (uilt in *a!e 22 of 3# with 6o%press.Algo.LAI; procedure Hello is pac&age FPueeQe rena%es 6o%press.Algo; 6o%pressor . FPueeQe.LAI.LAI_$ngine; begin FPueeQe.LAI.Process(6o%pressor 6o%press >e!"#; end Hello; Figure 22: Com&ression )xam&le "ith Package 4enaming wit5 Co"ress.Al!o.289: procedure Hello is subtBpe LAI_TBpe is 6o%press.Algo.LAI.LAI_$ngine; procedure 6o%p($ngine . LAI_TBpe; Hata . Ftring# rena%es 6o%press.Algo.LAI.Process; 6o%pressor . LAI_TBpe; begin 6o%p(6o%pressor /6o%press >e!/#; end Hello; Figure 23: Com&ression )xam&le "ith Arbitrar1 4enaming assignment and equality test operations on that type. All other operations" however" must (e pro- vided in the pacage where the type is defined. -u(programs in the same pacage as the type have access to the type.s internal representation. 2igure 6? shows a hypothetical pacage that provides a type representing calendar dates. 5ote that in a more realistic version of this pacage" one might introduce different types for year" month" and day values in order to prevent programs from accidentally mi,ing up those concepts. !owever" in the interest of (revity ' do not show that in this e,ample. The type Hate is declared private in the visi(le part of the specification. 't is then later fully defined as a record in the pri - vate part. Theoretically the full view of a type should not (e in the specification at all4 it is part of the pac- age.s implementation and thus should only (e in the pacage (ody. !owever" Ada requires that private types (e fully defined in pacage specifications as a concession to limited compiler tech- nology. When the compiler translates code that declares varia(les of the private type" it needs to now how much memory to set aside for such varia(les. Thus while the programmer is for(idden to mae use of the private type.s internal structure" the compiler needs to do so. 5ote that some programming languages go further than Ada in this regard and move all such private information out of the interface definition. !owever" there is generally an e,ecution performance penalty in- volved in doing this. 'n Ada it is possi(le to simulate such a feature using the so called 0pimpl id- iom.1 This method involves access types and controlled types and so is not descri(ed further here. 5ote also that the full view of a private type does not need to (e a record type. Although records are common in this situation" private types can (e implemented as arrays or even :ust simple scalars lie Integer or 3loat. Private types do allow assignment and equality tests. !owever" in some cases it is desira(le to disallow those things. Ada maes this possi(le using limited private types. A declaration such as tBpe Hate is li%ited pri,ate4 tells the compiler to disallow (uilt in assignment and equality tests for the specified type. This does not mean assignment is impossi(le4 it only means that the pacage author must now pro- vide a procedure to do assignment;if support for assignment is desired. Presuma(ly that proce- dure would tae whatever steps were necessary to mae the assignment wor properly. Calendar *a!e 23 of 3# pac&age $xa%ple is tBpe Hate is pri,ate; )unction >a&e(@ear >onth HaB . Integer# return Hate; )unction (et_@ear(TodaB . Hate# return Integer; 22 etc... )unction HaB_Hi))erence(3uture Past . Hate# return Integer; 22 etc... pri,ate tBpe Hate is record @ . Integer; > . Integer; H . Integer; end record; end $xa%ple; Figure 2: 0&eci$ication o$ a Package $or Calendar ,ates dates are not good candidates to mae into a limited type. The component-wise assignment of one date to another is e,actly the correct way to assign dates. Thus the (uilt in record assignment operation is fine. -imilar comments apply to the (uilt in test for equality operation. !owever" types that represent resources outside the computer system )for e,ample a networ connection* can.t reasona(ly (e assigned. They should (e declared limited private instead. 1.13 Strin)s To be written... 1.11 E4ce(tions >ie many modern programming languages" Ada allows su(programs to report error conditions using exceptions. When an error condition is detected an e,ception is raised. The e,ception prop- agates to the dynamically nearest handler for that e,ception. Ance the handler has e,ecuted the e,ception is said to have (een handled and e,ecution continues after the handler. <,ceptions are not resuma(le. This model is largely the same as that used (y C$$ although the terminology is different. !owever" unlie C$$" Ada e,ceptions are not ordinary o(:ects with ordinary types. 'n fact" Ada e,ceptions don.t have a type at all and e,ist outside the language.s type system. <,ceptions are typically defined in a pacage specification. They are then raised in the pacage (ody under appropriate conditions and handled (y the pacage users. 2igure 6C shows part of a specification for a <ig_'u%ber pacage that supports operations on ar(itrary precision integers. 5otice that Ada" lie C$$" allows operators to (e overloaded. 'n Ada this is done (y defining func- tions with names given (y the operator names in quotation mars. This pacage also defines an e,ception that will (e raised when one attempts to use <ig_'u%ber./;/ with a 7ero divisor. The implementation of the division operation might loo" in part" as shown in 2igure 6D. As you might guess" the raise statement a(orts e,ecution of the function immediately. A proce- dure that wishes to use <ig_'u%ber might try to handle this e,ception in some useful way. 2igure 6C shows the synta,. *a!e 24 of 3# pac&age <ig_'u%ber is tBpe 'u%ber_TBpe is pri,ate; Hi,ide_<B_Aero . exception; )unction /:/(Le)t Dight . 'u%ber_TBpe# return 'u%ber_TBpe; )unction /2/(Le)t Dight . 'u%ber_TBpe# return 'u%ber_TBpe; )unction /E/(Le)t Dight . 'u%ber_TBpe# return 'u%ber_TBpe; )unction /;/(Le)t Dight . 'u%ber_TBpe# return 'u%ber_TBpe; pri,ate 22 'ot shown. end <ig_'u%ber; Figure 2#: 0&eci$ication $or Package Big_Number 8Abbreviated9 The (loc delimited (y begin and end can contain a header exception. After that header a series of when clauses specify which e,ceptions the (loc is prepared to handle. The special clause when others is optional and is used for all e,ceptions that are otherwise not mentioned. 'f the normal statements in the (loc e,ecute without e,ception" control continues after the (loc )sipping over the e,ception clauses*. 'n the e,ample a(ove the procedure returns at that point. 'f an e,ception occurs in the (loc" that e,ception is matched against those mentioned in the when clauses. 'f a match is found the corresponding statements are e,ecuted and then control continues after the (loc. 'f no match is found" the (loc is a(orted and the ne,t dynamically en- closing (loc is searched for a handler instead. 'f you are familiar with C$$ or %ava e,ceptions none of this should (e surprising. 2igure 6E also shows an interesting detail related to operator overloading. The e,ample assumes that there is a conte,t clause of with <ig_'u%ber )not shown* (ut no use statement. Thus the di- vision operator is properly named <ig_'u%ber./;/. Bnfortunately it can.t (e called using the infi, operator notation with that name. There are several ways to get around this. Ane could include a use <ig_'u%ber in the conte,t clause or in the procedure.s declarative region. !owever that would also mae all the other names in pacage <ig_'u%ber directly visi(le and that might not (e desired. An alternative is to introduce a local function named /;/ that is :ust a renaming )essen- tially an alias* of the function in the other pacage. As we have seen Ada allows such renaming declarations in many situations" (ut in this case" every operator function would need a corre- sponding renaming and that could (e tedious. 2igure 6E shows a more elegant approach. The use tBpe declaration tells the compiler that the primitive operations of the named type should (e made directly visi(le. ' will discuss primitive op- erations in more detail in the section on o(:ect oriented programming. 'n this case" the operator overloads that are declared in pacage <ig_'u%ber are primitive operations. This method allows all the operator overloads to (e made directly visi(le with one easy statement" and yet does not mae every name in the pacage directly visi(le. The Ada language specifies four predefined e,ceptions. These e,ceptions are declared in pacage -tandard )recall that pacage -tandard is effectively (uilt into the compiler* and thus directly visi - (le at all times. The four predefined e,ceptions with their use is shown in the following ta(le. 6onstraint_$rror (aised w5enever a constraint is violated. %5is includes !oin! outside t5e bounds of a subt&e <or e=uivalentl& t5e allowed ran!e of an arra& inde/> as well as various ot5er situations. *a!e 25 of 3# )unction /;/(Le)t Dight . 'u%ber_TBpe# return 'u%ber_TBpe is begin 22 Assu%e there is a suitable o,erloaded -" operator. i) Dight - 1 then raise Hi,ide_<B_Aero; end i); 22 Proceed &nowing that the di,isor is not Qero. end /;/; Figure 2*: Im&lementation o$ Big_Number."/" procedure $xa%ple is use tBpe <ig_'u%ber.'u%ber_TBpe; ? @ A . <ig_'u%ber.'u%ber_TBpe; begin 22 3ill @ and A with interesting ,alues. ? . - @ ; A; exception when <ig_'u%ber.Hi,ide_<B_Aero -4 Put_Line(/<ig 'u%ber di,ision bB Qero!/#; when others -4 Put_Line(/9nexpected exception!/#; end $xa%ple; Figure 2+: 7andling 5ig:Number )xce&tions Progra%_$rror (aised w5en certain ill for"ed ro!ra"s t5at can7t be detected b& t5e co"iler are e/ecuted. 3or e/a"le, if a function ends wit5out e/ecutin! a return state"ent, Progra%_$rror is raised. Ftorage_$rror (aised w5en t5e ro!ra" is out of "e"or&. %5is can occur durin! d&na"ical "e"or& allocation, or be due to a lac+ of stac+ sace w5en invo+in! a subro!ra". %5is can also occur durin! t5e elaboration of a declarative re!ion <for e/a"le if t5e d&na"ic bounds on an arra& are too lar!e>. Tas&ing_$rror (aised in connection wit5 certain tas+in! roble"s. It is outside t5e scoe of t5is tutorial to cover t5ese details. Most of the time the predefined e,ceptions are raised automatically (y the program under the ap- propriate conditions. 't is legal for you to e,plicitly raise them if you choose" (ut it is recom- mended that you define your own e,ceptions for your code. 5ote that the Ada standard li(rary de- fines some additional e,ceptions as well. Those e,ceptions are not really predefined (ecause" un- lie the four a(ove" they are not (uilt into the language itself. 1.12 2iscri*inated T,(es To be written... 1.1" 5enerics -tatically checed strongly typed languages lie Ada force su(program argument types and pa- rameter types to match at compile time. This is awward in situations where the same sequence of instructions could (e applied to several different types. To satisfy the compile time type chec- ing requirements" it is necessary to duplicate those instructions for each type (eing used. To get around this pro(lem" Ada allows you to define generic su(programs and generic pacages where the types used are parameters to the generic unit. Whenever a new 0version1 of the generic unit is needed" it is instantiated (y the compiler for specific values of the type parameters. Ada generics are very similar in concept and purpose to C$$ templates. >ie C$$ templates" generics are handled entirely at compile time4 each instantiation generates code that is special- i7ed for the types used to instantiate it. This is different than generics in %ava which are resolved at run time and that use a common code (ase for all instances C . !owever" Ada generics and C$$ templates also differ in some important ways. 2irst Ada requires the programmer to e,plicitly in- stantiate a generic unit using special synta,. 'n C$$ instantiations are done implicitly. %ust men- tioning the instance causes it to come into e,istence D . 'n addition" Ada generics do not support e,- plicit speciali7ation or partial speciali7ation" two features of C$$ templates thare used in many advanced template li(raries. There are pros and cons to Ada.s approach as compared to C$$.s method. With Ada" it is very clear where the instantiation occurs )since it is shown e,plicitly in the source code*. !owever" C$ $.s method ena(les advanced programming techniques )template meta-programming* that Ada can.t easily replicate. The other ma:or difference (etween Ada generics and C$$ templates is that Ada allows the pro- grammer to specify the necessary properties of the types used to instantiate a generic unit. 'n 5 Actuall& Ada !enerics allow for t5e ossibilit& of s5arin! code, deendin! on t5e co"iler7s i"le"entation strate!&. $ C?? also allows e/licit instantiation of te"lates, but it is rarel& used. *a!e 2$ of 3# contrast in C$$ one only says that the parameter is a type. 'f a type is used to instantiate a tem- plate that doesn.t mae sense" the compiler only reali7es that when it is actually doing the instan- tiation. The resulting error messages are highly cryptic and misleading. 'n contrast the Ada com- piler can chec (efore it (egins the instantiation process if the given types are accepta(le. 'f they are not" it can provide a much clearer and more specific error message. To illustrate how Ada generics loo" consider 2igure 6G that shows the specification of a generic pacage containing a num(er of sorting procedures. 5otice that the specification has a generic header that defines the parameters to this generic unit. The first such parameter is a type that will (e called $le%ent_TBpe in the scope of the generic pacage. 't is declared as a private type to indicate that the pacage will only )(y default* (e a(le to assign and compare for equality o(:ects of that type. 't is thus possi(le to instantiate this pacage for private types" (ut non-private types lie 'ntegers" arrays" and records also have the necessary a(ilities and can (e used. !owever" a limited type )for e,ample" a type declared as li%ited pri,ate in some other pacage* can not (e used. This generic pacage also requires its user to provide a function that can compare two $le%ent_TBpe o(:ects. That function is called /0/ in the scope of the pacage" (ut it could (e called anything (y the user. 't must" however" have the same profile )the same num(er and type of parameters*. 'nside the implementation of the generic pacage" $le%ent_TBpe can (e used as a private type e,cept that it is also permitted to use /0/ to compare two $le%ent_TBpe o(:ects. 5o other opera- tions on $le%ent_TBpe o(:ects are allowed to guarantee the pacage will instantiate correctly with any type the user is allowed to use. 2igure 6I shows how this pacage might (e used. *a!e 2# of 3# generic tBpe $le%ent_TBpe is pri,ate; with )unction /0/(Le)t Dight . $le%ent_TBpe# return <oolean; pac&age Forters is tBpe $le%ent_ArraB is arraB('atural range 04# o) $le%ent_TBpe; procedure Ruic&_Fort(FePuence . in out $le%ent_ArraB#; procedure Heap_Fort(FePuence . in out $le%ent_ArraB#; procedure <ubble_Fort(FePuence . in out $le%ent_ArraB#; end Forters; Figure 2.: 0&eci$ication o$ a ;eneric Package $or 0orting 5otice the first line in the declarative region that instantiates the generic unit. 'n the e,ample" named parameter association is used to (ind the generic unit.s arguments to its parameters. The strange looing construction /0/ -4 Ftandard./0/ is an association (etween the generic param- eter /0/ )the comparison function* and the operator 0N1 that applies to integers )declared in pacage -tandard*. 't would (e more typical for the right side of this association )and even the left side as well* to (e normally named functions. The name Integer_Forters is given to the specific instance created. That name can then (e used lie the name of any other pacage. 'n fact" it is legal )and common* to follow a generic instantia- tion with a use statement to mae the contents of the newly instantiated pacage directly visi(le. Ada also allows procedures and functions to (e generic using an analogous synta,. The e,ample in 2igure 6G is fairly simple in that the generic type parameter has very limited a(ili- ties. 't is also possi(le to specify that the parameter is a discrete type )thus allowing the use of 73irst" 7Last" 7Fucc and 7Pred attri(utes*" an access type" a tagged type" a modular type" a floating point type" and various other possi(ilities. 'n addition" Ada.s generic facility allows generic units to (e parameteri7ed on values )so called 0non-type1 parameters in C$$* and varia(les. ' re- fer you to one of the references for more information on generic units in Ada. The discussion here is only scratching the surface of the topic. 1.1& Access T,(es and 2,na*ic 6e*or, Allocation Ada" lie many languages" allows you to create o(:ects that refer to other o(:ects. 't also allows you to create o(:ects that have a lifetime e,tending (eyond that of the scope in which they are created. 8oth of these capa(ilities are important and many programming techniques depend on them. C and C$$ allow the programmer to use ar(itrary pointers" implemented as simple mem- ory addresses" in any way desired. While this is very powerful" it is also very dangerous. C and C$ $ programs suffer from many (ugs and security vulnera(ilities related to the unrestricted use of pointers in those languages. 'n Ada pointer types are called access types. >ie C and C$$ pointer varia(les" access varia(les can (e manipulated separately from the o(:ects to which they point. !owever" unlie C and C$$ pointer types" access types in Ada have a num(er of restrictions on their use that are designed to mae them safer. Actually" the history of access types in Ada is quite interesting. 'n Ada G= access types were very limited (ut also very safe. !owever" e,perience with Ada showed that the limitations were too *a!e 2) of 3# with Forters; procedure $xa%ple is pac&age Integer_Forters is new Forters($le%ent_TBpe -4 Integer /0/ -4 Ftandard./0/#; Hata . Integer_Forters.$le%ent_ArraB; begin 22 3ill Hata with interesting in)or%ation. Integer_Forters.Ruic&_Fort(Hata#; end $xa%ple; Figure 2/: Instantiating a generic &ackage< great. Ada IC removed some of the limitations while still managing to eep the safety )at the e,- pense of complicating the language*. +et even after these changes access types were still not as fle,i(le as desired. Ada 6JJC removed yet more limitations (ut now requires" in certain cases" run time checing to (e done to ensure safety E . 'n this tutorial ' will not descri(e these issues in de- tail. My focus here is on the (asic use of access types in Ada. Access types can (e named or anonymous. ' will only consider named access types4 anonymous access types have special properties that are outside the scope of this tutorial. 2or e,ample the declaration tBpe Integer_Access is access Integer; declares Integer_Access as a type suita(le for accessing" or pointing at" integers. 5otice that in this tutorial ' have used a suffi, of E_TBpe when naming a type. 'n this case" however" ' use a suffi, of E_Access to emphasi7e the nature of the access type. This is" of course" :ust a conven- tion. Ance the access type has (een declared" varia(les of that type can then (e declared in the usual way. P . Integer_Access; Ada automatically initiali7es access varia(les to the special value null if no other initiali7ation is given. Thus access varia(les are either null or they point at some real o(:ect. 'ndeed" the rules of Ada are such that dangling pointers are not possi(le G . Access varia(les can (e copied and com- pared lie any other varia(le. 2or e,ample if P+ and P* are access varia(les than P+ - P* is true if they (oth point at the same o(:ect. To refer to the o(:ect pointed at (y an access varia(le you must use the special .all operation. P.all .- +; The .all plays the same role in Ada as the indirection operator )the E* plays in C and C$$. The use of .all may seem a little odd in this conte,t" (ut understand that most of the time access types are pointers to records. 'n that case" the components of the record pointed at can (e ac- cessed directly (y using the component selection operation on the access varia(le itself. 2igure =J illustrates. 'n this case the .all synta, is very natural. 't shows that you are accessing all the mem(ers of the referenced o(:ect at the same time. 't is important to notice that Ada normally 0forwards1 op- erations applied to the access varia(le to the referenced o(:ect. Thus H+.HaB in the e,ample means the HaB component of the o(:ect pointed at (y H+. Anly operations that are meaningful for the access type itself are not forwarded. Thus H+ .- H* copies the access values. To copy the o(- :ects pointed at (y the access varia(les one must use the .all synta,. ' should also note that synta, such as H+.all.HaB" while ver(ose" is also legal. The .all dereferences H+. The result is a date record so the selection of the HaB component is meaningful. # %5ese run ti"e c5ec+s are in cases t5at were reviousl& ille!al. 95en usin! access t&es in older wa&s Ada 2--5 access t&es re=uire no run ti"e c5ec+s over w5at older Ada versions re=uired. ) %5is isn7t t5e w5ole stor&. It would be "ore accurate to sa& t5at dan!lin! ointers aren7t ossible as lon! as 9nchec&ed_Heallocation is never used. *a!e 2' of 3# Access varia(les that refer to arrays also allow the normal array operations to (e forwarded to the referenced o(:ect. 2igure =3 illustrates. 8ecause of forwarding" using access types is generally quite convenient in Ada. !owever" you must eep in mind that operations that are meaningful for the access types themselves will (e ap- plied directly to the access o(:ects and are not forwarded. -o far we.ve seen how to declare and use access types. !ow does one get an access varia(le to point at another o(:ect in the first placeH 'n Ada G= there was only one way# using the new opera- tion. 2or e,ample P .- new Integer7(1#; dynamically allocates an integer" initiali7es that integer to 7ero" and then assigns the resulting ac- cess value to P. !ere ' assume P has an access to integer type. 5otice that argument to new has the form of a qualified e,pression )the apostrophe is required*. Also as with dynamically allocated o(:ects in other languages" the lifetime of the o(:ect created in this way e,tends (eyond the life- time of the access varia(le used to point at it. #arbage !ollection$ 'n many languages dynamically allocated o(:ects are automatically reclaimed when they can no longer (e accessed. 2or e,ample" in Ada parlance" when all access varia(les pointing at an o(:ect *a!e 3- of 3# tBpe Hate is record HaB >onth @ear . Integer; end record; tBpe Hate_Access is access Hate; H+ H* . Hate_Access; ... H+.HaB .- +; 22 Accesses the HaB %e%ber o) re)erenced Hate. H+ .- H*; 22 6auses H+ to point at sa%e obNect as H*. H+.all .- H*.all; =2 6opies Hate obNects. Figure 32: Access T1&e 01ntax tBpe <u))er_TBpe is arraB(1..+1*L# o) 6haracter; tBpe <u))er_Access is access <u))er_TBpe; <+ <* . <u))er_Access; ... <+ .- <*; 22 6opies onlB the access ,alues. <+.all .- <*.all 22 6opies arraBs. <+(1# .- 7?7 22 3orwards index operation. )or I in <+7Dange loop 22 3orwards 7Dange attribute. ... end loop; Figure 31: Access to Arra1 T1&es go out of scope the o(:ect pointed at (y those varia(les can no longer (e referenced and the memory it uses should (e made availa(le again. The process of reclaiming such memory is called garbage collection. 'n Ada gar(age collection is optional. 'mplementations are allowed to provide it" (ut they are not required to do so. This may seem surprisingly wishy-washy for a language that endeavors to sup- port relia(le and porta(le programming. The pro(lem is that Ada also endeavors to support low level em(edded systems and real time programming. 'n such environments gar(age collection is widely considered a (ad idea. 't is difficult to meet real time o(:ectives if a comple, gar(age col- lection algorithm might run at any time. Also the space overhead of having a gar(age collector in the run time system might (e unaccepta(le for space constrained em(edded devices. Advances in gar(age collection technology has made some of these concerns less pressing today than they were when Ada was first designed. !owever" these matters are still important. Thus Ada allows" (ut does not require gar(age collection. This presents an immediate pro(lem for programmers interested in porta(ility. 'f the implementa- tion does not collect its gar(age and the programmer taes no steps to manually reclaim allocated o(:ects" the program will lea memory. This is a disaster for long running programs lie servers. Thus for ma,imum porta(ility one must assume that gar(age collection is not done and tae steps accordingly. 'n fact" most Ada implementations do not provide gar(age collection" so this is a very realistic concern. The Ada li(rary provides a generic procedure named 9nchec&ed_Heallocation that can (e used to manually deallocate a dynamically allocated o(:ect. Bnfortunately the use of 9nchec&ed_Heal2 location can violate important safety properties the language otherwise provides. 'n particular" if you deallocate an o(:ect while an access varia(le still points at it" any further use of that access varia(le will result in erroneous (ehavior I . As a service 9nchec&ed_Heallocation will set the ac- cess varia(le you give it to null causing future use of that access varia(le to result in a well de- fined e,ception. !owever" there might (e other access varia(les that point at the same o(:ect and 9nchec&ed_Heallocation can not now a(out all of them in general. 'f your program never uses 9nchec&ed_Heallocation then all access varia(les are either null or point at a real o(:ect4 dangling pointers are impossi(le. !owever" your program might also lea memory if the Ada implementation does not provide gar(age collection. Thus in most real pro- grams 9nchec&ed_Heallocation is used. This is an e,ample of where Ada compromises safety for the sae of practical reality. 'n fact" there are several other 9nchec&ed_E operations in Ada that are used to address certain practical concerns and yet introduce the possi(ility of unsafe programs. -ince every such operation starts with the word 0Bncheced1 it is an simple matter to search an Ada program for occurrences of them. This feature maes reviewing the uncheced operations easier. Show an example of Unchecked_Deallocation... 1.1' Co**and Line Ar)u*ents and 7ile #andlin) To be written... 1.1+ Ob8ect Oriented /ro)ra**in) To be written... ' %5e Ada co""unit& uses t5e 5rase @erroneous be5aviorA to refer to undefined be5avior of all +inds, includin! ro!ra" cras5es. *a!e 31 of 3# 1.1- Tas0in) Many programs can (e naturally descri(ed as multiple" interacting" concurrent threads of e,ecu- tion. Programming environments that provide direct support for concurrency are thus very useful. -uch support can (e offered (y the operating system or (y the programming language or some com(ination of the two. The classic way in which operating systems support concurrency is (y al - lowing multiple independent processes to run simultaneously. This method has the advantage of offering good isolation (etween the processes so that if one crashes the others are not necessarily affected. An the other hand" communication (etween processes tends to have high overhead. Modern operating systems also usually allow programs to (e written that have multiple threads of control e,ecuting in the same process. This thread level concurrency is harder to program cor- rectly (ut has reduced overhead as compared to the older style process level concurrency. 'n some environments offering thread level concurrency the programmer must invoe su(pro- grams in a special li(rary to create and synchroni7e threads. -uch an approach requires relatively little support from the programming language (ut it tends to (e error prone. Another approach is to (uild support for thread level concurrency into the programming language itself. This allows the compiler to tae care of the low level details of thread management" freeing the programmer to focus on other aspects of the program.s design. Ada uses this second approach and supports con- current programming as a language feature. The unit of e,ecution in Ada is called a task. The main program e,ecutes in a tas called the envi- ronment task. +ou can create additional tass as appropriate to meet your application.s needs. >ie a pacage each tas has a specification and a (ody. 'n the simplest case a tas specification only needs to declare that the tas e,ists. 2igure =6 illustrates the (asic synta,. 'n this e,ample a tas 'ag is (oth specified and defined in the declarative region of the main pro- gram. The tas simply prints 0!ello1 one hundred times with a 3J second delay (etween each line of output. While the tas does this important wor" the main program simultaneously e,ecutes the useful function of the program. *a!e 32 of 3# with Ada.Text_IO; with Helper; procedure >ain is = Fpeci)ication o) nested tas&. tas& 'ag; = <odB o) nested tas&. tas& bodB 'ag is begin )or I in + .. +11 loop Ada.Text_IO.Put_Line(/Hello/#; delaB +1.1; end loop; end 'ag; begin Helper.Fo%ething_9se)ul; end >ain; Figure 32: 0im&le Nested Task 't is important to understand that the tas starts e,ecuting automatically as soon as the enclosing su(program (egins. 't is not necessary to e,plicitly start the tas. 2urthermore the enclosing su(- program will not return until the tas has completed. Care must (e taen to ensure that the tas eventually ends. 'f the tas never ends the enclosing su(program will never return. 8ecause the tas is nested inside another program unit it has access to the local varia(les and other entities declared in the enclosing unit a(ove the tas.s definition. This gives a way for the tas to share information with the enclosing unit (ut (eware that sharing data in this manner is difficult and error prone. As ' will descri(e shortly Ada provides much more ro(ust ways for tass to communicate. The e,ample a(ove shows a tas nested inside a procedure. Tass can also (e nested inside func- tions or even inside each other. This allows you to create a tas to assist in the e,ecution of any su(program without anyone outside your su(program (eing aware that tass are involved. +ou can also create tass inside a pacage (ody that support the operation of that pacage. 8e aware" however" that if you do create a tas inside a li(rary pacage (ody you need to arrange for that tas to eventually end or else the program will never terminate. 1.1. Container Librar, To be written... 1.11 Lo! Leel /ro)ra**in) To be written... SECTION 2 CASE STU29: #U776AN ENCO2IN5 To (etter understand the features of Ada" it is helpful to wor through a small (ut realistic pro- gram using the language. 'n this section ' will design and implement a simple file compression utility that uses the !uffman encoding compression algorithm. Although !uffman encoding is not particularly effective (y itself" it is good enough to provide a usa(le utility for some applications. 't also provides a good (alance of comple,ity and simplicity for this e,ercise. 1.23 The Al)orith* !uffman encoding taes advantage of the fact that in most files some (yte values are much more common than others. 8y assigning short (inary codes to the most commonly occurring values the file can (e made smaller. Ane consequence" however" of assigning short codes to some values is that other values must necessarily (e assigned long (inary codes. This is necessary in order to properly distinguish (etween all possi(le values. 2or e,ample" assume that the most commonly occurring value is assigned a single (it code of 3. All other values must necessarily have codes starting with J so that they can (e properly recog- ni7ed. There could (e as many as 6CC such values" requiring G additional (its )for a total of nine (its* to distinguish those values among themselves. !uffman encoding finds a way to assign varia(le length codes to the (yte values to minimi7e the overall file si7e. -pecifically it uses (yte value frequency information to mae the code assign- ments. That is" commonly occurring (ytes are assigned relatively short codes and infrequently oc- curring (ytes are assigned correspondingly longer codes. 'tt can (e shown that !uffman encoding is optimal4 no other compression method that does not tae advantage of correlations can provide *a!e 33 of 3# more compression 3J . !uffman encoding is also an e,ample of a greedy algorithm and is often dis- cussed in algorithms te,t(oos as such. The algorithm has three phases. 3. -can the input and count the num(er of times each (yte value occurs. 6. Construct a code tree that reflects the relative frequency of the (yte values and assign the varia(le length codes to each value. =. Kewrite the input su(stituting the codes assigned in step &6 for the (yte values. Ane significant disadvantage to !uffman encoding is that the input must (e scanned completely to do the frequency analysis (efore any output can (e written. 'n some applications the entire input is not nown initially )for e,ample# streaming data or user input* and that is a ma:or pro(lem for this method. 'n such cases the compressor can sometimes mae an educated guess a(out the rel- ative frequencies of the (yte values" (ased perhaps on past o(servations of similar input" (ut the results will then (e only appro,imate. This is not an issue in this case4 ' am interested in com- pressing files and ' have access to the entire file (efore ' have to compress any of it. The output of the first phase is" conceptually" a ta(le with one entry for each (yte value )6CD en- tries in all*. Associated with each entry is a count of the num(er of times that value appeared in the input. 2or e,ample" assume the algorithm is applied to a file containing only the letters .A. through .<.. The ta(le output (y the first phase might loo as follows# The ta(le elements (ecome the leaves of a tree. Pseudo code for the tree (uilding algorithm is shown in 2igure ==. <ach pass of the while loop com(ines the counts from the active nodes with the smallest and ne,t smallest count. Those nodes are then removed from the active list and the new node is added to the active list )where its com(ined count is then considered in later passes*. Thus each pass of the while loop reduces the si7e of the active list (y one. <ventually only a single active node is left and that node is the root of the code tree. 2or e,ample using the initial counts as shown a(ove" the result after the first past of the while loop in 2igure == is as follows# 1- Hi!5 end co"ression al!orit5"s alwa&s ta+e advanta!e of correlations for "uc5 5i!5er co"ression ratios. *a!e 34 of 3# A. +*+ <. LS 6. C+C H. J $. M* 'n the ne,t pass of the while loop the nodes with counts ?6 )smallest* and ?C )ne,t smallest* will (e com(ined. After the loop finishes e,ecuting in the sample a(ove the code tree loos lie 5otice that the nodes with large counts" such as the node for .A. are com(ined late in the process. -uch nodes thus end up (eing a short distance from the root of the code tree. This is the (asis for their short codes. 5otice also that the count in the root node ends up (eing the same as the total num(er of (ytes in the input. This can (e used as a validity chec on the code tree construction process. After the code tree has (een constructed" codes are assigned to the original (yte values (y as- signing a 3 or J (it to each lin in the code tree. The assignment can (e ar(itrary without affect- ing the correctness of the result" (ut for the sae of choosing something" ' will assign a 3 (it to the child node with the larger count value. After the (it assignments" the code tree (ecomes# *a!e 35 of 3# IHIL$ 0There is %ore than one acti,e node4 LOOP 03ind nodes x B with the s%allest and next s%allest counts4 06reate a new node Q that co%bines the count ,alues; Point Q at x and B4 0De%o,e x and B )ro% the set o) acti,e nodes4 0Add Q to the set o) acti,e nodes4 $'H Figure 33: 7u$$man code tree building &seudo=code A. C+C <. LS 6. +*+ H. J $. M* . MC A. C+C <. LS 6. +*+ H. J $. M* . MC . GO . *1G . O*L The code for a (yte value is then read from the root" assigning (its from left to right in the code as each lin in the code tree is traversed. 'n my e,ample this yields the codes as shown in Ta(le 3. 5otice how the codes for the most commonly occurring (yte values ).A. and .C.* are short while the codes for the most infrequently occurring (yte values ).8. and ./.* are long. 5otice also that there is no am(iguity in the encoding. 2or e,ample" a (it sequence such as 3JJ33J333JJJ can only (e interpreted as the (yte sequence 0A8CAA<.1 5otice also that if ordinary G (it (ytes are used the string 0A8CAA<1 would consume D (ytes of space. !owever" the (it sequence 3JJ33J333JJJ is only 36 (its )3.C (ytes* long. 1.21 I*(le*entation Notes 8efore looing at the detailed design of the !uffman compression program ' want to point out a few issues of interest. Feep these issues in mind when you review the program.s design and the source code of the program itself. 3. 8oth the input and output files have to (e processed as raw (inary (ytes without structure. To mae the program general" it should not concern itself with the meaning of the input file.s contents. 6. The construction of the code tree can.t start until the input file has (een fully analy7ed. *a!e 3$ of 3# A. C+C <. LS 6. +*+ H. J $. M* . MC . GO . *1G . O*L + 1 + 1 + 1 + 1 A 1 B --11 C -1 , --1- . --- Table 1: 7u$$man Codes $or )xam&le -imilarly no output can (e written until the code tree is fully constructed and code se- quences have (een assigned. This means there is little opportunity for parallelism among these phases of e,ecution. =. The pointers in a code tree node sometimes point at other code tree nodes )presuma(ly al - located dynamically* and sometimes point at the original ta(le of counter values. ?. An au,iliary data structure of some ind will (e necessary to eep trac of which code tree nodes are currently 0active.1 C. -ince the code sequences have varia(le length" writing the output file is tricy. A way must (e provided to write partial (ytes and to write long (it sequences that span multiple (ytes. D. 2or the compressed file to (e decompressed properly the receiver will need to (uild e,actly the same code tree as the sender. Ane way to allow the receiver to do this would (e for the sender to transmit the original counts in a header on the compressed file. 'f =6 (it counts are used" this adds 3J6? (ytes of overhead to the compressed file. E. 'n a realistic e,ample some code sequences can (e very long )one or two hundred (its in an e,treme case*. 't may (e appropriate to use a varia(le length data structure to handle them. SECTION " RE7ERENCES 3. rogramming in !da "##$ (y %ohn 8arnes. Addison-Wesley" 6JJD. '-85OJ-=6-3=?JEG-E. This is the definitive te,t on the latest Ada standard. 6. !da as a Second %anguage" second edition (y 5orman !. Cohen. Mc9raw-!ill" 3IID. '-85OJ-JE-J33DJE-C. This is an e,haustive reference of the Ada IC language. While a (it dated" it is still a very good resource for modern Ada programming. =. &oncurrency in !da" second edition (y Alan 8urns and Andy Wellings. Cam(ridge Bniver- sity Press" 3IIG. '-85OJ-C63-D6I33-P. This (oo focuses on Ada.s features for tasing. This edition only covers Ada IC" and thus does not discuss the significant tasing related additions made in the 6JJC standard. !owever" for many programs" the Ada IC features are more than sufficient. ?. 'igh (ntegrity Software. The S!)* !pproach to Safety and Security (y %ohn 8arnes. Addi- son-Wesley" 6JJ=. '-85OJ-=63-3=D3D-J. This (oo descri(es a speciali7ed su(set of the Ada language called -PAKF that is used for the construction of ultra-relia(le software. C. Wii8oo on Ada# http#@@en.wii(oos.org@wii@AdaMProgramming. This is one of the (etter of the Wii8oos. As always anything on-line is a wor in progress. 5evertheless many as- pects of Ada are well descri(ed. D. Ada 5ewsgroup# news#@@comp.lang.ada. An active newsgroup where you can post ques- tions and tal with Ada e,perts. E. Ada 'KC channel# irc#@@irc.freenode.net@&ada. Although often quiet there are usually a few people there who can answer questions. G. There are several Ada we( sites. The Ada 'nformation Clearinghouse )http#@@www.adaic.- com@*" site is a good place to start. *a!e 3# of 3#