 122 608  D!  IN  MJ  PA  ]`  `@  j>  o.  sI  yI  ~P !$> !(; !/R
 !4D !86 !>. !B# !E` !IE !NL !U\ !g^ !sB !|S ".) "8D "@8 "Q_ "c_
Q"mG "tE "vV "}. #!4Q#'' #9K #@KQ#GT #JK #ND #RJ #Z> #j# #yL $)S
 $7PQ$D3 $H3 $KP $ODQ$S[ $WC $[- $_, $c@ $p/ $x: %(<Q%82 %<I %C%
 %FF %IW %N% %R6 %V> %eN %sY &$F &7.Q&F< &M` &UL &\P &cH &lI &t?
 '!G '3MQ'D1 'F> 'KY 'Q, 'b\A'q7 (#; (.5 (56 (C^ (ZGQ(pU (sF (uK
 (x1 )!' )/2 )>6Q)N^ )U1 )ZL )b/ )oT )}< *3HQ*E# *J( *R5 *W\ *^"
 *d( *t& *}` +1OQ+FX +J7 +M= +P7 +`/ +o^Q+}! ,$9 ,&@ ,)T ,,6 ,.S
 ,2; ,4X ,<N ,KU ,WH ,eDQ,o. ,s1 ,v5 ,zH -"- -,2 -9Q -LJQ-X5 -^P
 -bF -f. -sU .%@ .3BQ.>G .EV .K< .PE .W. .\Z .a^ .kC .qU /$&Q/81
 /=' /B. /GS /OF /]; /k!Q/u% /z6 /~L 0#( 0(" 08TQ0B\ 0L" 0U_ 0^F
 0fW 0sX 0~)A1,X 1A: 1P@ 1\R 1i2 1sN 1}- 2,G 24; 2A4 2R?Q2^H 2g@
 2j( 2lS 2oU 2r< 3&A 35^ 3DK 3LW 3][Q3n2 3y* 4%8 4.G 49" 4D# 4RR
 4bA 4s4 5&.Q5+` 52X 58G 5=Y 5ES 5U6 5bE 5p< 6(.Q62R 6:$ 6I. 6U/
 6]= 6e: 6p# 6w# 7 L 7+OA7=S 7KF 7[M 7hG 7{W 8)/ 87U 8?K 8M\ 8]N
 8lRQ8|^ 9(& 92; 9<E 9GS 9TI 9gR 9w/A:&I :6< :<^ :J* :WK :_A :kK
 :w' :|[ ;''Q;84 ;=Z ;H( ;PX ;W! ;\B ;eN ;kN ;|E <.,Q<:^ <>_ <E%
 <I( <MM <\1 <g- <w` ="EQ=0V =74 =>6 =E/ =S% =dO =nG =u=Q>'+ >18
 >=/ >G, >PU >\. >l=Q>{\ ?#J ?*7 ?/# ?B6 ?NR ?Y2 ?hRQ?yA ?}! @!>
 @$Z @0S @?J @I@ @TY @a,Q@o. @t4 @{@ A#1 A6C AC! AL4 AW?QAd) AoM
 A{G B(" B7" BEX BMQ B]- Bp* C&' C51 CFS CQN C``QCl\ CrK Cx< C~!
 D1" D:*QDHZ DM_ DUE D[C D`O De[ Dm8 Dx. E"S E*] E=H EK0 EX\QE_H
 Ej7 EmO Eq* EsZ E{S F-I F>- FG6QF_9 FdF Fg\ Fk4 FnL Fq? FtX G X
 G), G@5 GQYQG_/ Gf% GkV Gq3 H$_ H:V HK0 HVSQH`" Hc5 Hf" Hi- Hl8
AHnU I&, I-K I4% I@? IL8 IX] Ib) Ii` Iw^ J0W JA5 JU5 J]=QJ`^ JhN
 JrS J{N K&' K/O K>Z KKA KY[ KhGQKvR K}V L'5 L/E L8E L@C LFP LSU
 L`& Lh=QLsR M + M+0 M5[ M>A MEW MQ-AM_" MnQ MyO N'' N-O N5G NBU
 NQY N^UQNhI NqF NzM O&' O0* O9) OFQ OWD ObD Ol] Ox3 P#P P,^ P7'
 PEP POL P`U PnU Pz_ Q'1 Q4KQQ@& QDJ QHU QM. QQB QUS Q]J QnM Q~.
 R4' R<7QRJ\ RNA RRW RUN RX8 Rl% S$S S07 SD%QSRR SY5 Sa_ Sh9 SnR
 S~` T/! T=B TJ3 T[SQTgQ Tk* To+ Tr] U"E U5J U=? UOK Ud3QUp4 Us7
 UyP U}9 V!A V5T VFT VW. V`P Vm+ Vx. W)Z W4; W<X WKQ WNI        
                                                                
                                                                
                                                                
{@-\@T`{@-\ ~@P\ `{@-\ ~@'^C O N G R A T U L A T I O N S !~@(\ `
{@-\ ~@P\ `{@-\@T`{{{@&^You've successfully completed ADA-TUTR, 
the Interactive Ada Tutor.`{{{@1Your comments and suggestions ar
e encouraged.{@>Please send them to:{{@+Software Innovations Tec
hnology, Attention: John J. Herro{@01083 Mandarin Drive NE, Palm
 Bay, FL 32905-4706{{{@@Have a good day!{{{[]{{@:Thank you for u
sing^ADA-TUTR`.{{{@2Please send your comments and suggestions to
{{@+Software Innovations Technology, Attention: John J. Herro{@0
1083 Mandarin Drive NE, Palm Bay, FL 32905-4706{{{@0I hope to se
e you again soon.  Have a good day!{{{{[]{{{@7The current screen
 number is$.{{@2You're about# percent through the course.{{{{{@7
Do you want to exit^ADA-TUTR~now?{}Please press Y for yes or N f
or no.[Y102N108B108 108#105M106]~@#\@f`{@$\ ~@b\ `{@$\ ~@7W E L 
C O M E@#T O@8\ `{@$\ ~@b\ `{@$\ ~@8^A D A - T U T R~@9\ `{@$\ ~
@b\ `{@$\ ~@(T H E@#I N T E R A C T I V E@#A D A@#T U T O R@)\ `
{@$\ ~@b\ `{@$\@7by John J. Herro, Ph.D.@8`{{@$Software Innovati
ons Technology@1Serial #  14320{@(1083 Mandarin Drive NE@7Versio
n  3.00{@'Palm Bay, FL  32905-4706@722-AUG-1994{@,(407) 951-0233
@2Copyright 1988-94 John J. Herro{{@$Shareware: Try^ADA-TUTR~fre
e.  To use it after the free trial, individ-{@$uals must registe
r and organizations must buy a license.  Both are very{@$inexpen
sive, and give many benefits.  See page 2 of PRINT.ME for infor-
{@$mation.  Whether or not you use^ADA-TUTR~and register or buy 
a license,{@$please copy the complete program and give unmodifie
d copies to others!{{@9Have you used^ADA-TUTR~before?{}@(Please 
press Y for yes or N for no.  You need not hit ENTER.[Y107N122]{
{@3What screen number would you like to see?{{@'(If you don't kn
ow, type 106 and I'll take you to the main menu.){{{Please type 
the number and press ENTER:{[#]@CMAIN MENU{{{%A~ Restart the Pro
gram.@1^I~ Subprograms and Packages{{%B~ Introduction@9^J~ Acces
s Types, User Defined Types,{@Oand Derived Types{%C~ The Format 
of an Ada Program{@H^K~ Exceptions, Text_IO, and{%D~ Generic Ins
tantiation and@3Assignment 5{@&Assignment 1{@H^L~ Generics, Task
ing, and Assignment 6{%E~ Simple Declarations and Simple{@&Attri
butes@8^M~ More Records and Types{{%F~ Operators, Control Constr
ucts, and@#^N~ Advanced Topics{@&Assignment 2{{%G~ Records, Arra
ys, and Assignment 3{{%H~ Recursion and Assignment 4@+^X~ Exit t
he Program.{}Please press a letter.[A104B109C110D111E112F113G114
H115I116J117K118L119M120N121]{{@@^WELCOME BACK!`{{{{@>Would you 
like to:{{{@1^1~ Resume where we left off?{{@1^2~ Go back to the
 last question?{{@1^3~ Go back to the last Outside Assignment?{{
@1^4~ Go to the main menu?{{@1^5~ Go to a screen number of your 
choice?{}Please press 1, 2, 3, 4, or 5.[11002099309841065105 100
B100#105M106]{{@>Would you like to:{{{@1^1~ Go back to where we 
were?{{@1^2~ Go back to the last question?{{@1^3~ Go back to the
 last Outside Assignment?{{@1^4~ Go to the main menu?{{@1^5~ Go 
to a screen number of your choice?{}Please press 1, 2, 3, 4, or 
5.[11002099309841065105 100B100#105M106]@AINTRODUCTION{@EMENU{{{
^A~ Welcome@>^F~ A Very Brief History of Ada{{^B~ Printed Course
 Notes@1^G~ What is Ada 9X?{{^C~ Do I Need a Textbook for this@(
^H~ What's a "Validated" Ada Compiler?{@&Course?{@I^M~ Go Back t
o the Main Menu.{^D~ Do I Need an Ada Compiler for{@&this Course
?{{^E~ What is Ada?@9^X~ Exit the Program.{}Please press a lette
r.[A122B123C125D126E128F129G130H136M106]@9THE FORMAT OF AN ADA P
ROGRAM{@EMENU{{{@%^A~ Our First Ada Program@.^F~ Numbers{{@%^B~ 
Local Declarations@1^G~ Making the Dot Notation{@SAutomatic{@%^C
~ Capitalization and Spacing{{@%^D~ Comments@;^M~ Go Back to the
 Main Menu.{{@%^E~ Identifiers@8^X~ Exit the Program.{}Please pr
ess a letter.[A143B145C156D158E159F167G168M106]@4GENERIC INSTANT
IATION AND ASSIGNMENT 1{@EMENU{{{@1^A~ Displaying Integers{{@1^B
~ Generic Instantiation{{@1^C~ Outside Assignment 1 -{@8Preparin
g to Run Ada on Your Computer{{@1^D~ The Ada Library{{{@1^M~ Go 
Back to the Main Menu.{{@1^X~ Exit the Program.{}Please press a 
letter.[A178B184C186D189M106]@3SIMPLE DECLARATIONS AND SIMPLE AT
TRIBUTES{@EMENU{{{@8^A~ Variables and Constants{{@8^B~ Enumerati
on Types{{@8^C~ Subtypes{{@8^D~ Simple Attributes{{{@8^M~ Go Bac
k to the Main Menu.{{@8^X~ Exit the Program.{}Please press a let
ter.[A196B202C211D213M106]@0OPERATORS, CONTROL CONSTRUCTS, AND A
SSIGNMENT 2{@EMENU{{{@$^A~ Operators@6^H~ Labels and GOTOs{{@$^B
~ Range Tests@4^I~ The CASE Construct{{@$^C~ The Short Circuit F
orms@(^J~ Brief Overview of Functions{{@$^D~ The IF Block@3^K~ O
utside Assignment 2 -{@NExercise in Enumeration Types{@$^E~ WHIL
E Loops{{@$^F~ FOR Loops@6^M~ Go Back to the Main Menu{{@$^G~ Th
e EXIT Statement@-^X~ Exit the Program.{}Please press a letter.[
A229B232C237D245E254F256G262H264I269J275K278M106]@7RECORDS, ARRA
YS, AND ASSIGNMENT 3{@EMENU{{{@8^A~ Records{{@8^B~ Arrays{{@8^C~
 Multidimensional Arrays{{@8^D~ Strings{{@8^E~ Array Operators{{
@8^F~ Outside Assignment 3 -{@?Exercise in Records{{{@8^M~ Go Ba
ck to the Main Menu.{{@8^X~ Exit the Program.{}Please press a le
tter.[A286B294C307D314E327F329M106]@:RECURSION AND ASSIGNMENT 4{
@EMENU{{{@8^A~ Recursion{{@8^B~ The Tower of Hanoi Problem{{@8^C
~ Outside Assignment 4 -{@?Exercise in Recursion{{{@8^M~ Go Back
 to the Main Menu.{{@8^X~ Exit the Program.{}Please press a lett
er.[A336B343C348M106]@;SUBPROGRAMS AND PACKAGES{@EMENU{{{@3^A~ P
rocedures and Functions{{@3^B~ Default Parameters{{@3^C~ Package
s{{@3^D~ Functions with Infix Notation{{@3^E~ Information Hiding
: Private Types{{@3^F~ Type Text and Limited Private Types{{@3^G
~ Hierarchical Libraries{{{@3^M~ Go Back to the Main Menu.{{@3^X
~ Exit the Program.{}Please press a letter.[A353B365C372D380E389
F404G420M106]@.ACCESS TYPES, USER DEFINED TYPES, AND DERIVED TYP
ES{@EMENU{{{@4^A~ Access Types{{@4^B~ User Defined Types and Por
tability{{@4^C~ Derived Types{{{@4^M~ Go Back to the Main Menu.{
{@4^X~ Exit the Program.{}Please press a letter.[A423B446C448M10
6]@5EXCEPTIONS, TEXT_IO, AND ASSIGNMENT 5{@EMENU{{{@5^A~ Excepti
ons{{@5^B~ More About Text_IO{{@5^C~ Outside Assignment 5 -{@<Wr
iting a Simple Line Editor{{{@5^M~ Go Back to the Main Menu.{{@5
^X~ Exit the Program.{}Please press a letter.[A455B473C483M106]@
6GENERICS, TASKING, AND ASSIGNMENT 6{@EMENU{{{@:^A~ Generics{{@:
^B~ Tasking{{@:^C~ Outside Assignment 6 -{@@Exercise in Tasking{
{{@:^M~ Go Back to the Main Menu.{{@:^X~ Exit the Program.{}Plea
se press a letter.[A491B501C524M106]@<MORE RECORDS AND TYPES{@EM
ENU{{{@0^A~ Record Discriminants and Record Variants{{@0^B~ Tagg
ed Records and Dynamic Dispatching{{@0^C~ Abstract Types and Abs
tract Subprograms{{@0^D~ Fixed Point, Modular, and Universal Typ
es{{{@0^M~ Go Back to the Main Menu.{{@0^X~ Exit the Program.{}P
lease press a letter.[A529B536C546D548M106]@@ADVANCED TOPICS{@EM
ENU{{{%A~ Renaming@=^H~ Unchecked Conversion and Unchecked{@ODea
llocation{%B~ Packages Standard and ASCII{@H^I~ Pragmas{%C~ An A
lternative to Infix Notation{@H^J~ Loose Ends and Pitfalls{%D~ M
ore Attributes{{%E~ Sequential_IO and Direct_IO{@H^M~ Go Back to
 the Main Menu.{%F~ Subprogram Parameters with Generics{{%G~ Rep
resentation Clauses and System@$^X~ Exit the Program.{}Please pr
ess a letter.[A560B562C564D569E572F578G580H587I590J597M106]@)\@\
`{@)\ ~@X\ `{@)\ ~@#^WELCOME TO ADA-TUTR, THE INTERACTIVE ADA TU
TOR!~@$\ `{@)\ ~@X\ `{@)\@\`{{%ADA-TUTR~will make you an excelle
nt Ada programmer in minimum time.  You should{be familiar with 
at least one other high-level language (Basic, Pascal, etc.){{Yo
u can study as long as you like. ^WHENEVER YOU WANT TO EXIT THE 
PROGRAM, JUST{TYPE X.~ (I'll ask you to confirm that you really 
want to exit, in case you{typed X by mistake.)  I'll remember ex
actly where we left off, so when you're{ready to learn again, yo
u'll be able to go back there or to any other lesson.{Remember, 
just type X at any time to exit^ADA-TUTR`.{{%ADA-TUTR~works with
 monochrome as well as color computers.  Please adjust the{brigh
tness and contrast of your screen now, so that the^highlighted~w
ords are{noticeably brighter than the others, but all are easy t
o read. ^YOU CAN SET THE{COLORS AT ANY TIME BY TYPING S`, and I'
ll remember your color choices.{{Please send your comments and s
uggestions to Software Innovations Technology,{Attention: John J
. Herro, 1083 Mandarin Drive NE, Palm Bay, FL 32905-4706.{}Pleas
e type a space to go on.  (You need not hit ENTER.)[ 123B104]@>P
RINTED COURSE NOTES{{To get the most from^ADA-TUTR`, you should 
have a printed copy of the PRINT.ME{file.  If you haven't starte
d printing the course notes yet, read this screen{and then type 
X to exit the program temporarily.  Remember, you can leave{%ADA
-TUTR~at any time, and later pick up exactly where you left off.
{{Then, when the system prompt (usually^C>`) appears, type:{{@@^
PRINT PRINT.ME`{{You can then restart^ADA-TUTR~while your course
 notes are being printed.{Please read them through page 2 now.  
If you got this far, you don't need page{6.  Please read page 42
 if you want to install^ADA-TUTR~on a non-PC computer,{such as a
 workstation or a mainframe.{}Please type X to exit, a space to 
go on, or B to go back.[ 124B122]In addition to the printed cour
se notes, we recommend (but don't require) that{you have access 
to the Military Standard Ada Programming Language manual,{ANSI/M
IL-STD-1815A, 1983.  This volume is often called the^Language Re
ference{Manual`, or^LRM`.  You'll probably find it in a public l
ibrary, or perhaps in{your company library.  If you can borrow a
n LRM, it's legal to copy the entire{book.  You can also buy an 
LRM very inexpensively.{{As this is written (August, 1994), a dr
aft copy of the Ada 9X LRM is also{available.{}Please type X to 
exit, a space to go on, or B to go back.[ 125B123]@5DO I NEED A 
TEXTBOOK FOR THIS COURSE?{{Although the LRM is a good reference,
 it's difficult reading and not a good{learning tool.  With^ADA-
TUTR~you probably won't need a textbook, but we made a{special a
rrangement with John Wiley and Sons in case you would like to ha
ve a{textbook to go along with this course.  If you copy page 37
 of PRINT.ME, or{print the file COUPON.TXT, you can purchase the
 excellent textbook RENDEZVOUS{WITH ADA by David Naiditch for a 
very good price.  Be sure to send your order{to the address on t
he coupon, not to us.{{If you're using a PC and you ever want to
 print the screen that's currently{being displayed, just hold a 
Shift key while pressing the^PrtSc~key.{{A few of you asked us f
or a way to print^all~the screens in this course, so we{added th
e program^BOOK~to^ADA-TUTR`.  While this is by no means required
, or{even recommended, if you want a printout of all the screens
, please see page 38{of your printed course notes for instructio
ns on running^BOOK`.  Be prepared to{print about 500 pages!{}b[ 
126B124]@3DO I NEED AN ADA COMPILER FOR THIS COURSE?{{An Ada com
piler is helpful, but not required.  As we go along, there will 
be{six Outside Assignments; most of them ask you to write and co
mpile a short Ada{program.  If you don't have access to an Ada c
ompiler, just skip the Outside{Assignments.{{A brief list of Ada
 compilers available for the PC and compatibles is in your{print
ed course notes, on page 39.  We tried to include all the popula
r Ada{compilers, but we might have missed some.  If you know of 
an Ada compiler that{you think should be on that list, please co
ntact us.{{That's enough discussion of what's recommended for^AD
A-TUTR`.  Let's begin!{}b[ 127B125]@;^ADA-TUTR COURSE OUTLINE`{{
{%>  INTRODUCTION~@<Recursion and Assignment 4{{@#The Format of 
an Ada Program@-Subprograms and Packages{{@#Generic Instantiatio
n and@0Access Types, User Defined Types,{@&Assignment 1@=and Der
ived Types{{@#Simple Declarations and Simple@+Exceptions, Text_I
O, and{@&Attributes@?Assignment 5{{@#Operators, Control Construc
ts, and@'Generics, Tasking, and Assignment 6{@&Assignment 2{@LMo
re Records and Types{@#Records, Arrays, and Assignment 3{@LAdvan
ced Topics{}b[ 128B126]@BWHAT IS ADA?{{Ada is a modern language 
designed for programming large scale and real time{systems.  Ada
 is also an excellent general purpose language.  It has many new
{features which help prevent errors and detect errors earlier.{{
However, Ada is much more than a new language.  It's also a new 
programming{%philosophy`.  Beware of learning just "Ada syntax";
 you'll wind up writing{Basic-like (or Pascal-like, etc.) progra
ms that happen to be coded in Ada.  If{you do that, you'll lose 
the many benefits of Ada.  Unfortunately, you won't{see why Ada 
is a new programming philosophy until later in this course.  (By
{the time we get to packages and information hiding, you'll be a
n enthusiastic{convert.)  In the meantime, please take our word 
for it:  Ada is a whole new{programming philosophy, not just ano
ther language.{{Because of its many features, Ada is relatively 
complicated.  There's about{seven times as much to learn as Pasc
al.  However, the effort pays great{dividends.  Once you learn t
he language, Ada programs are easier to write,{easier to read, a
nd much easier to modify a month or a year later.{}b[ 129B127]@:
A VERY BRIEF HISTORY OF ADA{{Ada was named for Augusta Ada Byron
, countess of Lovelace and daughter of the{poet Lord Byron.  She
 worked with Charles Babbage on his Analytical Engine, and{has b
een called the world's first programmer.  The Language Reference
 Manual{(LRM) was given the number ANSI/MIL-STD-1815A because Au
gusta Ada Byron was{born in 1815.{{Ada was invented because the 
U.S. Department of Defense (DoD) realized that{none of the exist
ing languages was very suitable for real-time control of{large, 
embedded systems.  An embedded system is a computer system insid
e a{product other than a computer, such as an intelligent oven o
r a guided missile.{Programs for embedded systems are usually wr
itten with a^cross compiler`, a{compiler that runs on one machin
e and produces code for another.  Cross{compilers are often call
ed compilers for short.{{In 1977 the DoD issued a Request for Pr
oposal to develop a new language; the{leading four contenders we
re designated Blue, Red, Yellow, and Green.{Eventually Green was
 selected to be Ada; it was designed by the company{Honeywell Bu
ll under the direction of Jean Ichbiah of France.{}b[ 130B128]@@
WHAT IS ADA 9X?{{The present version of Ada was standardized in 
1983.  For this reason, the{present version of Ada is often call
ed Ada 83.{{As this is written (August, 1994), there's an effort
 to revise the Ada{language.  Revision should be completed somet
ime in the 1990's.  For this{reason, the new version of Ada is c
alled Ada 9X.{{ADA-TUTR will point out the differences between A
da 83 and Ada 9X as we go{along.  All of the programs and exampl
es in this course are designed to compile{and run with either an
 Ada 83 or an Ada 9X system, except for the examples{specificall
y labeled as Ada 9X only.{}b[ 131B129]In the author's opinion, w
hich^one~of the following statements is true?{{{1.  Ada is simpl
er than Pascal.{{2.  Although Ada was designed for embedded syst
ems, it makes a good general{@$purpose language.{{3.  Basic and 
Pascal programs can easily be translated into good Ada programs.
{{4.  In languages that are simpler than Ada, errors are usually
 detected earlier{@$than in Ada.{}Please press 1, 2, 3, or 4, or
 B to go back.[2132113331344135B130]%You're right!~ Ada makes us
e of the latest advances in software engineering, so{it makes an
 excellent general purpose language.{}q[ 136B131Q131]No, Ada is 
more complicated than Pascal.  So far as the^philosophy~is{conce
rned, Ada is an extension (or "superset") of Pascal.  However, i
n^syntax`{Ada isn't a superset of Pascal; the Ada syntax is diff
erent.{{Although Ada is more complicated than Pascal (and many o
ther languages), it has{many advantages.  These advantages pay d
ividends in reduced effort to develop{and maintain programs.{}q[
 136B131Q131]No, it might be easy to translate Basic and Pascal 
programs into Ada, but the{resulting programs wouldn't be very g
ood, because they'd fail to take advantage{of the features of Ad
a.{}q[ 136B131Q131]No, Ada has a reputation for detecting errors
 earlier than the simpler{languages.  Ada detects errors at comp
ile time that other languages detect only{at run time or not at 
all.  Examples are calling a subprogram with the wrong{number of
 parameters, and unintentionally mixing different types in an{ex
pression.  We'll learn more about these things later.{}q[ 136B13
1Q131]@7WHAT'S A "VALIDATED" ADA COMPILER?{{Although the name "A
da" is no longer a trademark of the Department of Defense,{the A
da Joint Program Office (AJPO) still validates Ada compilers (an
d cross{compilers).  If a compiler conforms exactly to the stand
ard, and isn't a subset{or superset of Ada, it can be validated 
after passing an extensive suite of{tests (called the Ada Compil
er Validation Capability, or ACVC).{{The ACVC is updated periodi
cally.  Only currently validated compilers may{display an emblem
 that says, "Validated Ada ... This product conforms to{ANSI/MIL
-STD-1815A as determined by the AJPO under its current testing{p
rocedures."{{An unnumbered page in the beginning of the LRM says
 that "Only compilers which{have been validated ... shall be use
d in DoD systems."  Also, a 1987 DoD{Directive (3405.2) says tha
t only validated Ada compilers may be used on{mission critical s
ystems.{{As this is written (August, 1994), only Ada 83 compiler
s can be validated,{because the specifications for Ada 9X have n
ot yet been finalized.{{True or False?  Subsets and supersets of
 standard Ada may be called "Ada."{}Please press T for true or F
 for false, or B to go back.[T137F138B131]%You're right!~ Compil
ers not conforming exactly to the Ada standard may be{called "Ad
a."  This was true even when "Ada" was a DoD trademark.  A prefa
ce to{the LRM says that compilers not conforming to the standard
 may be called "Ada"{if there's a clear statement that they don'
t conform.{{Of course, only validated Ada compilers are to be us
ed on DoD systems, and{validated compilers can't be subsets or s
upersets of standard Ada.{}q[ 139B136Q136]True.  It's a common m
isconception that subsets and supersets may not be called{"Ada."
  However, this was allowed even when "Ada" was a DoD trademark.
  A{preface to the LRM says that compilers not conforming to the
 standard may be{called "Ada" if there's a clear statement that 
they don't conform.{{It's true that only validated Ada compilers
 are to be used in DoD systems.{Validated compilers can't be sub
sets or supersets of standard Ada.{}q[ 139B136Q136]True or False
?  The Validation tests are performed to provide reasonable{assu
rance that a compiler is bug-free.{}Please press T for true or F
 for false, or B to go back.[F140T141B136]%You're right!~ The Va
lidation tests are performed to make sure that a compiler{confor
ms to the Ada standard, and isn't a subset or superset.  A compi
ler isn't{believed to be bug-free just because it earned a Valid
ation Certificate.{}q[ 142B139Q139]False.  That's a common misco
nception, but validation only determines that a{compiler conform
s exactly to the Ada standard, and isn't a subset or superset.{A
 compiler isn't believed to be bug-free just because it earned a
 Validation{Certificate.{}q[ 142B139Q139]@;^ADA-TUTR COURSE OUTL
INE`{{{@#Introduction@=Recursion and Assignment 4{{%>  THE FORMA
T OF AN ADA PROGRAM~@,Subprograms and Packages{{@#Generic Instan
tiation and@0Access Types, User Defined Types,{@&Assignment 1@=a
nd Derived Types{{@#Simple Declarations and Simple@+Exceptions, 
Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Control Co
nstructs, and@'Generics, Tasking, and Assignment 6{@&Assignment 
2{@LMore Records and Types{@#Records, Arrays, and Assignment 3{@
LAdvanced Topics{}b[ 143B139]@=OUR FIRST ADA PROGRAM{{Now let's 
look at a simple Ada program.  This program merely displays "Hel
lo!"{on the screen.{{@8^with Text_IO;`{@8^procedure Hello is`{@8
^begin`{@;^Text_IO.Put_Line("Hello!");`{@8^end Hello;`{{Text_IO 
is a "package" that comes with the Ada language.  We'll learn mo
re{about packages later.  Text_IO contains, among other things, 
a procedure{Put_Line that takes one parameter of type String and
 displays it.  In this{case, the String parameter is^"Hello!"`. 
 Ada doesn't have any special I/O{statements.  I/O is done by ca
lling procedures that Ada provides for us.{{Even though the pack
age Text_IO comes with Ada, our procedure Hello can't "see"{it u
nless it says^with Text_IO;`.  With that statement, our procedur
e can call{any procedure or function inside Text_IO.  We call a 
procedure by giving the{package name (Text_IO), followed by a do
t and the name of the procedure within{the package.  Like Pascal
 and unlike Fortran, the word CALL isn't used in Ada.{}b[ 144B14
2]@8^with Text_IO;`{@8^procedure Hello is`{@8^begin`{@;^Text_IO.
Put_Line("Hello!");`{@8^end Hello;`{{The statement^with Text_IO;
~is called a^context clause~because it specifies the{"context" i
n which procedure Hello is compiled.{{In Ada a^procedure~may be 
called either from another procedure or as the main{program.  In
 this example, Hello is the main program; it calls Put_Line.{{Ev
ery Ada statement, including the last, ends with a semicolon.  (
Technically,{the lines above without semicolons aren't statement
s.)  In Pascal, semicolons{come^between~statements, but in Ada, 
a semicolon^ends~a statement.{{In Ada, the^end~statement may opt
ionally give the name of the procedure or{function.  If a name i
s given, the compiler will check that it agrees with the{name at
 the beginning.  If it doesn't agree, the compiler will issue a 
message.{{The statements between^begin~and^end~(this program has
 only one) are called{executable statements; when they're obeyed
 they're said to be^executed`.{}b[ 145B143]@?LOCAL DECLARATIONS{
{@9with Text_IO;{@9procedure Hello is{@;^I@$: Integer;`{@;^X, Y 
: Float;`{@9begin{@<Text_IO.Put_Line("Hello!");{@9end Hello;{{Lo
cal declarations may appear between^procedure ... is~and^begin`.
  This simple{program doesn't need any, but we've added two decl
arative statements by way of{example.  Executable statements are
 said to be^executed~when they're obeyed,{but when a declarative
 statement is obeyed, it's said to be^elaborated`.{Declarative s
tatements are elaborated at run time, not compile time.{{In this
 example, when the procedure is called (either from another proc
edure or{as the main program), the declarations are elaborated a
nd variables I, X, and Y{are brought into existence.  Then the e
xecutable statement(s) are obeyed.  When{the^end~statement is re
ached and the procedure returns, I, X, and Y go out of{existence
.  These three variables are local to procedure Hello and can't 
be{referenced outside this procedure.{}b[ 146B144]@9with Text_IO
;{@9procedure Hello is{@;^I@$: Integer;`{@;^X, Y : Float;`{@9beg
in{@<Text_IO.Put_Line("Hello!");{@9end Hello;{{If Hello is calle
d again, I, X, and Y will again be brought into existence, but{t
heir previous values won't necessarily be remembered between cal
ls.  (Of{course, in this simple example, I, X, and Y aren't assi
gned values anyway.){{Like Pascal and unlike Basic and Fortran, 
every Ada variable must be declared.{(The index of an Ada^for~lo
op declares itself, but we'll discuss that later.){Unlike Pascal
, Ada programs don't need to say "var".  Ada knows that the{obje
cts declared above are variables.  Constant declarations contain
 the{reserved word^constant~and may or may not specify a type, l
ike this:{{@5^Pi@%: constant := 3.141592654;`{@5^Two_Pi : consta
nt Float := 2.0 * Pi;`{{Constant declarations that don't specify
 a type are called^named numbers`.{}b[ 147B145]@5^Pi@%: constant
 := 3.141592654;`{@5^Two_Pi : constant Float := 2.0 * Pi;`{{Decl
arations are elaborated in order, top to bottom.  The two declar
ations{above must appear in the order shown, because the second 
refers to the first.{{The difference between a named number, lik
e Pi, and a constant declaration that{specifies a type, like Two
_Pi, is subtle.  We'll explain the difference in the{section on 
More Records and Types under "Universal Types."  For now, it doe
sn't{make any difference whether or not a constant declaration s
pecifies a type.{The compiler can tell, from looking at the cons
tant, whether the type is{Integer or Float.{{Unlike Pascal, Ada 
allows constant declarations to be intermixed with variable{decl
arations, so long as no declaration refers to a declaration belo
w it.{}b[ 148B146]@/1@)with Text_IO;{@9procedure Hello is{@/2@,I
@$: Integer;{@<X, Y : Float;{@9begin{@/3@,Text_IO.Put_Line("Hell
o!");{@9end Hello;{{OK, in the program above, where are the^exec
utable statement(s)`?{}Please press 1, 2, or 3, or B to go back.
[314911502151B147]@/1@)with Text_IO;{@9procedure Hello is{@/2@,I
@$: Integer;{@<X, Y : Float;{@9begin{@.^3@,Text_IO.Put_Line("Hel
lo!");`{@9end Hello;{{%You're right!~ Executable statements are 
placed between^begin~and^end`.{}q[ 152B148Q148]@/1@)with Text_IO
;{@9procedure Hello is{@/2@,I@$: Integer;{@<X, Y : Float;{@9begi
n{@/3@,Text_IO.Put_Line("Hello!");{@9end Hello;{{No,^with Text_I
O;~is a^context clause`.  Executable statements are placed{betwe
en^begin~and^end`.{}q[ 152B148Q148]@/1@)with Text_IO;{@9procedur
e Hello is{@/2@,I@$: Integer;{@<X, Y : Float;{@9begin{@/3@,Text_
IO.Put_Line("Hello!");{@9end Hello;{{No,^declarative~statements 
are placed between^procedure ... is~and^begin`.{%Executable~stat
ements are placed between^begin~and^end`.{}q[ 152B148Q148]@/1@)w
ith Text_IO;{@9procedure Hello is{@/2@,I@$: Integer;{@<X, Y : Fl
oat;{@9begin{@/3@,Text_IO.Put_Line("Hello!");{@9end Hello;{{Now,
 where are the^local declaration(s)`?{}Please press 1, 2, or 3, 
or B to go back.[215311543155B148]@/1@)with Text_IO;{@9procedure
 Hello is{@.^2@,I@$: Integer;`{@;^X, Y : Float;`{@9begin{@/3@,Te
xt_IO.Put_Line("Hello!");{@9end Hello;{{%You're right!~ Local de
clarations are placed between^procedure ... is~and{%begin`.{}q[ 
156B152Q152]@/1@)with Text_IO;{@9procedure Hello is{@/2@,I@$: In
teger;{@<X, Y : Float;{@9begin{@/3@,Text_IO.Put_Line("Hello!");{
@9end Hello;{{No,^with Text_IO;~is a^context clause`.  Local dec
larations are placed between{%procedure ... is~and^begin`.{}q[ 1
56B152Q152]@/1@)with Text_IO;{@9procedure Hello is{@/2@,I@$: Int
eger;{@<X, Y : Float;{@9begin{@/3@,Text_IO.Put_Line("Hello!");{@
9end Hello;{{No,^executable~statements are placed between^begin~
and^end`. ^Local declarations`{are placed between^procedure ... 
is~and^begin`.{}q[ 156B152Q152]@;CAPITALIZATION AND SPACING{{@9w
ith Text_IO;{@9procedure Hello is{@<I@$: Integer;{@<X, Y : Float
;{@9begin{@<Text_IO.Put_Line("Hello!");{@9end Hello;{{Except in 
quoted Strings like "Hello!", capitalization isn't important in 
Ada.{The Ada 9X LRM shows all reserved words in lower case and a
ll identifiers with{initial capitals, so that's the style we're 
using in our examples.  (The Ada 83{LRM uses all capitals for id
entifiers.  That style is also commonly used.){{In Ada, unlike F
ortran, statements may begin anywhere on the line; columns{aren'
t significant.  Most people indent the local declarations and th
e{executable statements two or three spaces, as shown above.  Sp
aces and tabs may{not appear^within~reserved words and identifie
rs, but they may freely be used{%between~elements of the program
.{}b[ 157B152]@9with Text_IO;{@9procedure Hello is{@<I@$: Intege
r;{@<X, Y : Float;{@9begin{@<Text_IO.Put_Line("Hello!");{@9end H
ello;{{Since a semicolon marks the end of a statement, we can pu
t several statements{on one line, like this:{{@:I : Integer;@#X,
 Y : Float;{{We can also continue a statement over several lines
, breaking anywhere a space{would be permitted, like this:{{@@Te
xt_IO.{@EPut_Line({@E"Hello!");{{Many people follow the capitali
zation and spacing style of the Ada 9X LRM, so{we'll do that in 
this course.{}b[ 158B156]@DCOMMENTS{{@*with Text_IO;{@*procedure
 Hello is{@,^-- This program displays "Hello!" on the screen.`{@
-I@$: Integer;^-- These declarations aren't needed; they`{@-X, Y
 : Float;  ^-- were added only to provide examples.`{@*begin{@-T
ext_IO.Put_Line("Hello!");{@*end Hello;{{Comments in Ada begin w
ith a double hyphen (double minus sign) and continue{through the
 end of the line.  No space is permitted inside the double hyphe
n.{As shown, a comment can be an entire line, or it can follow c
ode on a line.{{Ada programs generally have less need for commen
ts than programs written in{other languages.  The reason is that
, as we'll see, the identifiers may be as{long as we like (up to
 the length of a line) and can have very meaningful{names.  Also
, when we learn about named notation, we'll see that calls to{su
bprograms can be made much more readable in Ada than in other la
nguages.{These features and others tend to make Ada programs sel
f documenting.{}b[ 159B157]@BIDENTIFIERS{{@9with Text_IO;{@9proc
edure Hello is{@<I@$: Integer;{@<X, Y : Float;{@9begin{@<Text_IO
.Put_Line("Hello!");{@9end Hello;{{Here,^reserved words~are in l
ower case, and all other^identifiers~have initial{captials.  (Th
e Ada reserved words, which may not be used to identify anything
{in our programs, are listed on page 7 of your printed course no
tes, and in{section 2.9 of the LRM.)  Ada identifiers may contai
n letters, digits, and{underlines, but must start with a letter.
  They may not contain spaces or other{characters.  Identifiers 
may be as long as you like, up to the length of a{line.  (The ma
ximum line length depends on the particular implementation of{Ad
a.)  All characters are significant, so This_Is_a_Long_Identifie
r_1 and{This_Is_a_Long_Identifier_2 are distinct.  Since underli
nes are significant,{A_B is different from AB.  Every underline 
must be followed by a letter or a{digit.  Thus, you can't have t
wo underlines together, and an identifier can't{end in an underl
ine.{}b[ 160B158]@11.  1553B{{@12.  Begin{{@13.  THIS_IS_A_VERY_
LONG_NAME_FOR_AN_IDENTIFIER{{@14.  SYS$QIO{{@15.  Number_Of__Tar
gets{{@16.  Max Speed{{{Only^one~of the above is a legal Ada ide
ntifier.  Which is it?{}Please press 1, 2, 3, 4, 5, or 6, or B t
o go back.[316111622163416451656166B159]@11.  1553B{{@12.  Begin
{{@0^3.  THIS_IS_A_VERY_LONG_NAME_FOR_AN_IDENTIFIER`{{@14.  SYS$
QIO{{@15.  Number_Of__Targets{{@16.  Max Speed{{{%You're right!~
 An Ada identifier may be as long as we like (up to the length o
f{a line), and upper/lower case isn't important in Ada.{{Number 
1 begins with a digit, 2 is a reserved word, 4 has a dollar sign
, 5 has{two underlines together, and 6 has a space.{}q[ 167B160Q
160]@11.  1553B{{@12.  Begin{{@13.  THIS_IS_A_VERY_LONG_NAME_FOR
_AN_IDENTIFIER{{@14.  SYS$QIO{{@15.  Number_Of__Targets{{@16.  M
ax Speed{{{No, number 1 is illegal because Ada identifiers must 
begin with a letter.{}q[ 167B160Q160]@11.  1553B{{@12.  Begin{{@
13.  THIS_IS_A_VERY_LONG_NAME_FOR_AN_IDENTIFIER{{@14.  SYS$QIO{{
@15.  Number_Of__Targets{{@16.  Max Speed{{{No, number 2 is ille
gal because^begin~is a reserved word.{}q[ 167B160Q160]@11.  1553
B{{@12.  Begin{{@13.  THIS_IS_A_VERY_LONG_NAME_FOR_AN_IDENTIFIER
{{@14.  SYS$QIO{{@15.  Number_Of__Targets{{@16.  Max Speed{{{No,
 number 4 is illegal because of the dollar sign.  Ada identifier
s may{contain only letters, digits, and underlines.{}q[ 167B160Q
160]@11.  1553B{{@12.  Begin{{@13.  THIS_IS_A_VERY_LONG_NAME_FOR
_AN_IDENTIFIER{{@14.  SYS$QIO{{@15.  Number_Of__Targets{{@16.  M
ax Speed{{{No, number 5 is illegal because of the two underlines
 together.  Every{underline must be followed by a letter or a di
git.{}q[ 167B160Q160]@11.  1553B{{@12.  Begin{{@13.  THIS_IS_A_V
ERY_LONG_NAME_FOR_AN_IDENTIFIER{{@14.  SYS$QIO{{@15.  Number_Of_
_Targets{{@16.  Max Speed{{{No, number 6 is illegal because of t
he space.  Ada identifiers may contain only{letters, digits, and
 underlines.{}q[ 167B160Q160]@DNUMBERS{{In numbers, unlike ident
ifiers, underlines are^not~significant.  Thus^12345~and{%12_345~
are equivalent.  Spaces aren't permitted within numbers.  When a
n{underline appears in a number, it must be surrounded by digits
.  Thus, all of{these are illegal:@%123_@%123_.0@%_123@%12__3{{F
loating point numbers must have at least one digit before and on
e digit after{the decimal point.  Unlike Basic and Fortran, Ada 
forces us to write^1.0`{instead of^1.`, and^0.5~instead of^.5`. 
 Scientific notation may be used:^1.3E-3`{is the same as^0.0013`
.  Non-negative exponents may be used even in integers:{%12E3~me
ans^12_000`.{{Numbers may be specified in any base from 2 to 16,
 as shown below.  These three{numbers are all equal:{{@*^16#7C03
#@)2#0111_1100_0000_0011#@)8#076003#`{{A number with a base may 
have an exponent.  The number after the^E~is still{written in de
cimal, and gives the power by which the base is raised.  Thus{%2
#110#E5~is 6 times 2**5, or 192.{}b[ 168B160]@7MAKING THE DOT NO
TATION AUTOMATIC{{These two programs are equivalent:{{@&with Tex
t_IO;@;with Text_IO;^use Text_IO;`{@&procedure Hello is@6procedu
re Hello is{@&begin@Cbegin{@(^Text_IO.`Put_Line("Hello!");@-Put_
Line("Hello!");{@&end Hello;@>end Hello;{{We've said that the st
atement^with Text_IO;~makes the package^visible`, so that{our pr
ogram can call the procedures and functions in it.  To call a pr
ocedure,{we write the name of the package, a dot, and the name o
f the procedure.{{The statement^use Text_IO;~tells the compiler 
to supply the name of the package{and the dot for us.  That's wh
y the two programs above are equivalent.{{Remember, in Ada^with~
provides visibility;^use~asks the compiler to supply the{package
 name and the dot.{{The Ada meanings of the words^with~and^use~a
re more or less reversed from their{meanings in Pascal.  Also, i
n Ada one can't^use~records, only packages.{}b[ 169B167]@&with T
ext_IO;@;with Text_IO;^use Text_IO;`{@&procedure Hello is@6proce
dure Hello is{@&begin@Cbegin{@(^Text_IO.`Put_Line("Hello!");@-Pu
t_Line("Hello!");{@&end Hello;@>end Hello;{{A program can^with~a
nd^use~several packages.  For example, there's a package{that co
mes with Ada called Calendar.  Suppose we've also compiled two p
ackages{of our own, called My_Pkg_1 and My_Pkg_2.  Then our prog
ram might say{{@1^with Text_IO, Calendar, My_Pkg_1, My_Pkg_2;`{@
1^use  Text_IO, Calendar, My_Pkg_1, My_Pkg_2;`{{In this case, wh
en the compiler sees the call to Put_Line, it will search all{fo
ur packages that we've^use`d for a procedure Put_Line that takes
 one String{parameter (or "argument").  If it finds no procedure
 Put_Line, the compiler{will display an error message, like "Put
_Line is not declared" or "Undeclared{identifier Put_Line."{{You
 may ask, what if there are several procedures Put_Line among th
e four{packages?  Will the compiler stop searching when it finds
 the first Put_Line?{No.{}b[ 170B168]@1^with Text_IO, Calendar, 
My_Pkg_1, My_Pkg_2;`{@1^use  Text_IO, Calendar, My_Pkg_1, My_Pkg
_2;`{{If the compiler finds several Put_Line's, the name Put_Lin
e is said to be{%overloaded`.  In that case the compiler will us
e the^number~and^types~of{parameters (arguments) to try to selec
t the right Put_Line.  For example, if{Text_IO contains a Put_Li
ne that takes one String parameter, and My_Pkg_1{contains a Put_
Line that takes one Integer parameter, the compiler will write a
{call to Text_IO.Put_Line and not My_Pkg_1.Put_Line, because the
 calling{statement supplies one String parameter.{{If there's mo
re than one Put_Line that takes exactly one String parameter, th
en{the call is ambiguous and the compiler can't resolve the over
loading.  The{error message will be something like "Ambiguity de
tected during overload{resolution" or "Ambiguous expression."  I
n that case, we'd have to specify{%Text_IO.`Put_Line even though
 we said^use Text_IO;`.{{Finally, if there are procedures Put_Li
ne, but none of them has the right{number and types of parameter
s, the error message will be something like{"Inconsistency detec
ted during overloading resolution" or "Unresolvable{expression."
{}b[ 171B169]In summary, the compiler will search all the packag
es that we've^use`d for a{procedure with the correct number and 
types of parameters.  If it finds exactly{one, everything's fine
.  If it finds no procedure with the correct name, the{error mes
sage will be something like "Undeclared identifier."  If it find
s more{than one procedure with the correct number and types of p
arameters, the message{is "Ambiguity detected during overload re
solution" or "Ambiguous expression."{Finally, if it finds one or
 more procedures with the correct name, but none of{them has the
 right number and types of parameters, the message will be{somet
hing like "Inconsistency detected during overload resolution" or
{"Unresolvable expression."{{Overloading may seem like an unnece
ssary complication at this point, but you'll{see later how very 
useful it can be.  Overloading is especially useful with{the inf
ix operators when we create our own types.  All of this will be 
covered{later.{}b[ 172B170]Which^one~of the following would most
 likely be the cause of the message{"Inconsistency detected duri
ng overload resolution"?{{{@$1.  You tried to^use~a package that
 you didn't^with`.{{@$2.  You misspelled the name of a package i
n a call using dot notation.{{@$3.  You misspelled the name of a
 procedure or function in a call.{{@$4.  You called a procedure 
or function with the wrong number or types of{@(parameters.{}Ple
ase press 1, 2, 3, or 4, or B to go back.[4173117421753175B171]@
$1.  You tried to use a package that you didn't with.{{@$2.  You
 misspelled the name of a package in a call using dot notation.{
{@$3.  You misspelled the name of a procedure or function in a c
all.{{@#^4.  You called a procedure or function with the wrong n
umber or types of`{@'^parameters.`{{{%You're right!~ The message
 "Inconsistency detected during overload resolution"{usually mea
ns that you called a procedure or a function with the wrong numb
er{or types of parameters.{}q[ 176B172Q172]@$1.  You tried to^us
e~a package that you didn't^with`.{{@$2.  You misspelled the nam
e of a package in a call using dot notation.{{@$3.  You misspell
ed the name of a procedure or function in a call.{{@$4.  You cal
led a procedure or function with the wrong number or types of{@(
parameters.{{{No, for number 1 the message would be something li
ke "This package is not named{in a prior^with~clause," or "%use~
clause was not expected here."{}q[ 176B172Q172]@$1.  You tried t
o^use~a package that you didn't^with`.{{@$2.  You misspelled the
 name of a package in a call using dot notation.{{@$3.  You miss
pelled the name of a procedure or function in a call.{{@$4.  You
 called a procedure or function with the wrong number or types o
f{@(parameters.{{{No, if you misspell the name of a package, pro
cedure, or function, the most{probable error message would be "U
ndeclared identifier."{}q[ 176B172Q172]Text_IO contains both a p
rocedure^Put~and a procedure^Put_Line~(among other{things). ^Put
_Line~displays its String parameter followed by a Carriage Retur
n{and a Line Feed, while^Put~displays its String parameter witho
ut the CR-LF.{Text_IO also contains a procedure^New_Line~which p
roduces only CR-LF.  For{example, the following program will dis
play^Hi there,~leave a blank line, and{display^everybody!`:{{@:w
ith Text_IO; use Text_IO;{@:procedure Hi_There is{@:begin{@<^Put
`("Hi");{@<^Put_Line`(" there,");{@<^New_Line;`{@<^Put_Line`("ev
erybody!");{@:end Hi_There;{}b[ 177B172]@;^ADA-TUTR COURSE OUTLI
NE`{{{@#Introduction@=Recursion and Assignment 4{{@#The Format o
f an Ada Program@-Subprograms and Packages{{%>  GENERIC INSTANTI
ATION AND~@/Access Types, User Defined Types,{@%^ASSIGNMENT 1~@<
and Derived Types{{@#Simple Declarations and Simple@+Exceptions,
 Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Control C
onstructs, and@'Generics, Tasking, and Assignment 6{@&Assignment
 2{@LMore Records and Types{@#Records, Arrays, and Assignment 3{
@LAdvanced Topics{}b[ 178B176]@>DISPLAYING INTEGERS{{with Text_I
O; use Text_IO;@;with Text_IO; use Text_IO;{procedure Hello is@,
^THIS~@'^THIS~@$procedure Add is{begin@6^<= IS~@+^IS =>~ begin{@
#Put_Line(%"Hello!"`);@(^RIGHT~@%^WRONG~@'Put_Line(%2 + 2`);{end
 Hello;@Kend Add;{{Now let's write a program called Add that com
putes 2 + 2 and displays the{result.  You may think that we coul
d take the Hello program and substitute{%2 + 2~for^"Hello!"`, bu
t that won't work.  (We never said Ada is easy!)  Why{won't it w
ork?  Because Text_IO doesn't have a procedure Put_Line that tak
es an{Integer parameter.  One correct program is this:{{@(with T
ext_IO; use Text_IO;{@(procedure Add is{@*^package My_Int_IO is 
new Integer_IO(Integer); use My_Int_IO;`{@(begin{@*^Put(2 + 2);`
{@*^New_Line;`{@(end Add;{}b[ 179B177]@(with Text_IO; use Text_I
O;{@(procedure Add is{@*^package My_Int_IO is new Integer_IO(Int
eger); use My_Int_IO;`{@(begin{@+Put(2 + 2);{@+New_Line;{@(end A
dd;{{__________ Text_IO __________  The package Text_IO contains
 procedures for type{| Put_Line for type String  |  String.  Thi
s package is ready-to-use.  However,{| Put@&for type String  |  
inside Text_IO is another package, Integer_IO,{| Get_Line for ty
pe String  |  that's^not~ready-to-use.  It's called a^generic`{|
 Get@&for type String  |  package because it has an empty^box~(%
<>`) in{| New_Line@2|  place of the type.  We can make a new, re
ady-to-{| ...@7|  -use package from Integer_IO by giving the typ
e:{|@;|  package My_Int_IO is new Integer_IO(%Integer`); we{|  _
_____ Integer_IO ______ |  could have used any name in place of 
My_Int_IO.{|  | Put for type <>@&| |  Note that we've declared o
ur new package locally{|  | Get for type <>@&| |  inside the pro
cedure Add.  My_Int_IO now has the{|  | ...@2| |  same procedure
s and functions as Integer_IO, but{|  |______________________| |
  with the empty box filled in with the type{|__________________
_________|  Integer, like this:{}b[ 180B178]@@with Text_IO; use 
Text_IO;{__________ Text_IO __________@#procedure Add is{| Put_L
ine for type String  |@%^package My_Int_IO is new Integer_IO(`{|
 Put@&for type String  |@*^Integer); use My_Int_IO;`{| Get_Line 
for type String  |@#begin{| Get@&for type String  |@%^Put(2 + 2)
;`{| New_Line@2|@%^New_Line;`{| ...@7|@#end Add;{|@;|{|  ______ 
Integer_IO ______ |@#^______ My_Int_IO _______`{|  | Put for typ
e <>@&| |@#^| Put for type Integer |`{|  | Get for type <>@&| |@
#^| Get for type Integer |`{|  | ...@2| |@#^| ...@2|`{|  |______
________________| |@#^|______________________|`{|_______________
____________|{{Since Integer_IO (and therefore My_Int_IO) doesn'
t have a Put_Line, we call{My_Int_IO.Put and then Text_IO.New_Li
ne.  Note that our program says{%use My_Int_IO;~after declaring 
My_Int_IO.  When the compiler sees the call{%Put(2 + 2);~it writ
es code to call My_Int_IO.Put rather than Text_IO.Put,{because M
y_Int_IO.Put takes a parameter of type Integer.  The compiler th
en{finds New_Line in Text_IO and writes a call to Text_IO.New_Li
ne.{}b[ 181B179]True or False?  In our example, a program could 
call^Integer_IO.Put`.{}Please press T for true or F for false, o
r B to go back.[F182T183B180]%You're right!~ Since Integer_IO is
 generic, a program can't call its procedures{and functions.  Th
e program must specify the type and create an^instance~of{Intege
r_IO, such as My_Int_IO.  It can then call Put in My_Int_IO.  No
te also{that we can't^use~a generic package like Integer_IO, but
 only an instance of it{like My_Int_IO.{}q[ 184B181Q181]False.  
Since Integer_IO is generic, a program can't call its procedures
 and{functions.  The program must specify the type and create an
^instance~of{Integer_IO, such as My_Int_IO.  It can then call Pu
t in My_Int_IO.  Note also{that we can't^use~a generic package l
ike Integer_IO, but only an instance of it{like My_Int_IO.{}q[ 1
84B181Q181]@=GENERIC INSTANTIATION{{@0^package My_Int_IO is new 
Integer_IO(Integer);`{{@.______ Integer_IO ______@#^______ My_In
t_IO _______`{@.| Put for type <>@&|@#^| Put for type Integer |`
{@.| Get for type <>@&|@#^| Get for type Integer |`{@.| ...@2|@#
^| ...@2|`{@.|______________________|@#^|______________________|
`{{This process of creating an^instance~of the generic package I
nteger_IO for the{type Integer is called^generic instantiation`.
  Later in this course we'll{learn to write our own generic pack
ages, procedures, and functions.  However,{we wanted to learn, e
arly in the course, how to instantiate an already written{generi
c package in order to display integers.{{But why does Ada make T
ext_IO ready-to-use for Strings, while Integer_IO is{generic, an
d has to be instantiated for Integers?  Because programs normall
y{use only one type String, but can have several integer types. 
 Right now, we{know of only one integer type, the standard Integ
er.  Later we'll learn about{user-defined types and derived type
s, and we'll see how there can be many{integer types.  Integer_I
O can be instantiated for each of these types.{}b[ 185B181]Since
 Integer_IO is often instantiated for the standard Integer type,
 some{implementations of Ada provide an already-instantiated pac
kage for the type{Integer, equivalent to our package My_Int_IO. 
 However, an implementation of{Ada need not supply such a packag
e to meet the Ada standard.  Our program did{its own instantiati
on of Integer_IO so that it would run on any Ada that meets{the 
standard.{{There's another generic package within Text_IO called
 Float_IO.  Input and{output of floating point numbers is done b
y instantiating Float_IO for the type{Float.  As with integers, 
we'll later learn how there can be several floating{point types 
besides the standard Float.{{Later in this course, when we cover
 attributes, we'll learn another way to{display Integers by usin
g the^'Image~attribute.{{We're now ready for our first Outside A
ssignment!  Let's compile and run our{two sample programs, Hello
 and Add.{}b[ 186B184]@*OUTSIDE ASSIGNMENT 1 - PREPARING TO RUN 
ADA ON YOUR COMPUTER{{Since these screens disappear, you'll prob
ably want to refer to your printed{course notes when doing the O
utside Assignments.  The first assignment appears{on page 8.  In
 this assignment, we'll compile, link, and run our first two{pro
grams, Hello and Add.{{First compile HELLO.ADA, then link, and t
hen execute the program.  The exact{steps will depend on the Ada
 compiler you're using.  You'll probably have to{refer to the do
cumentation that came with your compiler.  Note that some{implem
entations of Ada use the term "binding" instead of "linking."  W
hen you{run the program, it should display^Hello!~on your screen
.{{Then compile ADD.ADA, link, and run the program.{{When we com
pile, we specify the name of the source file being compiled.  Ma
ny,{but not all, implementations of Ada assume the extension to 
be .ADA if it's not{specified.  When we link, we specify the nam
e of the main program, which in our{examples agrees with the nam
e of the source file.  The linking step produces a{file which we
 can execute.{}b[ 187B185]Before we can compile an Ada program, 
we must create our own Ada library.  Some{implementations of Ada
 come with a library already created for us; others{require us t
o type a command to create a library.  When we compile HELLO.ADA
{and ADD.ADA, the procedures HELLO and ADD are added to our libr
ary.  We'll{discuss the Ada library in more detail later.{{If yo
u haven't done so already, please type X to exit^ADA-TUTR~tempor
arily,{read page 8 of your printed course notes, and try the fir
st Outside Assignment.{{When you finish Outside Assignment 1, we
'll go on to discuss the Ada library{and separate compilation of
 program units.{}Please type X to exit, a space to go on, or B t
o go back.[ 188B186]@-^Congratulations on Completing Outside Ass
ignment 1!`{{We know this first assignment wasn't very interesti
ng, because the programs{HELLO.ADA and ADD.ADA were supplied for
 you.  But we had to be sure we can{compile, link, and execute A
da programs, so we can do the remaining{assignments.{{The rest o
f the Outside Assignments should be more challenging!{{Let's go 
on to discuss the Ada library and separate compilation of progra
m{units.{}b[ 189B187]@@THE ADA LIBRARY{{What's the difference be
tween an Ada library, and, say, a Fortran library?{Compilers for
 languages other than Ada simply take source code and produce{ob
ject code.  Compiling a Fortran program doesn't change the Fortr
an library.{Ada compilers, however, take source code and a libra
ry and produce object code{and an updated library. ^The Ada libr
ary remembers what we've compiled.~ Other{languages have librari
es of functions, etc., but they're fixed and don't{remember what
 we've compiled.{@@________________{@?|@0|{@-Source Code@'|  For
tran,@&|@&Object Code{@'----------------------->|  Pascal, etc. 
 |----------------------->{@?|  Compiler@&|{@?|________________|
{{@@________________{@-Source Code@'|@0|@&Object Code{@'--------
--------------->|  Ada@+|----------------------->{@-Ada Library@
'|  Compiler@&|  Updated Ada Library{@'----------------------->|
@0|----------------------->{@?|________________|{}b[ 190B188]Ada
 gives us the advantage that compilation is^separate but depende
nt`.  Some{languages, such as Fortran, offer^separate and indepe
ndent~compilation.  A{Fortran main program and a subroutine can 
be compiled independently, perhaps a{month apart.  When the subr
outine is compiled, Fortran knows nothing about the{main program
, and vice versa.  An advantage of^separate~compilation is that 
we{can develop our program one piece at a time and compile each 
piece as it's{developed.  However, the^independent~compilation i
s a disadvantage.  The{compiler can't check that the number and 
types of parameters in the call agree{with the number and types 
of parameters in the subroutine.  A Fortran main{program might s
ay^CALL SUB(I, J, K)`, while the subroutine might say{%SUBROUTIN
E SUB(I, J)`.  Both of these will compile correctly.  When the p
rogram{is run, however, the results are unpredictable.  The prog
ram might simply give{wrong answers with no warning.{{Other lang
uages, such as early Pascal and many versions of Basic, don't ha
ve{separate compilation at all.  The compiler could check the nu
mber and types of{parameters in a call, because the entire progr
am must be compiled at one time.{But the advantages of separate 
compilation are lost.  We can't develop the{program one piece at
 a time, compiling each piece as it's developed.  And if we{make
 the slightest change in one part of the program, the whole prog
ram has to{be recompiled.{}b[ 191B189]Ada gives us the advantage
s of both systems, because compilation is^separate{but dependent
`.  We can compile a subprogram today and the calling program ne
xt{month.  (We could also put both into one file and compile the
m together.)  Each{compilation unit updates the library when it'
s successfully compiled.  Thus,{when a call to a subprogram is e
ncountered, the compiler will check the number{and types of para
meters against the subprogram already in the library.{{We could 
also write the calling program^before~the subprogram, because Ad
a lets{us compile the subprogram^specification~separately from i
ts^body`.  (We'll learn{more about that later.)  The specificati
on contains the name of the subprogram,{and the names, number, a
nd types of any parameters.  The specification also{tells which 
parameters are inputs, which are outputs, and which are both inp
uts{and outputs.  That's all the information the compiler needs 
to compile calls to{the subprogram; the body can be supplied lat
er.  When the subprogram body is{compiled, the compiler will mak
e sure it's consistent with the specification.{{Ada comes with s
everal packages, such as Text_IO.  These are already compiled{an
d placed into the library.  That's why our programs can say^with
 Text_IO;~and{call its procedures and functions.{{Ada libraries 
are a complication compared to other languages, but they offer{g
reat advantages in program development.{}b[ 192B190]True or Fals
e?  A procedure specification must be compiled before calls to t
he{procedure can be compiled.{}Please press T for true or F for 
false, or B to go back.[T193F194B191]%You're right!~ The specifi
cation contains all the information the compiler{needs to compil
e calls to the procedure.{}q[ 195B192Q192]True.  The compiler ne
eds the information in the specification to compile calls{to the
 procedure.  However, the procedure^body~can be compiled later.{
}q[ 195B192Q192]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Re
cursion and Assignment 4{{@#The Format of an Ada Program@-Subpro
grams and Packages{{@#Generic Instantiation and@0Access Types, U
ser Defined Types,{@&Assignment 1@=and Derived Types{{%>  SIMPLE
 DECLARATIONS AND SIMPLE~@*Exceptions, Text_IO, and{@%^ATTRIBUTE
S~@>Assignment 5{{@#Operators, Control Constructs, and@'Generics
, Tasking, and Assignment 6{@&Assignment 2{@LMore Records and Ty
pes{@#Records, Arrays, and Assignment 3{@LAdvanced Topics{}b[ 19
6B192]@=VARIABLES AND CONSTANTS{{@&procedure Declarations_Demo i
s{@(^I, J, K : Integer;`{@(^L, M@$: Integer := 30;`{@)F, G@$: Fl
oat;{@)Factor  : constant := 1000;{@&begin{@)J := L + 10;@*-- Si
mple assignment statements.{@)F := 0.0;{@)G := F + L;@+-- ILLEGA
L.  Can't accidentally mix types.{@)G := F + Float(L);@$-- Legal
.  May deliberately convert types.{@)K := Integer(F) + L;  -- Le
gal.{@)Factor := 1000;@'-- ILLEGAL.  Factor is a constant.{@&end
 Declarations_Demo;{{This program doesn't do anything except dem
onstrate Ada declarations.  The{statement^I, J, K : Integer;~bri
ngs three integer variables into existence.{The next statement c
reates two more integer variables and initializes both of{them t
o 30.  Every time this procedure is called, L and M are brought 
into{existence and initialized to 30.  This is different from a 
Fortran DATA{statement, which initializes only once at compile t
ime.{}b[ 197B195]@&procedure Declarations_Demo is{@)I, J, K : In
teger;{@)L, M@$: Integer := 30;{@(^F, G@$: Float;`{@(^Factor  : 
constant := 1000;`{@&begin{@(^J := L + 10;@*-- Simple assignment
 statements.`{@(^F := 0.0;`{@(^G := F + L;@+-- ILLEGAL.  Can't a
ccidentally mix types.`{@)G := F + Float(L);@$-- Legal.  May del
iberately convert types.{@)K := Integer(F) + L;  -- Legal.{@)Fac
tor := 1000;@'-- ILLEGAL.  Factor is a constant.{@&end Declarati
ons_Demo;{{The statement^F, G@$: Float;~creates two variables of
 type Float.  The next{statement names a constant.  Writing^Fact
or~is thereafter equivalent to writing{%1000`.  Unlike variables
, constants^must~be initialized.{{The first two executable state
ments are simple assignment statements.  The{symbol^:=~is read "
becomes" or "gets."  It may not contain a space.  In the{third e
xecutable statement, the compiler will reject the expression^F +
 L`{because Ada doesn't let us accidentally mix a Float with an 
Integer.{}b[ 198B196]@&procedure Declarations_Demo is{@)I, J, K 
: Integer;{@)L, M@$: Integer := 30;{@)F, G@$: Float;{@)Factor  :
 constant := 1000;{@&begin{@)J := L + 10;@*-- Simple assignment 
statements.{@)F := 0.0;{@)G := F + L;@+-- ILLEGAL.  Can't accide
ntally mix types.{@(^G := F + Float(L);@$-- Legal.  May delibera
tely convert types.`{@(^K := Integer(F) + L;  -- Legal.`{@(^Fact
or := 1000;@'-- ILLEGAL.  Factor is a constant.`{@&end Declarati
ons_Demo;{{However, Ada lets us^deliberately~mix types.  The sta
tement^G := F + Float(L);`{is legal because it converts L from I
nteger to Float, adds it to F which is of{type Float, and stores
 the result in G, also of type Float.  Likewise, the next{statem
ent is legal because it converts F to Integer, adds the integer 
L, and{stores the result in the integer K.  But note that when a
 Float is converted to{Integer, it's rounded, not truncated.  (L
ater we'll present two functions that{truncate integers.)  The l
ast executable statement is illegal because a{constant can't app
ear on the left side of an assignment statement.{}b[ 199B197]@'^
with Text_IO; use Text_IO;`{@'^procedure Try_Me is`{@*^package M
y_Int_IO is new Integer_IO(Integer); use My_Int_IO;`{@*^N : Inte
ger := 1;`{@'^begin`{@*^Put(N);`{@*^New_Line;`{@*^N := 2;`{@'^en
d Try_Me;`{{What number will be displayed the^second~time proced
ure Try_Me is called?{{@81.  The program will display 1.{{@82.  
The program will display 2.{}Please press 1 or 2, or B to go bac
k.[12002201B198]@'^with Text_IO; use Text_IO;`{@'^procedure Try_
Me is`{@*^package My_Int_IO is new Integer_IO(Integer); use My_I
nt_IO;`{@*^N : Integer := 1;`{@'^begin`{@*^Put(N);`{@*^New_Line;
`{@*^N := 2;`{@'^end Try_Me;`{{%You're right!~ N is brought into
 existence and initialized to 1 each time the{procedure is calle
d, so 1 will be displayed.{}q[ 202B199Q199]@(with Text_IO; use T
ext_IO;{@(procedure Try_Me is{@+package My_Int_IO is new Integer
_IO(Integer); use My_Int_IO;{@+N : Integer := 1;{@(begin{@+Put(N
);{@+New_Line;{@+N := 2;{@(end Try_Me;{{No, N is declared locall
y within Try_Me.  So N is brought into existence and{initialized
 to 1^each~time the procedure is called, and the procedure will{
display 1 each time.  Also remember that N goes out of existence
 when Try_Me{returns, so the statement N := 2; has no effect.{}q
[ 202B199Q199]@?ENUMERATION TYPES{{In Ada we can declare^enumera
tion types`, where we enumerate every possible{value for a type.
  For example, if we declare{{  ^type Rainbow_Color is (Red, Ora
nge, Yellow, Green, Blue, Indigo, Violet);`{  ^Rc : Rainbow_Colo
r;`{{then Rc can have any of 7 values.  In the executable region
 we might write{%Rc := Red;~and we could also test:^if Rc = Red 
then~...^end if;`.  The{enumerated values, enclosed in parenthes
es, must follow the rules for Ada{identifiers, or they can be si
ngle^characters~enclosed in^'~marks (called "tic"{marks), thus:{
{@1^type Even_Digit is ('0', '2', '4', '6', '8');`{{It's illegal
 to write^type Processor is (80386, Z80, 1750A);~because two of 
the{values aren't legal Ada identifiers.  However, it's OK to mi
x characters and{identifiers in the same declaration, thus:{{@4^
type Mixed is (Big, Small, 'X', '9');`{}b[ 203B199]  ^type Rainb
ow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);`
{  ^type Traffic_Light_Color is (Red, Amber, Green);`{  ^Rc : Ra
inbow_Color;`{  ^Tc : Traffic_Light_Color;`{{With the above decl
arations, Rc could have any of 7 values, and Tc could have{any o
f 3 values.  The compiler will have no trouble compiling{{@B^Rc 
:= Red;`{@B^Tc := Red;`{{because it knows that in^Rc := Red;~Red
 must be the Rainbow_Color if it's{stored into Rc, and in^Tc := 
Red;~Red must be the Traffic_Light_Color if it's{stored into Tc.
  The compiler knows that the types across^:=~must always match.
{Naturally, it's illegal to write^Rc := 2;~because of the mixed 
types.{{Also, if we have a procedure Display that takes one para
meter of type{Rainbow_Color, the compiler could handle^Display(R
ed);~because it knows that{Red must be the Rainbow_Color to fit 
the procedure.{}b[ 204B202]  ^type Rainbow_Color is (Red, Orange
, Yellow, Green, Blue, Indigo, Violet);`{  ^type Traffic_Light_C
olor is (Red, Amber, Green);`{{However, if we had a procedure Di
splay that takes one Rainbow_Color and another{procedure Display
 that takes one Traffic_Light_Color, then the statement{%Display
(Red);~would be ambiguous; the compiler couldn't possibly know w
hich{Display to call.  In that case, we could specify the type b
y writing{%Rainbow_Color'(Red)`.  This is called^qualifying~the 
name Red; note the^'~with{the parentheses.  The call would be wr
itten^Display(Rainbow_Color'(Red));`.  The{statements^Display(Vi
olet);~and^Display(Amber);~aren't ambiguous; the compiler{will f
igure out which Display to call in these cases.{{Declaring an en
umeration type not only defines equality for objects of that{typ
e, but also an order for the values.  Thus we can check for <, >
, <=, etc.{For example, if we declare^A, B: Rainbow_Color;~and l
ater write, in the{executable region,^A := Yellow;~and^B := Blue
;~then the test^if A < B then~...{%end if;~will turn out to be T
rue. ^Yellow~is considered less than^Blue`.{{Input and output of
 enumeration types can be done by instantiating the generic{pack
age Text_IO.Enumeration_IO.  For example:{%with Text_IO; use Tex
t_IO;~...{%package My_Rainbow_IO is new Enumeration_IO(Rainbow_C
olor); use My_Rainbow_IO;`{}b[ 205B203]Here are two enumeration 
types built into Ada 83:{{@%^type Boolean is (False, True);`{{@%
^type Character is (~(nul)%,~(soh)%,~(stx)%,~...^, ' ', '!', '"'
,~...^,`{@9^'0', '1', '2',~...^, 'A', 'B', 'C',~...^,`{@9^'a', '
b', 'c',~...^,~(del)^);`{{Since the above two declarations are b
uilt into the Ada language, they{shouldn't be repeated in your p
rograms.  Note that type Boolean is just an{enumeration type.  T
he relational operators (^=`,^>`,^<=`, etc. ) all return{results
 of type Boolean.{{The definition of type Character can't be com
pletely written out, because there{are 33 unprintable ASCII char
acters.  However, the enumeration type Character{contains all 12
8 values, in ASCII character order.  On this screen, we've{denot
ed the unprintable characters with names in parentheses, and we'
ve also{used "..." for brevity.  Even if Ada is run on an EBCDIC
 machine, it's{guaranteed that type Character contains the 128 A
SCII characters in ASCII{character order.  (In Ada 9X, type Char
acter contains all 256 8-bit values, and{a type Wide_Character i
s also defined, containing all 65,536 16-bit values.){}b[ 206B20
4]@.1.  type Count is ("1", "2", "3", "Ab", "Cd", "Ef");{{@.2.  
type Count is ('1', '2', '3', 'Ab', 'Cd', 'Ef');{{@.3.  type Cou
nt is (1, 2, 3, Ab, Cd, Ef);{{@.4.  type Count is ('1', '2', '3'
, Ab, Cd, Ef);{{{Which^one~of the above type declarations is leg
al?{}Please press 1, 2, 3, or 4, or B to go back.[42071208220932
10B205]@.1.  type Count is ("1", "2", "3", "Ab", "Cd", "Ef");{{@
.2.  type Count is ('1', '2', '3', 'Ab', 'Cd', 'Ef');{{@.3.  typ
e Count is (1, 2, 3, Ab, Cd, Ef);{{@-^4.  type Count is ('1', '2
', '3', Ab, Cd, Ef);`{{{%You're right!~ Enumeration types can co
ntain single characters between^'~marks,{and Ada identifiers.  N
umber 1 is illegal because it contains Strings, number 2{is ille
gal because^'~marks may enclose only single characters, and numb
er 3 is{illegal because an Ada identifier can't begin with a dig
it.{}q[ 211B206Q206]@.1.  type Count is ("1", "2", "3", "Ab", "C
d", "Ef");{{@.2.  type Count is ('1', '2', '3', 'Ab', 'Cd', 'Ef'
);{{@.3.  type Count is (1, 2, 3, Ab, Cd, Ef);{{@.4.  type Count
 is ('1', '2', '3', Ab, Cd, Ef);{{{No, number 1 is illegal becau
se an enumeration type can't contain Strings, only{single charac
ters between^'~marks, and Ada identifiers.{}q[ 211B206Q206]@.1. 
 type Count is ("1", "2", "3", "Ab", "Cd", "Ef");{{@.2.  type Co
unt is ('1', '2', '3', 'Ab', 'Cd', 'Ef');{{@.3.  type Count is (
1, 2, 3, Ab, Cd, Ef);{{@.4.  type Count is ('1', '2', '3', Ab, C
d, Ef);{{{No, number 2 is illegal because only single characters
 may appear between^'`{marks.  Enumeration types contain single 
characters between^'~marks, and Ada{identifiers.{}q[ 211B206Q206
]@.1.  type Count is ("1", "2", "3", "Ab", "Cd", "Ef");{{@.2.  t
ype Count is ('1', '2', '3', 'Ab', 'Cd', 'Ef');{{@.3.  type Coun
t is (1, 2, 3, Ab, Cd, Ef);{{@.4.  type Count is ('1', '2', '3',
 Ab, Cd, Ef);{{{No, number 3 is illegal because an Ada identifie
r can't begin with a digit.{Enumeration types can contain only s
ingle characters between^'~marks, and Ada{identifiers.{}q[ 211B2
06Q206]@DSUBTYPES{{A subtype does^not~define a new type, but it 
imposes a range constraint on{objects of that subtype.  For exam
ple,{{%subtype Day_Subtype is Integer range 1 .. 31;{D : Day_Sub
type; -- D can have only Integer values from 1 to 31.`{{type Rai
nbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet)
;{%subtype Bright_Color is Rainbow_Color Range Orange .. Green;{
B : Bright_Color; -- B can have only Rainbow_Color values from O
range to Green.`{{%subtype Probability is Float range 0.0 .. 1.0
;{P : Probability; -- P can have only Float values from 0.0 to 1
.0.`{{Every time the program stores a value into D, B, or P, a c
heck is made to see{if the value is in range.  If it isn't, the 
message Constraint_Error is{displayed.  Constraint Errors are us
ually detected at run time.{{Since subtypes don't define new typ
es, the^type~of D is Integer, the type of B{is Rainbow_Color, an
d that of P is Float.  Thus, if we write^I : Integer;~we{may wri
te^D := D + I;~etc., because D and I have the same type.{}b[ 212
B206]We don't have to supply a name for the subtype explicitly. 
 If we declare{{@:^D : Integer range 1 .. 31;`{{the compiler cre
ates its own name for the subtype internally; we never see it.{T
his is called an^anonymous~subtype.  The name the compiler creat
es will be one{that we can't accidentally create ourselves.  Per
haps it will contain a control{character or punctuation mark tha
t Ada doesn't allow us to put into an{identifier.  The above dec
laration is equivalent to{{@0^subtype~(something)^is Integer ran
ge 1 .. 31;`{@0^D :~(something)%;`{{where (something) represents
 the anonymous subtype that we can't see or write.{}b[ 213B211]@
?SIMPLE ATTRIBUTES{{An^attribute~consists of an apostrophe (call
ed a "tic" mark for short), and the{name of the attribute.  Attr
ibutes often follow type names.  They're something{like function
s, except that they usually involve a type.  For example:{{@#typ
e Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Vi
olet);{@#type Traffic_Light_Color is (Red, Amber, Green);{  ^Rai
nbow_Color'Succ(Green)~@&is^Blue`{  ^Traffic_Light_Color'Pred(Gr
een)~is^Amber`{{The attributes^Succ~and^Pred~stand for successor
 and predecessor, respectively.{In Rainbow_Colors, the successor
 of^Green~is^Blue`, and in Traffic_Light_Colors,{the predecessor
 of^Green~is^Amber`.  Thus we could write^R : Rainbow_Color;~and
{then^R := Rainbow_Color'Succ(Green);`.  You'll get a Constraint
_Error if you{try to take the successor of the last value or the
 predecessor of the first;{for example, taking Rainbow_Color'Pre
d(Red) will cause an error.{{Succ and Pred work with any^discret
e type`.  That means any integer type or{enumeration type.  Thes
e two attributes aren't particularly useful with integer{types, 
because we can simply add or subtract 1 instead.  So they're usu
ally{used with enumeration types.{}b[ 214B212]@#type Rainbow_Col
or is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#type
 Traffic_Light_Color is (Red, Amber, Green);{{The attribute^Pos~
converts from a discrete type to an integer, and^Val~converts{fr
om an integer to a discrete type.  Again, the type is usually an
 enumeration{type, because there's little point converting from 
integer to integer.{{For example,^Rainbow_Color'Pos(Orange)~is^1
`.  (The positions are numbered from{zero.) ^Rainbow_Color'Pos(R
ed)~is^0~and^Rainbow_Color'Pos(Violet)~is^6`.{%Traffic_Light_Col
or'Pos(Green)~is^2`, but^Rainbow_Color'Pos(Green)~is^3`.{%Charac
ter'Pos('A')~is^65`, because the ASCII value of 'A' is 65, and t
he{Ada 83 type Character contains all 128 characters in ASCII or
der.{%Character'Pos('0')~is^48`, because the ASCII value of the 
character '0' is 48.{(Note that in Ada 9X, Character'Pos can be 
as high as 255, because the Ada 9X{type Character contains 256 v
alues, from position 0 through position 255.){{%Val~converts the
 other way, so^Rainbow_Color'Val(0)~is^Red`, and{%Rainbow_Color'
Val(6)~is^Violet`.  Taking the Rainbow_Color'Val of a parameter{
outside the range 0 .. 6 will raise a Constraint_Error. ^Charact
er'Val(65)~is{%'A'`, and^Character'Val(7)~is the "bell" characte
r (control-G).  Since Boolean{is an enumeration type,^Boolean'Va
l(0)~is^False~and^Boolean'Val(1)~is^True`.{}b[ 215B213]@%type Mo
nth_Type is (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{{
@:What is Month_Type'Pos(Feb)?{{{@:1.  Month_Type'Pos(Feb) is 1.
{{@:2.  Month_Type'Pos(Feb) is 2.{}Please press 1 or 2, or B to 
go back.[12162217B214]@%type Month_Type is (Jan,Feb,Mar,Apr,May,
Jun,Jul,Aug,Sep,Oct,Nov,Dec);{{%You're right!~ The positions are
 numbered from zero, so Feb is in position 1,{and Month_Type'Pos
(Feb) is 1.{}q[ 218B215Q215]@%type Month_Type is (Jan,Feb,Mar,Ap
r,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{{No, the positions are numbe
red from zero, so Feb is in position 1, and{Month_Type'Pos(Feb) 
is 1.{}q[ 218B215Q215]While^Pos~and^Val~convert to and from inte
gers, the attributes^Image~and^Value`{convert to and from String
s.  They work with any discrete types, and are useful{with integ
er types as well as enumeration types.  For example,{{@#type Rai
nbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet)
;{@#type Traffic_Light_Color is (Red, Amber, Green);{{  ^Rainbow
_Color'Value("RED")~@&is^Red`{  ^Rainbow_Color'Value("yellow")~@
#is^Yellow`{  ^Traffic_Light_Color'IMAGE(Amber)~is^"AMBER"`{{  ^
Integer'Value("123")~is^ 123`{  ^Integer'Image(123)~  is^" 123"`
{  ^Integer'Image(-123)~ is^"-123"`{{If I is an Integer, we can 
write^Put(Integer'Image(I));~without having to{instantiate Integ
er_IO.  However, this won't work for type Float, only for{discre
te types. ^Value~will raise a Constraint_Error if the String can
't be{converted to the discrete type.  For example, taking^Integ
er'Value("12X3")~or{%Rainbow_Color'Value("CHARTREUSE")~will norm
ally display Constraint_Error on the{screen and stop the program
.{}b[ 219B215]For any discrete type, the attributes^First~and^La
st~are also available.{{@#type Rainbow_Color is (Red, Orange, Ye
llow, Green, Blue, Indigo, Violet);{@#type Traffic_Light_Color i
s (Red, Amber, Green);{  ^Rainbow_Color'First~@%is^Red`{  ^Traff
ic_Light_Color'Last~is^Green`{{A program can use these attribute
s with Integer to determine the size of{integers on the host com
puter.  For example, if your PC Ada has 16-bit 2's{complement in
tegers, while a mainframe Ada uses 32-bit 2's complement, then{{
@#^Integer'First~is^-32_768~on your PC and^-2_147_483_648~on the
 mainframe.{@#^Integer'Last~ is ^32_767~on your PC and^ 2_147_48
3_647~on the mainframe.{{Most attributes may also be used with s
ubtypes:{@1subtype Day_Subtype is Integer range 1 .. 31;{@0^Day_
Subtype'First~is^1`{@0^Day_Subtype'Last~ is^31`{{There are two s
ubtype definitions involving^Last~built into the Ada language:{@
-^subtype Positive is Integer range 1 .. Integer'Last;`{@-^subty
pe Natural  is Integer range 0 .. Integer'Last;`{}b[ 220B218]Mor
e attributes are discussed in the Advanced Topics section.  In s
ummary,{%discrete type~means any integer or enumeration type.  (
The only integer type{we've learned about so far is the standard
 Integer.){{@&^Pos~converts from a discrete type to an integer.{
@&^Val~converts from an integer to a discrete type.{@&^Image~con
verts from a discrete type to String.{@&^Value~converts from Str
ing to a discrete type.{@&^First~and^Last~take no parameter and 
give a discrete type.{@&^Succ~and^Pred~take a discrete type and 
give the same discrete type.{{{@'Also remember that a type name 
followed by^'~denotes an^attribute`:{@9Put(%Character'`Val(7)); 
-- beep{{@0A type name followed by^( )~denotes^conversion`:{@?G 
:= F +^Float(`I%)`;{{@,And a type name followed by^'( )~denotes^
qualification`:{@:Display(%Rainbow_Color'(`Red%)`);{}b[ 221B219]
@*1.  Rainbow_Color'First@-5.  Rainbow_Color'Pred{{@*2.  Rainbow
_Color'Image@-6.  Rainbow_Color'Succ{{@*3.  Rainbow_Color'Last@.
7.  Rainbow_Color'Val{{@*4.  Rainbow_Color'Pos@/8.  Rainbow_Colo
r'Value{{{Which one of the above attributes would you use to con
vert from the String{%"Blue"~to the Rainbow_Color^Blue`?{}Please
 press 1, 2, 3, 4, 5, 6, 7, or 8, or B to go back.[8222122322243
2234225522662267227B220]%You're right!~ The attribute^Value~conv
erts from String to a discrete type.{{@5^Rainbow_Color'Value("Bl
ue")~is^Blue`.{}q[ 228B221Q221]No,^First~and^Last~take no parame
ter and return a discrete type:{{@)^Rainbow_Color'First~is^Red~a
nd^Rainbow_Color'Last~is^Violet`.{{You want to convert from a St
ring parameter to a discrete type.{}q[ 228B221Q221]No,^Image~con
verts from a discrete type to String:{{@5^Rainbow_Color'Image(Bl
ue)~is^"BLUE"`.{{You want to convert from String to a discrete t
ype.{}q[ 228B221Q221]No,^Pos~converts from a discrete type to an
 integer:{{@8^Rainbow_Color'Pos(Blue)~is^4`.{{You want to conver
t from String to a discrete type.{}q[ 228B221Q221]No,^Pred~and^S
ucc~take a discrete type parameter and return the same discrete{
type.{{  ^Rainbow_Color'Pred(Blue)~is^Green~and^Rainbow_Color'Su
cc(Blue)~is^Indigo`.{{You want to convert from String to a discr
ete type.{}q[ 228B221Q221]No,^Val~converts from an integer to a 
discrete type.{{@8^Rainbow_Color'Val(4)~is^Blue`.{{You want to c
onvert from String to a discrete type.{}q[ 228B221Q221]@;^ADA-TU
TR COURSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{
{@#The Format of an Ada Program@-Subprograms and Packages{{@#Gen
eric Instantiation and@0Access Types, User Defined Types,{@&Assi
gnment 1@=and Derived Types{{@#Simple Declarations and Simple@+E
xceptions, Text_IO, and{@&Attributes@?Assignment 5{{%>  OPERATOR
S, CONTROL CONSTRUCTS, AND~@&Generics, Tasking, and Assignment 6
{@%^ASSIGNMENT 2`{@LMore Records and Types{@#Records, Arrays, an
d Assignment 3{@LAdvanced Topics{}b[ 229B221]@COPERATORS{{The fo
ur basic arithmetic operators,^+`,^-`,^*`, and^/`, can be used w
ith any{integer or floating point type.  (We'll learn about fixe
d point types in the{section on More Records and Types.)  The ex
ponentiation operator,^**`, takes a{base of type Integer or Floa
t, and an exponent of subtype Natural.  It returns{the same type
 as the base.  Although Float ** Float isn't part of the Ada 83{
language, a vendor may supply a math package with an Ada compile
r to increase{its sales appeal.  If the math package includes a 
function "**" to raise a{Float base to a Float exponent, then ou
r programs can^with~and^use~the package{and then use^**~between 
two Floats.{{Similarly, Exp, Log, and the trig functions don't c
ome with Ada 83, but the{vendor may supply them in a math packag
e.{{Ada 9X comes with a package called Numerics.Elementary_Funct
ions that provides{Float ** Float, Exp, Log, and the trig functi
ons.  See Appendix C of the Ada 9X{LRM.{}b[ 230B228]The six^rela
tional operators~are:{{%<~ less than@1^>~ greater than@1^=~ equa
l to{{%<=~less than or equal to@%^>=~greater than or equal to@%^
/=~not equal to{{Five of these are the same as in Basic and Pasc
al, but the Ada symbol for "not{equal to" is^/=`, because^<>~mea
ns^box`.  The relational operators compare two{objects of the sa
me type, and return a result of type Boolean.{{All of the above 
operators are used^between~two objects (e.g.,^B := A + B;`).{Of 
course,^+~and^-~may also be^unary~operators (%B := +A;  A := -A;
`).{{The operators^and`,^or`, and^xor~are used between two Boole
an objects, and^not~is{a unary Boolean operator.  Naturally,^xor
~is the exclusive or: ^A xor B~is True{if either A or B is True,
 but not if both are True.{}b[ 231B229]The numeric operator^abs~
takes the absolute value of an Integer or Float.{Since^abs~is a 
unary operator like^-`, we can write^B := abs A;`.  We may, but{
don't have to, use parentheses and write^B := abs(A);`.{{When us
ed between two integers,^/~gives only the integer part of the qu
otient.{Thus^9/4~is 2.  The operators^mod~(modulo) and^rem~(rema
inder) are very similar{to each other, and are used between two 
integers to give only the remainder in{division.  For example,^9
 mod 4~is 1.  For positive parameters,^mod~and^rem~are{the same.
  But with negative parameters,^mod~gives the sign of the denomi
nator{while^rem~gives the sign of the numerator.  Many programme
rs simply ignore^rem`{and use^mod~exclusively.{{The operator^&~c
oncatenates arrays, so we'll discuss it later.  We'll learn{that
 a String is one type of array (an array of Characters), so^&~ca
n{concatenate Strings.{}b[ 232B230]@BRANGE TESTS{{The reserved w
ord^in~tests if something is inside a range, and returns a{Boole
an result.  For example, if Lower, Upper, and X are declared as 
Floats, we{need not write{{@0^if X >= Lower and X <= Upper then~
...^end if;`{{This can be expressed more clearly as{{@3^if X in 
Lower .. Upper then~...^end if;`{{We can also write^not in`.  Th
us^X not in Lower .. Upper~is a clear way of{expressing^X < Lowe
r or X > Upper`.{{A subtype may be substituted for the range to 
the right of^in`.  If Day_Subtype{is defined as a subtype of Int
eger, and D is an Integer, then we can write{%D in Day_Subtype`.
{}b[ 233B231]If we have the following declarations:{{@=B@': Bool
ean;{@=A, X, Y : Character;{{then which^one~of the following is^
illegal`?{{@71.@$B := X <> Y;{{@72.@$B := A in X .. Y;{{@73.@$B 
:= A = X and X = Y;{}Please press 1, 2, or 3, or B to go back.[1
23422353236B232]@=B@': Boolean;{@=A, X, Y : Character;{{{@6^1.@$
B := X <> Y;`{{@72.@$B := A in X .. Y;{{@73.@$B := A = X and X =
 Y;{{{%You're right!~ Number 1 is illegal because^<>~should be^/
=`.{}q[ 237B233Q233]@=B@': Boolean;{@=A, X, Y : Character;{{{@71
.@$B := X <> Y;{{@72.@$B := A in X .. Y;{{@73.@$B := A = X and X
 = Y;{{{No, number 2 is legal.  The reserved word^in~tests to se
e if A is within the{range X to Y.  It returns a Boolean result,
 which is stored in B.{}q[ 237B233Q233]@=B@': Boolean;{@=A, X, Y
 : Float;{{{@71.@$B := X <> Y;{{@72.@$B := A in X .. Y;{{@73.@$B
 := A = X and X = Y;{{{No, number 3 is legal.  Parentheses aren'
t necessary here, but it's the same as{if we had written{{@;B :=
 (A = X) and (X = Y);{{In two places^=~returns a Boolean result.
  Then^and~takes the two Boolean{results and also returns a resu
lt of type Boolean.  That final result is then{stored in B.{}q[ 
237B233Q233]@<THE SHORT CIRCUIT FORMS{{Suppose that^N~(for numer
ator) and^D~(for denominator) are Floats, and we want{to execute
 a block of code if the quotient is 10.0 or greater.  We could w
rite{{@:^if N/D >= 10.0 then`{@>-----;{@>-----;  (block of code)
{@>-----;{@:^end if;`{{However, we realize that if^D~is 0.0, the
 program will raise a Numeric_Error or{Constraint_Error trying t
o compute^N/D`.  If the denominator is zero, we{consider the quo
tient to be very large, so we want to execute the block of code{
when^D~is zero.  Our second attempt might be{{@9if^D = 0.0 or N/
D >= 10.0~then{@<-----;{@<-----;  (block of code){@<-----;{@9end
 if;{}b[ 238B233]@9if^D = 0.0 or N/D >= 10.0~then{@<-----;{@<---
--;  (block of code){@<-----;{@9end if;{{Here we^hope~that^N/D~w
on't be evaluated if^D~is zero.  We figure that the{compiler sho
uld be smart enough to know that if the expression before^or~is{
True, then the whole expression must be True, so the expression 
to the right of{%or~needn't be evaluated.  However, there's no g
uarantee that the compiler will{write code to skip the evaluatio
n of the second expression when the first is{True.  An optimizin
g compiler just might, for some unknown reason, even decide{that
 the expression on the right should be evaluated first.{{However
, with the form^or else`, Ada can bypass (or "short circuit") ev
aluating{the expression on the right when the one on the left is
 true:{{@6if D = 0.0^or else~N/D >= 10.0 then{@9-----;{@9-----; 
 (block of code){@9-----;{@6end if;{}b[ 239B237]@6if D = 0.0^or 
else~N/D >= 10.0 then{@9-----;{@9-----;  (block of code){@9-----
;{@6end if;{{Ada guarantees that the expression to the left of^o
r else~will be evaluated{first.  If this expression is True, the
 entire expression must be True, and{it's guaranteed that the se
cond expression won't be evaluated.  If the first{expression is 
False, then of course the second expression must be evaluated to
{determine if the entire expression is True.  Thus the code abov
e will never try{to divide by zero.  If^D~is zero, the expressio
n on the left is True.  The{expression on the right won't be eva
luated in that case.{{There's another "short circuit" form calle
d^and then`.  If the expression to{the left of^and then~is False
, the whole expression must be False, and the{expression on the 
right won't be evaluated.  If the expression on the left is{True
, then the expression on the right must be evaluated to determin
e the value{of the entire expression.  Suppose this time that we
 want to execute a block of{code if^N/D~is^less than~10.0.  If t
he denominator is zero, we consider the{quotient to be very larg
e, and we don't want to execute the block of code in{that case. 
 We can write the following:{}b[ 240B238]@6if D /= 0.0^and then~
N/D < 10.0 then{@9-----;{@9-----;  (block of code){@9-----;{@6en
d if;{{Again this protects us from trying to divide by zero.  If
^D~is zero, the{expression on the left is False.  The second exp
ression won't be evaluated in{that case.{{After we discuss array
s, we'll see how the short circuit forms can prevent us{from usi
ng out-of-range subscripts.  And when we learn about access type
s,{we'll see how the short circuit forms can keep us from derefe
rencing a null{pointer.  That means trying to access "the object
 pointed to" when there's no{such object.{{Remember,^and then~ev
aluates the second expression only if the first expression{is Tr
ue;^or else~evaluates the second expression only if the first is
 False.{}b[ 241B239]Assume that^N~has been declared^Float`, and 
that our program^with`s and^use`s a{math package with a square r
oot function called^Sqrt`.  Naturally, we don't want{to call^Sqr
t~with a negative parameter.  Which of the following would be mo
re{appropriate?{{{@+1.@$if N >= 0.0^and then~Sqrt(N) > 1.618 the
n ...{{@+2.@$if N >= 0.0^or else~ Sqrt(N) > 1.618 then ...{}Plea
se press 1 or 2, or B to go back.[12422243B240]@*^1.@$if N >= 0.
0 and then Sqrt(N) > 1.618 then ...`{{@+2.@$if N >= 0.0 or else 
 Sqrt(N) > 1.618 then ...{{{%You're right!~ We want the second e
xpression to be evaluated only if the first{expression is True, 
so we use^and then`.{}q[ 244B241Q241]@+1.@$if N >= 0.0 and then 
Sqrt(N) > 1.618 then ...{{@+2.@$if N >= 0.0 or else  Sqrt(N) > 1
.618 then ...{{{No, we want the second expression to be evaluate
d only if the first expression{is True, so we use^and then`.{}q[
 244B241Q241]@?CONTROL CONSTRUCTS{{You're almost ready to write 
your own Ada program in an Outside Assignment, but{first we need
 to discuss the control constructs.{{Ada encourages structured p
rogramming by providing control constructs such as{{@9block^if`s
 with^elsif`s and^else`{@8^while~loops{@8^for~loops{@8^case~stat
ements{{Ada also provides a^goto~statement, but it's seldom if e
ver needed.  That's{because the constructs above handle the flow
 of control more clearly, making{the program easier to read.  Wi
th the constructs above, we know how control{reaches each statem
ent.  When^goto`s are used, there can be many paths to a{stateme
nt, and we're not sure how control got there.{{Let's look at the
 above control constructs, and the^goto~statement, one at a{time
.  Discussion of the^declare~statement and Ada "blocks" is postp
oned until{we cover exception handlers.{}b[ 245B241]@ATHE "IF" B
LOCK{{@9^if~A >= B and C = A + D^then`{@=-----;{@=-----;  (block
 of code){@=-----;{@9^end if;`{{In Ada, every^if~introduces a bl
ock of code that ends with^end if;`.  There are{no exceptions; e
very^if~always has an^end if;`.  The condition is followed by{%t
hen`, and it can be any expression with a Boolean result.  The a
bove example{is valid if A, B, C, and D are suitably declared.  
Each statement in the block{of code, including the last, has a s
emicolon.  Note that^end if;~is two{reserved words, so there mus
t be at least one space between them.  All Ada{control construct
s, including^if~blocks, can be nested to any depth.{{In Pascal,^
if~is designed to execute only one statement conditionally.  If{
there's a whole block of statements to be executed conditionally
, it has to be{enclosed with "begin ... end" so it will be consi
dered as one statement.  In{Ada, however,^if~always starts a blo
ck of code, so "begin ... end" isn't{necessary.  The end of the 
block is always marked by^end if;~even if there's{just one state
ment in the block.{}b[ 246B244]@9^if A >= B and C = A + D then`{
@<^-----;`{@<^-----;`{@<^-----;`{@9^elsif G = H + P then`{@<^---
--;`{@9^elsif Q > R or S <= T then`{@<^-----;`{@<^-----;`{@9^els
e`{@<^-----;`{@9^end if;`{{The reserved words^elsif~and^else~are
 also available; note the unusual spelling{of^elsif`.  In the ab
ove example, only one of the four blocks of code will be{execute
d.  If^A >= B and C = A + D~is True, the first block of code wil
l be{executed and the remaining tests and blocks will be skipped
.  Control will{continue after the^end if;`.  If^A >= B and C = 
A + D~is False, then^G = H + P`{will be tested.  If it's True, t
he second block, and only that block, will be{executed; otherwis
e,^Q > R or S <= T~will be tested.  If that's True, the third{bl
ock will be executed; otherwise the^else~block will be executed.
  If all the{tests are False and there's no^else~block, then no 
blocks are executed.{}b[ 247B245]if A >= B and C = A + D then@6i
f A >= B and C = A + D then{@#-----;@L-----;{@#-----;@L-----;{@#
-----;@9^THESE~@,-----;{elsif G = H + P then@)^<=@$TWO@$=>~@$els
e{@#-----;@:^ARE~@-if G = H + P then{elsif Q > R or S <= T then@
%^EQUIVALENT!~@,-----;{@#-----;@Lelse{@#-----;@Oif Q > R or S <=
 T then{else@W-----;{@#-----;@R-----;{end if;@Qelse{@[-----;{@Xe
nd if;{@Uend if;{@Rend if;{{As shown,^elsif~is equivalent to^els
e~plus^if~...^end if;`.  Although the two{program segments above
 are equivalent, the one on the left is much clearer.{The exampl
e on the left doesn't require multiple^end if;`s at the bottom, 
and{the indentation emphasizes that only one of the four blocks 
of code will be{executed.{}b[ 248B246]@>D, N : Integer := 1;{@>.
..{@>if D = 0 then{@AOne;{@>elsif N/D = 1 then{@ATwo;{@>elsif D 
= 1 then{@AThree;{@>else{@AFour;{@>end if;{{In this segment of c
ode, which procedure(s) will be called?{{@21.  Procedure One wil
l be called.{@22.  Procedure Two will be called.{@23.  Procedure
 Three will be called.{@24.  Procedure Four will be called.{@25.
  Procedures Two and Three will be called.{}Please press 1, 2, 3
, 4, or 5, or B to go back.[22491250325142525253B247]@>D, N : In
teger := 1;{@>...{@>if D = 0 then{@AOne;{@=^elsif N/D = 1 then`{
@@^Two;`{@>elsif D = 1 then{@AThree;{@>else{@AFour;{@>end if;{{%
You're right!~ The first test, D = 0, is False, so the second te
st is made.{N/D = 1 is True, so Two is called.  Since only one b
lock of code is executed in{an^if~block, the remaining tests are
 not done.{}q[ 254B248Q248]@>D, N : Integer := 1;{@>...{@>if D =
 0 then{@AOne;{@>elsif N/D = 1 then{@ATwo;{@>elsif D = 1 then{@A
Three;{@>else{@AFour;{@>end if;{{No, both D and N are initialize
d to 1, so the first test, D = 0, is False and{the second test i
s made.  The block that's executed is the first block{following 
a test that's True.{}q[ 254B248Q248]@>D, N : Integer := 1;{@>...
{@>if D = 0 then{@AOne;{@>elsif N/D = 1 then{@ATwo;{@>elsif D = 
1 then{@AThree;{@>else{@AFour;{@>end if;{{No, both D and N are i
nitialized to 1, so the second test, N/D = 1, is True.{The block
 that's executed is the^first~block following a test that's True
.{Once a block is executed, no further tests in that^if~block ar
e made.  Thus,{Three isn't called even though D = 1 is True.{}q[
 254B248Q248]@>D, N : Integer := 1;{@>...{@>if D = 0 then{@AOne;
{@>elsif N/D = 1 then{@ATwo;{@>elsif D = 1 then{@AThree;{@>else{
@AFour;{@>end if;{{No, both D and N are initialized to 1, so the
 second test, N/D = 1, is True.{The block that's executed is the
 first block following a test that's True.  The{%else~block is e
xecuted only if all the tests are False.{}q[ 254B248Q248]@>D, N 
: Integer := 1;{@>...{@>if D = 0 then{@AOne;{@>elsif N/D = 1 the
n{@ATwo;{@>elsif D = 1 then{@AThree;{@>else{@AFour;{@>end if;{{N
o, although N/D = 1 and D = 1 are both True, only^one~block of c
ode in an^if`{block is executed.  The block that's executed is t
he^first~block following a{test that's True.{}q[ 254B248Q248]@A"
WHILE" LOOPS{{@>^while~I < 10^loop`{@B-----;{@B-----;{@B-----;{@
>^end loop;`{{The^while~loop first evaluates the Boolean express
ion (%I < 10~in this example).{If it's False, the block of code 
isn't executed at all, and execution continues{after the^end loo
p;`.  If it's True, the block of code is executed and then the{B
oolean condition is again evaluated.  If the condition is still 
True, the{block is executed again and the Boolean expression is 
evaluated again, and so{forth.  When the Boolean expression beco
mes False, the block of code is skipped{and execution continues 
after the^end loop;`.{}b[ 255B248]To create an "infinite loop," 
it isn't necessary to write^while True loop`.  We{simply write^l
oop`, as follows:{{@B^loop`{@F-----;{@F-----;{@F-----;{@B^end lo
op;`{{Ada doesn't have a "repeat ... until" loop, with the test 
at the bottom.{However, we can create a loop that's equivalent t
o a "repeat ... until" loop by{using an infinite loop with an^ex
it~statement, to be covered very soon.{{}b[ 256B254]@C"FOR" LOOP
S{{@(^for Ix in 1 .. 10 loop~@'^for Ix in reverse 1 .. 10 loop`{
@+^-----;~@7^-----;`{@+^-----;~@7^-----;`{@(^end loop;~@4^end lo
op;`{{Here are two sample^for~loops.  We need not declare the in
dex (%Ix~in these{examples) in the declarative region of the pro
gram; an index of a^for~loop{declares itself.  In these examples
,^Ix~comes into existence at the^for`{statement and goes out of 
existence at^end loop;~the index isn't available{outside the loo
p.  If the name^Ix~happens to be used in the declarative region,
{it's a different^Ix`.  Inside the loop^Ix~refers to the index; 
there the name^Ix`{is said to^hide~any^Ix~that might be mentione
d in the declarative region.{{The index variable may not be modi
fied.  In these examples,^Ix~may not appear{on the left side of 
an assignment statement, etc.{{In the first example above, the b
lock of statements is executed ten times, with{Ix equal to 1, th
en 2, then 3, etc., up to 10.  In the second example, Ix{starts 
at 10 and counts down to 1.  Note that the range is still writte
n{%1 .. 10`, but the keyword^reverse~precedes the range.{}b[ 257
B255]The index of a^for~loop can have any discrete type (integer
 or enumeration{type).  It can't be of type Float.  For example,
 if we write{{@#type Rainbow_Color is (Red, Orange, Yellow, Gree
n, Blue, Indigo, Violet);{@#type Traffic_Light_Color is (Red, Am
ber, Green);{{then we can write^for Ix in Red .. Blue loop`, and
 the compiler will know that{%Ix~must be of type Rainbow_Color. 
 Similarly, the type of^Ix~will be{Traffic_Light_Color if we wri
te^for IX in Red .. Amber loop`.  But the compiler{can't handle^
for Ix in Red .. Green loop~because of the ambiguity.  In this{c
ase we have to specify the type.  For example, we could write ei
ther of these:{@1^for Ix in Rainbow_Color'(Red) .. Green loop`{@
/^for Ix in Rainbow_Color range Red .. Green loop`{{Because the 
index can have any discrete type, there's no STEP clause in Ada.
{One might increment an Integer index by 2, but we couldn't add 
2 to Red.  For{uniformity, no STEP clause is available, even if 
the index type is Integer.{{Ranges may contain expressions.  If 
A, B, C, and D are Integer variables, we{can say^for I in A + B 
.. C + D loop~or^for I in reverse A + B .. C + D loop`.{In both 
cases the range is null if C + D is less than A + B.  That won't
 cause{an error; the loop is simply skipped when the range is nu
ll.{}b[ 258B256]If we have{{@#type Rainbow_Color is (Red, Orange
, Yellow, Green, Blue, Indigo, Violet);{@#J : Integer := 5;{{whi
ch one of these statements is^illegal`?{{{@81.  for I in -J .. J
 loop{{@82.  for I in J .. Violet loop{{@83.  for I in Violet ..
 Red loop{}Please press 1, 2, or 3, or B to go back.[22591260326
1B257]@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue,
 Indigo, Violet);{@#J : Integer := 5;{{@81.  for I in -J .. J lo
op{{@7^2.  for I in J .. Violet loop`{{@83.  for I in Violet .. 
Red loop{{{%You're right!~ Number 2 is illegal because the expre
ssions before and after the{"%..`" must be of the same type.{}q[
 262B258Q258]@#type Rainbow_Color is (Red, Orange, Yellow, Green
, Blue, Indigo, Violet);{@#J : Integer := 5;{{@81.  for I in -J 
.. J loop{{@82.  for I in J .. Violet loop{{@83.  for I in Viole
t .. Red loop{{{No, number 1 is legal.  The expressions on both 
sides of^..~have the same type.{%I~will be of type Integer and w
ill take 11 values, from -5 to 5.{}q[ 262B258Q258]@#type Rainbow
_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);{@#
J : Integer := 5;{{@81.  for I in -J .. J loop{{@82.  for I in J
 .. Violet loop{{@83.  for I in Violet .. Red loop{{{No, number 
3 is legal.  The expressions on both sides of^..~have the same t
ype.{The loop will be skipped because Red is less than Violet, g
iving a null range.{But the syntax is legal.  To make^I~start at
 Violet and count down to Red, we{would write{{@6for I in revers
e Red .. Violet loop{}q[ 262B258Q258]@>THE "EXIT" STATEMENT{{@)f
or I in 1 .. 10 loop@,for I in 1 .. 10 loop{@,J := 0;@:J := 0;{@
,loop@=loop{@/J := J + 1;@6J := J + 1;{@.^if A(I, J) = 0 then`{@
1^exit;~@7^exit when A(I, J) = 0;`{@.^end if;`{@,end loop;@8end 
loop;{@,B(I) := J;@7B(I) := J;{@)end loop;@8end loop;{{The state
ment^exit;~exits the innermost loop.  In the example at the left
,{%exit;~transfers control to the statement^B(I) := J;`.  Since^
exit;~is often the{only statement in an^if~block,^exit when~is a
vailable to abbreviate an^if~block{with^exit;~as its only statem
ent.  The two examples above are equivalent.{{Although^exit;~can
 appear anywhere inside any kind of loop, well-structured{Ada pr
ograms use only^exit when`, and then only as the last statement 
of an{otherwise infinite loop, as shown at the right above.  Thi
s simulates a{"repeat ... until" loop, which isn't directly avai
lable in Ada.{}b[ 263B258]@6^Outer:`{@6^for I in 1 .. 10 loop`{@
:J := 0;{@:loop{@=J := J + 1;{@<^exit Outer when A(I, J) = 0;`{@
:end loop;{@:B(I) := J;{@6^end loop Outer;`{@7K := J;{{An^exit~s
tatement can exit other than the innermost loop by^naming~the lo
op to{be exited.  In this example, the^for~loop is named^Outer`.
  A loop name is any{Ada identifier, and is followed by a colon.
  Of course,^Outer:~could have been{placed on the same line as t
he^for~statement.  When a loop is named, the^end{loop~statement 
must repeat the name of the loop.  The^exit~statement can then{n
ame the loop to be exited, as in^exit Outer;~or^exit Outer when 
A(I, J) = 0;`.{In this example, the^exit~statement transfers con
trol to the statement^K := J;`,{not to^B(I) := J;`.{{Well-struct
ured programs don't use^exit~to leave any loop except the innerm
ost{loop.  The above example isn't well-structured.{}b[ 264B262]
@@LABELS AND GOTOS{{@7Outer:{@7for I in 1 .. 10 loop{@:J := 0;{@
:loop{@=J := J + 1;{@=exit Outer when A(I, J) = 0;{@:end loop;{@
:B(I) := J;{@7end loop Outer;{@7K := J;{{Although an Ada loop na
me looks exactly like a Pascal label,^Outer:~is^not~a{label, and
 the program can't^goto Outer`.  An Ada label looks like this:{{
@B^<< Jail >>`{{The^<<~...^>>~makes the label very conspicuous, 
whether it's on the same line{as a statement or on a line by its
elf.  The program can then say^goto Jail;`.{Like all reserved wo
rds,^goto~can't contain a space.  Well-structured Ada{programs d
on't need^goto`s and labels, so their use is very rare.{}b[ 265B
263]@8I_Loop:@#for I in 1 .. 10 loop{@EJ := 0;{@8J_Loop:@&loop{@
HJ := J + 1;{@Hexit;{@Eend loop J_Loop;{@EL := J;{@Bend loop I_L
oop;{@BM := J;{{{In the program segment above, which statement w
ill be executed after^exit;`?{{@;1.  L := J;{{@;2.  M := J;{{@;3
.  for I in 1 .. 10 loop{}Please press 1, 2, or 3, or B to go ba
ck.[126622673268B264]@8I_Loop:@#for I in 1 .. 10 loop{@EJ := 0;{
@8J_Loop:@&loop{@HJ := J + 1;{@Hexit;{@Eend loop J_Loop;{@D^L :=
 J;`{@Bend loop I_Loop;{@BM := J;{{{%You're right!~ When used wi
thout a name,^exit;~leaves the innermost loop, so{the next state
ment executed is^L := J;`.{}q[ 269B265Q265]@8I_Loop:@#for I in 1
 .. 10 loop{@EJ := 0;{@8J_Loop:@&loop{@HJ := J + 1;{@Hexit;{@Een
d loop J_Loop;{@EL := J;{@Bend loop I_Loop;{@BM := J;{{{No, when
 used without a name,^exit;~leaves the^innermost~loop.{}q[ 269B2
65Q265]@8I_Loop:@#for I in 1 .. 10 loop{@EJ := 0;{@8J_Loop:@&loo
p{@HJ := J + 1;{@Hexit;{@Eend loop J_Loop;{@EL := J;{@Bend loop 
I_Loop;{@BM := J;{{{No, when used without a name,^exit;~leaves t
he innermost loop.  The next{statement executed will be the firs
t statement after the end of the innermost{loop.{}q[ 269B265Q265
]@>THE "CASE" CONSTRUCT{{%case C is~@7In this example, assume th
at^C~is of type{  ^when '*' =>~@2Character.  The expression bein
g tested (%C`),{@%^-----;~@4must have a discrete type: integer o
r{@%^-----;~@4enumeration type.  The^case~construct must{  ^when
 '#' | '$' =>~@,handle all possible values, but^when others~is{@
%^-----;~@4available.  If no action is desired for{@%^-----;~@4c
haracters not mentioned, we can write^when`{@%^-----;~@3^others 
=> null;`.  The Ada statement^null;~does{  ^when '0' .. '9' =>~@
+nothing.  Note that the vertical bar can be{@%^-----;~@4used to
 apply several cases to one block of{  ^when 'A'..'Z' | 'a'..'z'
 =>~  code, and that ranges can be used.  Here, if^C`{@%^-----;~
@4is '*', the first block is executed; if it's{@%^-----;~@4'#' o
r '$', the second block is executed.  If{@%^-----;~@4it's a digi
t, the third block is executed, and{  ^when others =>~@/if it's 
a letter (upper or lower case), the{@%^-----;~@4fourth block is 
executed.  If^C~is anything{@%^-----;~@4else, the fifth (last) b
lock of code is{%end case;~@7executed.{}b[ 270B265]case C is{@#w
hen '*' =>@8if C = '*' then{@&-----;@=-----;{@&-----;@=-----;{@#
when '#' | '$' =>@2elsif C = '#' or C = '$' then{@&-----;@=-----
;{@&-----;@=-----;{@&-----;@=-----;{@#when '0' .. '9' =>@1elsif 
C in '0' .. '9' then{@&-----;@=-----;{@#when 'A'..'Z' | 'a'..'z'
 =>@(elsif C in 'A'..'Z' or C in 'a'..'z' then{@&-----;@=-----;{
@&-----;@=-----;{@&-----;@=-----;{@#when others =>@5else{@&-----
;@=-----;{@&-----;@=-----;{end case;@=end if;{{The two examples 
above are equivalent.  In both cases only one block of code{will
 be executed.  By the way, the symbol^=>~is read "choose" (or so
metimes{"arrow"), and may not contain a space.{}b[ 271B269]If we
 have{{@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue
, Indigo, Violet);{@#type Traffic_Light_Color is (Red, Amber, Gr
een);{@#F : Float range 0.0 .. 2.0;{@#R : Rainbow_Color;{@#T : T
raffic_Light_Color;{{then which^one~of the following program seg
ments is^legal`?{{@,1:@<2:@93:{{ case R is@7case F is@4case T is
{@$when Red | Green =>@-when 0.0 .. 1.0 =>@+when Red =>{@'-----;
@:-----;@7-----;{@$when Blue .. Violet =>@*when others =>@/when 
others =>{@'-----;@:-----;@7-----;{ end case;@7end case;@4end ca
se;{{}Please press 1, 2, or 3, or B to go back.[327212732274B270
]@#type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indi
go, Violet);{@#type Traffic_Light_Color is (Red, Amber, Green);{
@#F : Float range 0.0 .. 2.0;{@#R : Rainbow_Color;{@#T : Traffic
_Light_Color;{{@,1:@<2:@8^3:`{{ case R is@7case F is@3^case T is
`{@$when Red | Green =>@-when 0.0 .. 1.0 =>@*^when Red =>`{@'---
--;@:-----;@6^-----;`{@$when Blue .. Violet =>@*when others =>@.
^when others =>`{@'-----;@:-----;@6^-----;`{ end case;@7end case
;@3^end case;`{{%You're right!~ Number 1 is illegal because it d
oesn't account for all possible{values of^R`, and number 2 is il
legal because^F~doesn't have a discrete type.{}q[ 275B271Q271]@#
type Rainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo,
 Violet);{@#type Traffic_Light_Color is (Red, Amber, Green);{@#F
 : Float range 0.0 .. 2.0;{@#R : Rainbow_Color;{@#T : Traffic_Li
ght_Color;{{@,1:@<2:@93:{{ case R is@7case F is@4case T is{@$whe
n Red | Green =>@-when 0.0 .. 1.0 =>@+when Red =>{@'-----;@:----
-;@7-----;{@$when Blue .. Violet =>@*when others =>@/when others
 =>{@'-----;@:-----;@7-----;{ end case;@7end case;@4end case;{{N
o, number 1 is illegal because it doesn't account for all the po
ssible values{of^R`.{}q[ 275B271Q271]@#type Rainbow_Color is (Re
d, Orange, Yellow, Green, Blue, Indigo, Violet);{@#type Traffic_
Light_Color is (Red, Amber, Green);{@#F : Float range 0.0 .. 2.0
;{@#R : Rainbow_Color;{@#T : Traffic_Light_Color;{{@,1:@<2:@93:{
{ case R is@7case F is@4case T is{@$when Red | Green =>@-when 0.
0 .. 1.0 =>@+when Red =>{@'-----;@:-----;@7-----;{@$when Blue ..
 Violet =>@*when others =>@/when others =>{@'-----;@:-----;@7---
--;{ end case;@7end case;@4end case;{{No, number 2 is illegal be
cause^F~doesn't have a discrete type.{}q[ 275B271Q271]@:BRIEF OV
ERVIEW OF FUNCTIONS{{@.procedure Funct_Demo is{@1X : Float := 1.
2;{@1Y : Float;{@0^function Twice(Dummy : in Float) return Float
 is`{@3^Answer : Float;`{@0^begin`{@3^Answer := Dummy * 2.0;`{@3
^return Answer;`{@0^end Twice;`{@.begin{@1Y := Twice(X);{@.end F
unct_Demo;{{Let's look briefly at functions so we can do Outside
 Assignment 2; later, we'll{cover functions and procedures in de
tail.  Here procedure Funct_Demo locally{declares a function Twi
ce.  Twice can be called only from within Funct_Demo:{%Y := Twic
e(X);`.  The function specification gives the name (Dummy), mode
 (in),{and type (Float) of any formal parameters, or "dummy argu
ments."  For{functions, the mode of all parameters must be^in`, 
never^out~or^in out`.  The{function specification also gives the
 type being^return`ed, in this case Float.{}b[ 276B271]@.procedu
re Funct_Demo is{@1X : Float := 1.2;{@1Y : Float;{@1function Twi
ce(Dummy : in Float) return Float is{@4Answer : Float;{@1begin{@
4Answer := Dummy * 2.0;{@3^return Answer;`{@1end Twice;{@.begin{
@1Y := Twice(X);{@.end Funct_Demo;{{The function body must have^
return~followed by an expression of the right type.{In well-stru
ctured functions, this is the last statement before^end`.  We do
n't{return a value by placing the name of the function in an ass
ignment statement,{as in Fortran.  Of course, function Twice cou
ld be written more simply as{{@0function Twice(Dummy : in Float)
 return Float is{@0begin{@3return Dummy * 2.0;{@0end Twice;{}b[ 
277B275]@)procedure Funct_Demo is{@,X : Float := 1.2;{@,Y : Floa
t;{@+^function Twice(Dummy : in Float) return Float is separate;
`{@)begin{@,Y := Twice(X);{@)end Funct_Demo;{{@(^separate (Funct
_Demo)`{@(^function Twice(Dummy : in Float) return Float is`{@)b
egin{@,return Dummy * 2.0;{@)end Twice;{{The function can be pla
ced in a separate file and compiled later.  Here the{calling pro
gram can be compiled once, and later the function can be edited 
and{recompiled as often as desired. ^Twice~is still local to^Fun
ct_Demo`.  The{phrase^separate (Funct_Demo)~tells Ada that this 
subprogram is part of the{previously compiled unit^Funct_Demo`. 
 It's as if the function were cut out and{"pasted" where the cal
ling program says^function Twice~...^is separate;`.  Ada{can sti
ll compile the call^Y := Twice(X);~because the calling program c
ontains{the specification of the function.{}b[ 278B276]@.OUTSIDE
 ASSIGNMENT 2 - EXERCISE IN ENUMERATION TYPES{{Separate compilat
ion is the basis of our next Outside Assignment.  The function{w
e want you to write is completely specified by these two lines o
f Ada:{{@%^type Triangle is (Equilateral, Isosceles, Scalene, No
t_a_Triangle);`{@%^function Tritype(Len1, Len2, Len3 : in Intege
r) return Triangle;`{{From these two lines, it's obvious that yo
ur function must decide whether three{integers, representing the
 lengths of the sides of a triangle, in fact{represent an equila
teral triangle, an isosceles triangle, a scalene triangle,{or no
 triangle at all.  (An equilateral triangle has three equal side
s; an{isosceles triangle has only two equal sides.  A scalene tr
iangle has sides of{three different lengths, and the integers -1
, 0, 5 represent no triangle.){{A test driver for your function 
is already written, and is in the file{%TRITEST.ADA`.  A listing
 starts on page 10 of your printed course notes.  You{need not u
nderstand the test driver.  It's sufficient to know that if your
{function passes all the tests, the message "Congratulations, yo
u completed the{assignment!" is shown.  For any failed tests, th
e test driver displays the test{case, the answer from your funct
ion, and the correct answer.  This will help{you in debugging yo
ur function.{}b[ 279B277]The test driver, which is the main prog
ram, contains these declarations:{{  type Triangle is (Equilater
al, Isosceles, Scalene, Not_a_Triangle);{  function Tritype(Len1
, Len2, Len3 : in Integer) return Triangle is separate;{{This al
lows you to edit and recompile your function as often as you lik
e,{without having to recompile the test driver.  Since type^Tria
ngle~is defined in{the calling program, you should^not~define it
 in your function.{{To get you started, a dummy solution is give
n in^TRITYPE.DUM`.  You can copy it{and edit the copy to become 
your real solution.  It looks like this:{{@'-- Dummy solution fo
r Outside Assignment 2{@'-- Edit to become your real solution.{@
'separate (Tritest){@'function Tritype(Len1, Len2, Len3 : in Int
eger) return Triangle is{@'begin{@*return Not_a_Triangle;{@'end 
Tritype;{{If you wish, you may compile this dummy solution befor
e editing it.  Then{you'll see what error messages from the test
 driver look like.{}b[ 280B278]@'-- Dummy solution for Outside A
ssignment 2{@'-- Edit to become your real solution.{@&^separate 
(Tritest)`{@&^function Tritype(Len1, Len2, Len3 : in Integer) re
turn Triangle is`{@&^begin`{@*return Not_a_Triangle;{@&^end Trit
ype;`{{When you do edit the function, you'll probably want to re
move or change the{first two comment lines.  Don't change the li
nes^highlighted~above.  You may{want to create a new variable of
 type Triangle, and return that variable{instead of the constant
 Not_a_Triangle at the end of your function:{{@'separate (Trites
t){@'function Tritype(Len1, Len2, Len3 : in Integer) return Tria
ngle is{@)^Answer : Triangle;`{@'begin{@*if ... end if;{@)^retur
n Answer;`{@'end Tritype;{{However, that's not the only way to s
olve the problem, just a suggestion.{}b[ 281B279]Here are the st
eps to follow for Outside Assignment 2.  They're also in your{pr
inted course notes on page 12:{{1.  Compile the test driver TRIT
EST.ADA.  Also, make a copy of the dummy{@$solution by typing^CO
PY TRITYPE.DUM TRITYPE.ADA`.  You need do this step{@$only once.
{{2.  Edit TRITYPE.ADA to become your real solution.  You may sk
ip this step the{@$first time through, to see error messages fro
m the test driver.{{3.  Compile your solution TRITYPE.ADA.  If t
he compiler finds errors, go back{@$to step 2.{{4.  Link with th
e name of the main program Tritest.  Then execute.  If the test{
@$driver displays error messages, go back to step 2.{{5.  When t
he message "Congratulations, you completed the assignment!" is{@
$displayed, you'll have a chance to compare your solution with o
urs.{}b[ 282B280]Remember that a function can't change the value
s of its parameters (in this{case, Len1, Len2, and Len3), becaus
e function parameters are always of mode^in`.{{This assignment s
hould be a simple exercise in enumeration types and the{control 
constructs.  Our solution easily fits on one screen.  If you fin
d your{solution getting long and difficult, you should probably 
think through the{problem again.  See if there's a simple way to
 test for the four possible{answers.{{Please type X to exit^ADA-
TUTR~temporarily, and try Outside Assignment 2.  Work{at your ow
n pace; there's no deadline.  Good luck!{}Please type X to exit,
 a space to go on, or B to go back.[ 283B281]@-^Congratulations 
on Completing Outside Assignment 2!`{{Our solution is in^TRITYPE
.ANS`.  It looks like this:{{-- Our solution to Outside Assignme
nt 2:{separate (Tritest){function Tritype(Len1, Len2, Len3 : in 
Integer) return Triangle is{@#Answer : Triangle;{begin{@#if Len1
 + Len2 <= Len3  or Len1 + Len3 <= Len2  or Len2 + Len3 <= Len1 
 then{@&Answer := Not_a_Triangle;{@#elsif  Len1 = Len2  and  Len
2 = Len3  then{@&Answer := Equilateral;{@#elsif  Len1 = Len2  or
  Len2 = Len3  or  Len1 = Len3  then{@&Answer := Isosceles;{@#el
se{@&Answer := Scalene;{@#end if;{@#return Answer;{end Tritype;{
}b[ 284B282]Note that it isn't necessary to include tests for si
des <= 0, because if any{side <= 0, one of the three tests in th
e following would have to catch that:{{if  Len1 + Len2 <= Len3  
or  Len1 + Len3 <= Len2  or  Len2 + Len3 <= Len1  then{@#Answer 
:= Not_a_Triangle;{{However, most students include tests for sid
es <= 0, so if you did, don't feel{bad.  It doesn't do any harm.
{{You must have realized by now that it's impossible to draw a t
riangle with{sides 1, 2, and 3.  The sum of any two sides must b
e greater than the third.{{There are many correct ways to solve 
this problem.  Some students make copies{of the three sides and 
sort them first.  Some initialize Answer to Scalene in{the decla
rative region and omit the code{{@=else{@@Answer := Scalene;{{If
 you saw the message "Congratulations, you completed the assignm
ent!" you may{consider your solution correct.  Let's go on to di
scuss Records and Arrays.{}b[ 285B283]@;^ADA-TUTR COURSE OUTLINE
`{{{@#Introduction@=Recursion and Assignment 4{{@#The Format of 
an Ada Program@-Subprograms and Packages{{@#Generic Instantiatio
n and@0Access Types, User Defined Types,{@&Assignment 1@=and Der
ived Types{{@#Simple Declarations and Simple@+Exceptions, Text_I
O, and{@&Attributes@?Assignment 5{{@#Operators, Control Construc
ts, and@'Generics, Tasking, and Assignment 6{@&Assignment 2{@LMo
re Records and Types{%>  RECORDS, ARRAYS, AND ASSIGNMENT 3`{@LAd
vanced Topics{}b[ 286B284]@DRECORDS{{A^record~lets us group seve
ral declarations together and refer to them as one:{{@%type Mont
h_Type is (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{@%s
ubtype Day_Subtype is Integer range 1 .. 31;{@$^type Date is`{@'
^record`{@*^Day@#: Day_Subtype;~  -- Naturally, Day_Subtype and{
@*^Month : Month_Type;~@#-- Month_Type must be defined{@*^Year  
: Integer;~@&-- before type Date is defined.{@'^end record;`{@$^
USA : Date;`{{In this example,^USA~has three parts (called "fiel
ds"): ^USA.Day`,^USA.Month`,{and^USA.Year`.  The fields of a rec
ord can be of any type, including other{records.  Here^USA.Day~i
s of^type~Integer,^USA.Month~is of type Month_Type, and{%USA.Yea
r~is of type Integer.  The parts of^USA~may be referenced separa
tely:{{@>^USA.Day@#:= 4;`{@>^USA.Month := Jul;`{@>^USA.Year  := 
1776;`{}b[ 287B285]@%type Month_Type is (Jan,Feb,Mar,Apr,May,Jun
,Jul,Aug,Sep,Oct,Nov,Dec);{@%subtype Day_Subtype is Integer rang
e 1 .. 31;{@$^type Date is`{@'^record`{@*^Day@#: Day_Subtype;`{@
*^Month : Month_Type;`{@*^Year  : Integer;`{@'^end record;`{@$^U
SA : Date;`{{However,^USA~can also be referenced as one object. 
 For example, we could have{assigned all three fields in one sta
tement: ^USA := (4, Jul, 1776);`.  Here the{object on the left i
s of type Date, and the object on the right is called an{%aggreg
ate`.  The aggregate fits the type Date because it contains an I
nteger, a{Month_Type, and another Integer.  This aggregate is sa
id to use^positional`{notation because its three parts appear in
 the same order as the three parts of{the record definition:  fi
rst Day, then Month, then Year.{{We can specify the parts of an 
aggregate in any order if we use^named~notation:{%USA := (Month 
=> Jul, Day => 4, Year => 1776);`.  (The symbol^=>~is read "arro
w"{and may not contain a space.)  Using named notation often imp
roves program{readability, especially if the names of the fields
 are well chosen.{}b[ 288B286]@%type Month_Type is (Jan,Feb,Mar,
Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{@%subtype Day_Subtype is I
nteger range 1 .. 31;{@$^type Date is`{@'^record`{@*^Day@#: Day_
Subtype;`{@*^Month : Month_Type;`{@*^Year  : Integer;`{@'^end re
cord;`{@$^USA : Date;`{{We can switch from positional to named n
otation in an aggregate.  But once we{use named notation, the co
mpiler loses track of position, so we can't switch{back to posit
ional.  For example, the following is^legal`:{{@3^USA := (4, Yea
r => 1776, Month => Jul);`{{But the following is^illegal~because
 positional notation can't follow named:{{@3USA := (4, Year => 1
776, Jul); -- illegal{{Record discriminants and record variants 
will be discussed in the section on{More Records and Types, as w
ill Ada 9X Tagged Records.{}b[ 289B287]@$procedure Record_Exerci
se is{@'type Month_Type is (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,
Oct,Nov,Dec);{@'subtype Day_Subtype is Integer range 1 .. 31;{@'
type Date is{@*record{@-Day@#: Day_Subtype;{@-Month : Month_Type
;{@-Year  : Integer;{@*end record;{@'D1, D2, D3 : Date; ^-- 1`{@
$begin{@'D1 := (Month => Jan, Day => 22, Year => 1983); ^-- 2`{@
'D2.Day := 22;{@'D2.Month := 1; ^-- 3`{@'D2.Year := 1983;{@'D3 :
= D2; ^-- 4`{@$end Record_Exercise;{{Which commented line in the
 above program is^illegal`?{}Please press 1, 2, 3, or 4, or B to
 go back.[3290129122924293B288]@&^D2.Month := 1;  -- 3`{{%You're
 right!~ This statement is illegal, because the types are mixed.
{%D2.Month~is of type Month_Type, and^1~is an integer.{}q[ 294B2
89Q289]@'D1, D2, D3 : Date;  -- 1{{No, this statement is legal, 
because several objects may be declared in one{statement, if the
 objects are separated by commas.{}q[ 294B289Q289]@'D1 := (Month
 => Jan, Day => 22, Year => 1983);  -- 2{{No, this statement is 
legal, because the fields within the aggregate may appear{in any
 order when named notation is used.{}q[ 294B289Q289]@'D3 := D2; 
 -- 4{{No, this statement is legal, because^D3~and^D2~both have 
the same type:^Date`.{An entire record can be assigned with one 
statement.{}q[ 294B289Q289]@EARRAYS{{To declare an array in Ada,
 we specify the^type and range of the subscript`,{followed by th
e^type of the elements~of the array.  The subscript can have any
{discrete type (integer or enumeration), and the elements of the
 array can be of{any type at all, including records and other ar
rays.  There are three ways to{declare an array in Ada.  Here ar
e three examples of the most direct, but least{flexible, way (ty
pes Rainbow_Color and Date must be defined earlier):{{%A : array
(Rainbow_Color range Orange .. Blue) of Date;`{@#-- A four-eleme
nt array, each element of which is a record with three parts.{@#
-- The allowable subscripts are Orange, Yellow, Green, and Blue.
  Here{@#-- A(Yellow) is of type Date, and A(Yellow).Year is of 
type Integer.{%B : array(Integer range -10 .. 10) of Integer;`{@
#-- An array of 21 Integers, with Integer subscripts.{%C : array
(0 .. 30) of Float;`{@#-- Here (0 .. 30) is understood to mean (
Integer range 0 .. 30), and we have{@#-- an array of 31 Floats, 
with Integer subscripts.`{{A subscript can be an expression; if 
I is an Integer, we can write^C(2*I)`.  If{a subscript is out-of
-range (for example,^A(Red)~or^C(-32)`), the program will{raise 
a Constraint_Error.{}b[ 295B289]This direct method of declaring 
arrays is usually used to create single arrays{for table lookup,
 etc., where there's no need to have several arrays of the{same 
type.  A better way to declare an array is to specify a type nam
e for the{array itself.  Then several objects can be declared to
 have that same type.{For example,{{@1^type Vector100 is array(1
 .. 100) of Float;`{@1^type Vector300 is array(1 .. 300) of Floa
t;`{@1^D, E, F : Vector100;`{@1^G, H@$: Vector300;`{{Here D, E, 
and F are all of type^Vector100`, so we can write^D := E;~ and a
ssign{the entire array with one statement.  Similarly, we can wr
ite^G := H;`, but not{%G := F;`.{{The example above takes four s
tatements.  An even better way to declare arrays{is to leave the
 range of the subscript unspecified with the^box~symbol,^<>`,{sp
ecifying the range when declaring the objects.  For example,{{@/
^type Vector is array(Integer range <>) of Float;`{@/^D, E, F : 
Vector(1 .. 100);`{@/^G, H@$: Vector(1 .. 300);`{}b[ 296B294]The
re are two errors to avoid when declaring arrays in this way.  O
ne is to{declare a type with the box symbol for the range of the
 subscript, and then{fail to specify the range when declaring an
 object (other than a constant):{{@,^type Vector is array(Intege
r range <>) of Float;`{@,^D1 : Vector := (2.3, 4.5, 4.0); -- ill
egal in Ada 83.`{@-D2 :^constant~Vector := (2.3, 4.5, 4.0);^-- l
egal`{{This error is called^unconstrained array`.  Unconstrained
 arrays are legal in{formal parameters ("dummy arguments") of pr
ocedures and functions, and a{function can^return~an unconstrain
ed array type.  (We'll learn about these{things later.)  But an 
unconstrained array is illegal when declaring a{variable, becaus
e the compiler needs to know the range of the subscript.{{The se
cond example above is illegal in Ada 83, but it is legal in Ada 
9X,{because the Ada 9X compiler translates it to{{@3^D1 : Vector
(1 .. 3) := (2.3, 4.5, 4.0);`{}b[ 297B295]@3^D1 : Vector(1 .. 3)
 := (2.3, 4.5, 4.0);`{{In Ada 83, we have to supply the^(1 .. 3)
~ourselves.  Either version of Ada{will report an unconstrained 
array error if we write{{@;^D1 : Vector; -- illegal`{{The other 
error is to specify the range of the subscript twice: once when{
declaring the type and once when declaring the object:{{@1^type 
Vector100 is array(1 .. 100) of Float;`{@1^D2 : Vector100(1 .. 1
00);  -- illegal`{{Even if the two ranges agree, this is illegal
 and is called^doubly constrained{array`.{}b[ 298B296]Arrays may
 be initialized and assigned with aggregates, and both positiona
l and{named notation may be used.  For example, arrays^A~and^B~a
re equal here:{{^type Vector5 is array(1 .. 5) of Float;`{^A : c
onstant Vector5 := (2.0, 4.0, 8.0, 16.0, 32.0);`{^B : constant V
ector5 := (1 => 2.0, 2 => 4.0, 3 => 8.0, 4 => 16.0, 5 => 32.0);`
{{The aggregate must fill the whole array, but the reserved word
^others~is{available.  Here's an array of 500 Float variables, a
ll initialized to 0.0:{{@1^type Vector500 is array(1 .. 500) of 
Float;`{@1^V1 : Vector500 := (others => 0.0);`{{If^others~follow
s named notation, it's best to qualify the aggregate with the{ty
pe name.  Here W(10) = 1.3, W(15) = -30.7, and the rest of the a
rray is 0.0:{{@$^W : Vector500 := Vector500'(10 => 1.3,  15 => -
30.7,  others => 0.0);`{{Sometimes we^must~qualify an aggregate 
when^others~is used with named notation;{at other times it's opt
ional.  The rules (LRM section 4.3.2, paragraphs 4-8){are very c
omplicated.  It's easiest always to qualify an aggregate when^ot
hers`{follows named notation, as shown above.{}b[ 299B297]In arr
ay aggregates, multiple choices can be denoted with the vertical
 bar (%|`),{shift-backslash on your keyboard.  In this array, th
e elements with odd{subscripts are True, while the elements with
 even subscripts are False:{{@)^type Decade is array(1 .. 10) of
 Boolean;`{@)^D1 : Decade;`{@*...{@)^D1 := Decade'(1 | 3 | 5 | 7
 | 9 => True,  others => False);`{{Here we assigned to D1 with a
n executable statement for variety; we could also{have initializ
ed D1 in the declarative region with the same aggregate.  Some{p
eople read the vertical bar as "and," others as "or."  One can s
ay, "Elements{1,^and~3, and 5, and 7, and 9 are True," or one ca
n say, "If the subscript is{1,^or~3, or 5, or 7, or 9, the array
 element is True."{{Array aggregates may also contain ranges.  I
n this array, elements 1 and 6 - 10{are 1; the rest are 0.  Arra
ys^L1~and^L2~are equal:{{@(^type List15 is array(1 .. 15) of Int
eger;`{@(^L1 : List15 := List15'(1 | 6 .. 10 => 1,  others => 0)
;`{@(^L2 : List15 := (1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 
0);`{}b[ 300B298]%with Text_IO; use Text_IO;{procedure Array_Qui
z is`{  ^package My_Int_IO is new Integer_IO(Integer); use My_In
t_IO;`{  ^subtype Capital_Letter is Character range 'A' .. 'Z';{
  ^type Set_Of_Letters is array(Capital_Letter) of Boolean;`{  ^
Vowels : Set_Of_Letters :=`{@'^Set_Of_Letters'('A' | 'E' | 'I' |
 'O' | 'U' => True,  others => False);`{  ^Letter : Capital_Lett
er;{begin`{  ^Letter := 'E';`{  ^Put(Boolean'Pos(Vowels(Letter))
);{end Array_Quiz;`{{@7What will this program display?{{@71.  Th
e program will display 1.{{@72.  The program will display 2.{{@7
3.  The program will display TRUE.{{@74.  The program will displ
ay E.{}Please press 1, 2, 3, or 4, or B to go back.[130123023303
4304B299]%with Text_IO; use Text_IO;{procedure Array_Quiz is`{  
^package My_Int_IO is new Integer_IO(Integer); use My_Int_IO;`{ 
 ^subtype Capital_Letter is Character range 'A' .. 'Z';`{  ^type
 Set_Of_Letters is array(Capital_Letter) of Boolean;`{  ^Vowels 
: Set_Of_Letters :=`{@'^Set_Of_Letters'('A' | 'E' | 'I' | 'O' | 
'U' => True,  others => False);`{  ^Letter : Capital_Letter;{beg
in`{  ^Letter := 'E';`{  ^Put(Boolean'Pos(Vowels(Letter)));{end 
Array_Quiz;`{{{%You're right!~ Vowels has 26 elements, with subs
cripts 'A' through 'Z'.{Vowels(Letter) is Vowels('E'), which is 
True, and since Ada defines{{@9type Boolean is (False, True);{{a
nd the positions are numbered starting from 0, Boolean'Pos(True)
 is 1.{}q[ 305B300Q300]with Text_IO; use Text_IO;{procedure Arra
y_Quiz is{@#package My_Int_IO is new Integer_IO(Integer); use My
_Int_IO;{@#subtype Capital_Letter is Character range 'A' .. 'Z';
{@#type Set_Of_Letters is array(Capital_Letter) of Boolean;{@#Vo
wels : Set_Of_Letters :={@(Set_Of_Letters'('A' | 'E' | 'I' | 'O'
 | 'U' => True,  others => False);{@#Letter : Capital_Letter;{be
gin{@#Letter := 'E';{@#Put(Boolean'Pos(Vowels(Letter)));{end Arr
ay_Quiz;{{{No.  Recall that Ada defines{{@9type Boolean is (Fals
e, True);{{and that the positions are numbered starting with 0 f
or the^Pos~attribute.{}q[ 305B300Q300]with Text_IO; use Text_IO;
{procedure Array_Quiz is{@#package My_Int_IO is new Integer_IO(I
nteger); use My_Int_IO;{@#subtype Capital_Letter is Character ra
nge 'A' .. 'Z';{@#type Set_Of_Letters is array(Capital_Letter) o
f Boolean;{@#Vowels : Set_Of_Letters :={@(Set_Of_Letters'('A' | 
'E' | 'I' | 'O' | 'U' => True,  others => False);{@#Letter : Cap
ital_Letter;{begin{@#Letter := 'E';{@#Put(Boolean'Pos(Vowels(Let
ter)));{end Array_Quiz;{{{No.  Indeed Vowels(Letter) is Vowels('
E'), which is True, but the program takes{the Boolean'Pos of Vow
els(Letter).  Recall that the attribute^Pos~converts from{a disc
rete type (in this case, Boolean) to an integer.{}q[ 305B300Q300
]with Text_IO; use Text_IO;{procedure Array_Quiz is{@#package My
_Int_IO is new Integer_IO(Integer); use My_Int_IO;{@#subtype Cap
ital_Letter is Character range 'A' .. 'Z';{@#type Set_Of_Letters
 is array(Capital_Letter) of Boolean;{@#Vowels : Set_Of_Letters 
:={@(Set_Of_Letters'('A' | 'E' | 'I' | 'O' | 'U' => True,  other
s => False);{@#Letter : Capital_Letter;{begin{@#Letter := 'E';{@
#Put(Boolean'Pos(Vowels(Letter)));{end Array_Quiz;{{{No.  While 
Letter is 'E', and Letter appears inside the Put statement, the{
parameter of Put is the Boolean'Pos of one element of array Vowe
ls{(specifically, the element whose subscript is 'E').  Recall t
hat the^Pos`{attribute always returns an integer.{}q[ 305B300Q30
0]In an array declaration or an array type declaration, we may t
otally omit the{range of the subscript (not even supplying a box
), if the type or subtype of{the subscript has a reasonable numb
er of possible values.  (We did that in the{declaration of type 
Set_Of_Letters in the last question.)  For example, in{{@#type R
ainbow_Color is (Red, Orange, Yellow, Green, Blue, Indigo, Viole
t);{  ^R : array(Rainbow_Color) of Float;`{{we have an array of 
seven Floats, because there are seven possible values of{type Ra
inbow_Color.  Similarly,{{@7^V : array(Character) of Boolean;`{{
creates an array of 128 Booleans in Ada 83 and 256 Booleans in A
da 9X.{However,^J : array(Integer) of Float;~is an attempt to de
clare a very large{array indeed!  In a case like this, we can us
e a subtype in the subscript{declaration:{{@1subtype Day_Subtype
 is Integer range 1 .. 31;{@0^J : array(Day_Subtype) of Float;`{
{This creates an array of 31 Floats.{}b[ 306B300]The attributes^
First~and^Last`, which we've seen with discrete types, can also{
be used with array types and with the array names themselves.  F
or example,{{@0^type My_Vector is array(30 .. 33) of Integer;`{@
0^Mv : My_Vector;`{@1...{@0^Mv(30) := 1000;`{@0^Mv(31) := 20;`{@
0^Mv(32) := -70;`{@0^Mv(33) := -500;`{{Here^Mv'First~and^My_Vect
or'First~are both 30. ^Mv'Last~and^My_Vector'Last~are{both 33.  
Note that^First~and^Last~refer to the subscripts, not to the val
ues{of the array elements.  Thus^Mv'First~is^not~1000.  To obtai
n the value of the{first element, we would use^Mv'First~as a^sub
script`. ^Mv(Mv'First)~is 1000.{{The attribute^Range~is an abbre
viation for^First .. Last`.  It can be used only{with array type
s and array names, not with discrete types.  Thus^Mv'Range~and{%
My_Vector'Range~both mean^30 .. 33`.  We can't write^Integer'Ran
ge`, even though{we can write^Integer'First~and^Integer'Last`.  
The attribute^Length~is also{available: ^Mv'Length~and^My_Vector
'Length~are both 4.{}b[ 307B305]@<MULTIDIMENSIONAL ARRAYS{{Ada a
rrays may have any number of dimensions, and the subscripts may 
be of{different discrete types.  For example, assuming Rainbow_C
olor, Month_Type, and{Date have already been defined, we can wri
te{{@$^X : array(Integer range -10 .. -1, Rainbow_Color range Or
ange .. Blue,`{@.^Month_Type range Feb .. Jun) of Date;`{{Here t
he first subscript is of type Integer and has 10 possible values
, the{second subscript is of type Rainbow_Color and has four pos
sible values, and the{third subscript has type Month_Type with f
ive possible values.  Thus we have{a three-dimensional array of 
10 * 4 * 5 = 200 Dates.  One element of the array{might be^X(-5,
 Green, Apr)`; one field of that element might be{%X(-5, Green, 
Apr).Year`.  The array in this example probably has no use, othe
r{than demonstrating that multiple subscripts need not have the 
same type.{{If one subscript of a multidimensional array type is
 constrained, they must all{be constrained.  We can't write{{@$t
ype Rectangle is array(1 .. 5, Integer range <>) of Float;  -- i
llegal{}b[ 308B306]Multidimensional arrays are initialized or as
signed with^nested aggregates`.  We{can create a two-dimensional
 array of Floats, initializing all 50 elements to{1.0, with^Mat 
: array(0 .. 9, 1 .. 5) of Float := (others => (others => 1.0));
`.{{Here X is a 10-by-10 array of Integers.  All elements are 0,
 except X(4, 5),{which is 1.  We qualify the aggregate because^o
thers~follows named notation:{{@%^type Square10 is array (1 .. 1
0, 1 .. 10) of Integer;`{@%^X : Square10 := Square10'(@%4@%=>@#(
5 => 1, others => 0),`{@B^others  =>@'(others => 0)@');`{{We ini
tialize or assign an^array of arrays~with nested aggregates, the
 same as{a multidimensional array.  However, we reference a sing
le element differently:{{ ^type Square10 is array(1 .. 10, 1 .. 
10) of Integer;`{ ^type Row10@$is array(1 .. 10) of Integer;`{ ^
type Mat10@$is array(1 .. 10) of ROW10;`{ ^S : Square10 := (othe
rs => (others => 0)); -- S is a two-dimensional array.`{ ^M : Ma
t10@$:= (others => (others => 0)); -- M is an array of arrays.`{
  ...{ ^S(4, 5) := 1; -- a single element of a two-dimensional a
rray`{ ^M(4)(5) := 1; -- a single element of an array of arrays`
{}b[ 309B307]The "short circuit" forms can prevent us from using
 array subscripts that are{out of range.  For example, if we wri
te{{@4A : array(1 .. 10) of Float;{@4I : Integer;{@4...{@4if^I i
n A'Range and then A(I) = 0.0~then{@7-----;{@7-----;  (block of 
code){@7-----;{@4end if;{{then we know the program won't try to 
evaluate^A(I)~when I is outside the range{1 to 10.{}b[ 310B308]W
hich one of these is^illegal`?{{{@*1.@$subtype Day_Subtype is In
teger range 1 .. 31;{@0type Group is array(Day_Subtype) of Float
;{@0Gr : Group;{@0...{@0Gr(3) := 0.0;{{{@*2.@$type List is array
(1 .. 10) of Integer;{@0type Page is array(1 .. 20) of List;{@0P
g : Page;{@0...{@0Pg(5)(10) := 0;{{{@*3.@$type Row is array (Int
eger range <>) of Integer;{@0R1 : Row;{@0...{@0R1(1) := 0;{}Plea
se press 1, 2, or 3, or B to go back.[331113122313B309]@)^3.@$ty
pe Row is array (Integer range <>) of Integer;`{@/^R1 : Row;`{@/
^...`{@/^R1(1) := 0;`{{%You're right!~ The above is illegal beca
use the range of the subscript must be{specified, either in the 
first line,^(Integer range 1 .. 10)`, or in the{second,^R1 : Row
(1 .. 10);`, but not both.  This is the^unconstrained array`{err
or mentioned earlier.{}q[ 314B310Q310]@*1.@$subtype Day_Subtype 
is Integer range 1 .. 31;{@0type Group is array(Day_Subtype) of 
Float;{@0Gr : Group;{@0...{@0Gr(3) := 0.0;{{No, the above is leg
al.  Gr is an array of 31 elements.  The subscript ranges{from 1
 to 31, and each element has type Float.  Therefore, Gr(3) has t
ype{Float, and the assignment is legal.{}q[ 314B310Q310]@*2.@$ty
pe List is array(1 .. 10) of Integer;{@0type Page is array(1 .. 
20) of List;{@0Pg : Page;{@0...{@0Pg(5)(10) := 0;{{No, the above
 is legal.  The elements of an array can be of any type, includi
ng{other arrays.  Here Pg has type Page, which is an array of Li
st.  Therefore{Pg(5) has type List (which is an array of Integer
), and Pg(5)(10) has type{Integer.  Thus the assignment is legal
.  The notation Pg(5)(10) may seem{strange, but it's correct Ada
 when we have an array of arrays.{}q[ 314B310Q310]@DSTRINGS{{The
re's one very important array type declaration built into the Ad
a language.{As with types Boolean and Character, and subtypes Po
sitive and Natural, this{definition comes with Ada and shouldn't
 be repeated in our programs:{{@,^type String is array(Positive 
range <>) of Character;`{{Thus we can declare, for example,^S : 
String(1 .. 5);`.  We can't simply write{%S : String;~or^S : Str
ing := "Hello";~because we can't declare unconstrained{array obj
ects.  (We can declare^S : constant String := "Hello";~and in Ad
a 9X,{we may write^S : String := "Hello";~because the compiler w
ill translate this to{%S : String(1 .. 5) := "Hello";`).  Note t
hat String isn't a special type in Ada,{it's just an array of Ch
aracters.  Everything we learned about arrays applies{to Strings
.  For example, we can assign to S using the same syntax that we
 use{when assigning to an array of any other type.  If we write^
S : String(1 .. 5);`{we can write:{{@7^S := ('H', 'e', 'l', 'l',
 'o');`{{}b[ 315B310]However, this notation is clumsy, so Ada al
lows us to abbreviate an array of{Character constants using the 
double quote.  Thus^S := "Hello";~is equivalent{to the statement
 above.  If a quotation mark appears inside the string, it must{
be doubled.  Thus^Text_IO.Put_Line("a ""big"" man");~will displa
y^a "big" man`.{{It may seem disappointing that Ada Strings have
 fixed length, and that we can't{declare a variable^S : String;`
.  Later we'll learn how to define our own type{Text to get arou
nd this restriction and simulate variable-length Strings.{{Also,
 Ada 9X comes with several string-handling packages to simulate 
variable-{-length strings; see Appendix C of the Ada 9X LRM.  Th
e name of the Ada 9X{package that provides "Unbounded-Length Str
ing Handling" is{%Ada.Strings.Unbounded`, described in section C
.4.5 of the Ada 9X LRM.{}b[ 316B314]When arrays are assigned, th
e^lengths~must be the same on both sides of the^:=`,{and the^typ
es~must be the same, but the^subscripts~needn't be the same.{For
 example, if we have{{@/^type Vector is array(Integer range <>) 
of Float;`{@/^V1 : Vector(1 .. 5);`{@/^V2 : Vector(2 .. 6) := (o
thers => 0.0);`{{@/^S1 : String(1 .. 5);`{@/^S2 : String(2 .. 6)
 := (others => ' ');`{{then we can write^V1 := V2;~and^S1 := S2;
~even though the subscripts are{different, because the array len
gths are the same and the element types are the{same.  But we'll
 get a Constraint_Error if we write^S1 := "Hello there";~or{%S1 
:= "Hi";~or^V1 := (1.0, 2.0, 3.0);`, because these arrays have w
rong lengths.{Ada won't automatically truncate Strings or pad wi
th blanks.  Of course, it{would be easy to write our own procedu
re to assign Strings of different{lengths, padding or truncating
 as necessary.{}b[ 317B315]A^slice~of an array is a portion of a
n array, and is indicated with a^range~in{the subscript.  A slic
e is itself an array.  Some languages use the term{"substring" t
o refer to a slice of a String, but in Ada we can take a slice o
f{%any~kind of array, not just an array of Characters.  So inste
ad of "substring,"{Ada uses the more general term "slice."  For 
example, if we have{{@&^A : array(1 .. 10) of Integer := (1, 2, 
3, 4, 5, 6, 7, 8, 9, 10);`{{then^A(1 .. 3)~is the array^(1, 2, 3
)~and^A(6 .. 9)~is the array^(6, 7, 8, 9)`.{Similarly, if we hav
e^S : String(1 .. 11) := "Hello there";~then^S(8 .. 11)~is{%"her
e"~and^S(4 .. 5)~is^"lo"`.  We can also write^S(1 .. 10) := S(2 
.. 11);~and{%A(1 .. 3) := A(4 .. 6);~since the lengths are the s
ame on both sides.{{If the value preceding^..~is greater than th
e value following it, we have a{%null range`.  A slice with a nu
ll range has a length of zero, and is called a{%null slice`.  In
 the case of a null slice, the subscript is^not~checked for{Cons
traint_Error.  Thus, even if N is 0 we could write^S(1 .. N);~wh
ich would{produce the null string^""`.  This is legal, even thou
gh Ada defines{"type String is array(%Positive~range <>) of Char
acter;".  Assigning a null{slice to a null slice does no harm an
d generates no error; it does nothing.{Also, if^S~is a null arra
y, then^S'Length~is 0, and^S'First~and^S'Last~don't{exist.  Usin
g^First~or^Last~with a null array will raise a Constraint_Error.
{}b[ 318B316]Beginners sometimes confuse a^Character~with a^Stri
ng of length 1`.  If we{write{{@=^S : String(1 .. 10);`{@=^I : I
nteger := 5;`{{then^S(I)~is a Character and^S(I .. I)~is a Strin
g of length 1.  Also,^'X'~is a{Character while^"X"~is a String o
f length 1.  Thus we could write{{@>^S(I) := 'X';`{@>^S(I .. I) 
:= "X";`{{but we'd be mixing types if we were to write^S(I) := "
X";~or^S(I .. I) := 'X';`.{{Fortunately, Text_IO has a Put for t
ype Character as well as a Put for type{String.  (It also has a 
Get for each of these types.)  Thus we can write either{%Put(S(I
 .. I));~or^Put(S(I));`.  However, Put_Line and Get_Line exist o
nly for{Strings, not for Characters.{}b[ 319B317]@$1.  Hello  : 
String := "Hello there";{@$2.  Digit  : String(0 .. 9) := "01234
56789";{@$3.  Line@#: String(1 .. 80) := (others => "*");{@$4.  
Hello  : String(2 .. 6) := "Hello";{@$5.  Hello  : String(1 .. 5
) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  Prompt : Str
ing(1 .. 3) := ">";{@$7.  Hello  : String(1 .. 5) := 'Hello';{{{
Which^one~of the above is legal in Ada 83?{}Please press 1, 2, 3
, 4, 5, 6, or 7, or B to go back.[4320132123223323532463257326B3
18]@$1.  Hello  : String := "Hello there";{@$2.  Digit  : String
(0 .. 9) := "0123456789";{@$3.  Line@#: String(1 .. 80) := (othe
rs => "*");{@#^4.  Hello  : String(2 .. 6) := "Hello";`{@$5.  He
llo  : String(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o')
;{@$6.  Prompt : String(1 .. 3) := ">";{@$7.  Hello  : String(1 
.. 5) := 'Hello';{{{%You're right!~ Number 4 creates Hello, a St
ring of length 5, and initializes it{to "Hello", a String of the
 same length.  The subscript of Hello need not start{at 1, so lo
ng as the length is 5.{{In Ada 83, number 1 attempts to create a
n unconstrained array.  Number 2 has a{zero subscript, while Ada
 defines type String for Positive subscripts.  Number{3 should h
ave^'`*%'~instead of^"`*%"`.  Number 5 tries to set each of the 
first{three elements, which are Characters, to a String.  Number
 6 tries to store a{String of length 1 into a String of length 3
, and number 7 should have^"`Hello%"`{instead of^'`Hello%'`.{}q[
 327B319Q319]@$1.  Hello  : String := "Hello there";{@$2.  Digit
  : String(0 .. 9) := "0123456789";{@$3.  Line@#: String(1 .. 80
) := (others => "*");{@$4.  Hello  : String(2 .. 6) := "Hello";{
@$5.  Hello  : String(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5
 => 'o');{@$6.  Prompt : String(1 .. 3) := ">";{@$7.  Hello  : S
tring(1 .. 5) := 'Hello';{{{No, number 1 is illegal in Ada 83 be
cause it tries to create an unconstrained{array.  (However, numb
er 1 is legal in Ada 9X.)  In Ada 83, the fact that{%"Hello ther
e"~has a definite length doesn't make the statement legal.  We m
ust{constrain the String to a length of 11 by writing, for examp
le,{%Hello  : String(1 .. 11) := "Hello there";`.  However, it^i
s~legal to write{{@3Hello :^constant~String := "Hello there";{}q
[ 327B319Q319]@$1.  Hello  : String := "Hello there";{@$2.  Digi
t  : String(0 .. 9) := "0123456789";{@$3.  Line@#: String(1 .. 8
0) := (others => "*");{@$4.  Hello  : String(2 .. 6) := "Hello";
{@$5.  Hello  : String(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  
5 => 'o');{@$6.  Prompt : String(1 .. 3) := ">";{@$7.  Hello  : 
String(1 .. 5) := 'Hello';{{{No, number 2 is illegal because of 
the zero subscript.  Ada defines "type{String is array(%Positive
~range <>) of Character;".  Therefore, the subscripts{must be 1 
or greater.{}q[ 327B319Q319]@$1.  Hello  : String := "Hello ther
e";{@$2.  Digit  : String(0 .. 9) := "0123456789";{@$3.  Line@#:
 String(1 .. 80) := (others => "*");{@$4.  Hello  : String(2 .. 
6) := "Hello";{@$5.  Hello  : String(1 .. 5) := (1 .. 3 => "Hel"
,  4 => 'l',  5 => 'o');{@$6.  Prompt : String(1 .. 3) := ">";{@
$7.  Hello  : String(1 .. 5) := 'Hello';{{{No, number 3 is illeg
al because^"`*%"~should be^'`*%'`.  As it stands, it tries to{as
sign a String of length 1 to each of the elements, which are Cha
racters.{}q[ 327B319Q319]@$1.  Hello  : String := "Hello there";
{@$2.  Digit  : String(0 .. 9) := "0123456789";{@$3.  Line@#: St
ring(1 .. 80) := (others => "*");{@$4.  Hello  : String(2 .. 6) 
:= "Hello";{@$5.  Hello  : String(1 .. 5) := (1 .. 3 => "Hel",  
4 => 'l',  5 => 'o');{@$6.  Prompt : String(1 .. 3) := ">";{@$7.
  Hello  : String(1 .. 5) := 'Hello';{{{No, number 5 is illegal 
because it tries to initialize each of the first three{elements,
 which are Characters, to a String of length 3.  We could, howev
er,{have written simply^Hello : String(1 .. 5);`, and then writt
en the following in{the executable region:{{@;^Hello(1 .. 3) := 
"Hel";`{@;^Hello(4) := 'l';`{@;^Hello(5) := 'o';`{}q[ 327B319Q31
9]@$1.  Hello  : String := "Hello there";{@$2.  Digit  : String(
0 .. 9) := "0123456789";{@$3.  Line@#: String(1 .. 80) := (other
s => "*");{@$4.  Hello  : String(2 .. 6) := "Hello";{@$5.  Hello
  : String(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@
$6.  Prompt : String(1 .. 3) := ">";{@$7.  Hello  : String(1 .. 
5) := 'Hello';{{{No, number 6 is illegal because it tries to ass
ign a String of length 1 to a{String of length 3.{}q[ 327B319Q31
9]@$1.  Hello  : String := "Hello there";{@$2.  Digit  : String(
0 .. 9) := "0123456789";{@$3.  Line@#: String(1 .. 80) := (other
s => "*");{@$4.  Hello  : String(2 .. 6) := "Hello";{@$5.  Hello
  : String(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@
$6.  Prompt : String(1 .. 3) := ">";{@$7.  Hello  : String(1 .. 
5) := 'Hello';{{{No, number 7 is illegal because it should say^"
`Hello%"~instead of^'`Hello%'`.  Ada{"tic" marks (%'`) always en
close a single Character, while double quotes (%"`){always enclo
se an array of Characters.{}q[ 327B319Q319]@@ARRAY OPERATORS{{Th
e operator^&~concatenates any two arrays of the same type, inclu
ding two{Strings.  It can also concatenate a single element with
 an array of that{element type, or two single elements into an a
rray of length two.  For example,{every use of^&~below is legal:
{{@+C, D : Character := '*';{@+S2@#: String(1 .. 2);{@+S3@#: Str
ing(1 .. 3) := (others => ' ');{@+S5@#: String(1 .. 5);{{@+type 
Vector is array(Integer range <>) of Float;{@+F, G : Float := 1.
2;{@+V2@#: Vector(1 .. 2);{@+V3@#: Vector(1 .. 3) := (others => 
0.0);{@+V5@#: Vector(1 .. 5);{@+...{@*^S2 := C & D;  S5 := S2 & 
S3;  S3 := C & S2;  S3 := S2 & C;`{@*^V2 := F & G;  V5 := V2 & V
3;  V3 := F & V2;  V3 := V2 & F;`{}b[ 328B319]The operators^and`
,^or`,^xor`, and^not`, defined for Booleans, are also defined fo
r{one-dimensional arrays of Boolean.  They operate element by el
ement on the{arrays.  Thus, we can simulate^sets~in Ada.  For ex
ample, if we write{{@#^type Set_Of_Chars is array(Character) of 
Boolean;`{@#^S1 : Set_Of_Chars := Set_Of_Chars'('*' | '#' => Tru
e, others => False);`{@#^S2 : Set_Of_Chars := Set_Of_Chars'('*' 
| '?' => True, others => False);`{{then^S1 or S2~is^Set_Of_Chars
'('*' | '#' | '?' => True, others => False)`,{and^S1 and S2~is^S
et_Of_Chars'('*' => True, others => False)`.{{The operators^=~an
d^/=~can compare two records or two arrays of the same type.{Rec
ords are equal if all of their corresponding fields are equal, a
rrays, if{all of their corresponding elements are equal.  Arrays
 of different lengths{are always unequal.  The four remaining re
lational operators can compare two{arrays of the same type.  The
y're compared element by element until a{difference is found.  F
or example, if we have{{@7^S : String(1 .. 6) := "to all";`{@7^T
 : String(1 .. 7) := "to Bill";`{{then^S > T~because 'a' > 'B' i
n Ada's definition of type Character.{}b[ 329B327]@3OUTSIDE ASSI
GNMENT 3 - EXERCISE IN RECORDS{{Your third Outside Assignment is
 to write a function specified by{{@%type Month_Type is (Jan,Feb
,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{@%subtype Day_Subtype
 is Integer range 1 .. 31;{@%type Date is{@(record{@+Day@#: Day_
Subtype;{@+Month : Month_Type;{@+Year  : Integer;{@(end record;{
@$^function Tomorrow(Today : in Date) return Date;`{{Given any d
ate, Tomorrow should return the following date.  Your function w
ill{be tested only with legal dates.  As with Outside Assignment
 2, a test driver{is already written; it's in^NEXTDATE.ADA`.  A 
listing is on page 13 of your{printed course notes, but you need
n't understand the test driver.  If your{function fails any test
, you'll see the test case, the answer from your{function, and t
he right answer.  Otherwise, you'll see "Congratulations, you{co
mpleted the assignment!"{}b[ 330B328]The definitions of Month_Ty
pe, Day_Subtype, and Date are in the test driver;{you shouldn't 
define them inside your function.  A dummy solution is in{%TOMOR
ROW.DUM`; it looks like this:{{@/-- Dummy solution to Outside As
signment 3{@.^separate (Nextdate)`{@.^function Tomorrow(Today : 
in Date) return Date is`{@.^begin`{@2return Today;{@.^end Tomorr
ow;`{{Again, you'll probably want to remove or change the commen
t line, and you{shouldn't change the lines^highlighted~above.  Y
ou may, but don't have to,{include^Answer : Date;~in the declara
tive region and make^return Answer;~the{last statement before^en
d Tomorrow;`.{{Normally, years divisible by 4 are leap years.  B
ut if a year is divisible by{100, it must also be divisible by 4
00 to be a leap year.  Thus, 2000 is a leap{year, but 1900 and 2
100 are not.  Note that^Today.Year~is divisible by 4 if and{only
 if^Today.Year mod 4 = 0`.  You may assume that^Today.Year~will 
always be{between 1583 and 3999, because outside this range the 
calendar gets more{complicated.{}b[ 331B329]The steps to follow 
for Outside Assignment 3 are very similar to those of{Outside As
signment 2.  They're in your printed course notes on page 14:{{1
.  Compile the test driver NEXTDATE.ADA.  Also, make a copy of t
he dummy{@$solution by typing^COPY TOMORROW.DUM TOMORROW.ADA`.  
You need do this step{@$only once.{{2.  Edit TOMORROW.ADA to bec
ome your real solution.  You may skip this step the{@$first time
 through, to see error messages from the test driver.{{3.  Compi
le TOMORROW.ADA.  If the compiler finds errors, go back to step 
2.{{4.  Link with the name of the main program Nextdate.  Then e
xecute.  If the{@$test driver displays error messages, go back t
o step 2.{{5.  When the message "Congratulations, you completed 
the assignment!" is{@$displayed, you'll have a chance to compare
 your solution with ours.{}b[ 332B330]There are many ways to sol
ve this problem.  In our solution we declared an{array of Day_Su
btype with subscripts of type Month_Type.  Some students use a{%
case~construct on Today.Month; some use an^if~block with^elsif`s
.{{This assignment should be a simple exercise in records.  Our 
solution fits on{one screen.  If your solution starts to get lon
g and difficult, you should{think the problem through again.  Do
n't try to save the computer a few{microseconds; computers are s
upposed to save people time.  Instead, minimize{the^complexity~o
f the program to save yourself programming effort!{{Remember tha
t an entire record can be assigned in one statement.  Also, try 
to{calculate the number of days in the month and^then~test for e
nd of month and{end of year in only one place.  This is better t
han having several blocks of{code testing for end of month and e
nd of year in three or four different places{in your program.  O
ne last hint: remember that Month_Type'Succ(Today.Month){will ra
ise a Constraint_Error if Today.Month is Dec.{{Please type X to 
exit^ADA-TUTR~temporarily, and try Outside Assignment 3.  Work{a
t your own pace; there's no deadline.  Good luck!{}Please type X
 to exit, a space to go on, or B to go back.[ 333B331]@-^Congrat
ulations on Completing Outside Assignment 3!`{{-- Our solution t
o Outside Assignment 3 (in TOMORROW.ANS):{separate (Nextdate){fu
nction Tomorrow(Today : in Date) return Date is{@#Length : array
(Month_Type) of Day_Subtype :={@>(31, 28, 31, 30, 31, 30, 31, 31
, 30, 31, 30, 31);{@#Answer : Date;{begin{@#if Today.Year mod 4 
= 0 and{@7(Today.Year mod 100 /= 0 or Today.Year mod 400 = 0) th
en{@&Length(Feb) := 29;{@#end if;{@#if Today.Day /= Length(Today
.Month) then@0-- Not end of month.{@&Answer := (Today.Day + 1, T
oday.Month, Today.Year);{@#elsif Today.Month /= Dec then@*-- End
 of month, but not end of year.{@&Answer := (1, Month_Type'Succ(
Today.Month), Today.Year);{@#else@Y-- End of year.{@&Answer := (
1, Jan, Today.Year + 1);{@#end if;{@#return Answer;{end Tomorrow
;{}b[ 334B332]In our solution, the first^if~statement checks for
 leap year.  No^else~is{needed because the locally declared arra
y^Length~is re-initialized every time{the function is called.  A
fter this^if~statement, the number of days in the{month is in^Le
ngth(Today.Month)`, and it's easy to test for end of month and e
nd{of year - in only one place in the program.{{We could have wr
itten^Month_Type'Last~instead of^Dec`, and^Month_Type'First`{ins
tead of^Jan`.  We could even have used^Day_Subtype'First`.  But 
the author{reasoned that if our calendar ever changes, the entir
e program will probably{have to be rewritten anyway!  The progra
m seems a little easier to read when we{use the names^Dec~and^Ja
n~and the number^1~directly.{{Your solution might be entirely di
fferent from ours.  If the test driver said{"Congratulations, yo
u completed the assignment!" you may consider your solution{corr
ect.  Let's go on to discuss recursion.{}b[ 335B333]@;^ADA-TUTR 
COURSE OUTLINE`{{{@#Introduction@9^>  RECURSION AND ASSIGNMENT 4
`{{@#The Format of an Ada Program@-Subprograms and Packages{{@#G
eneric Instantiation and@0Access Types, User Defined Types,{@&As
signment 1@=and Derived Types{{@#Simple Declarations and Simple@
+Exceptions, Text_IO, and{@&Attributes@?Assignment 5{{@#Operator
s, Control Constructs, and@'Generics, Tasking, and Assignment 6{
@&Assignment 2{@LMore Records and Types{@#Records, Arrays, and A
ssignment 3{@LAdvanced Topics{}b[ 336B334]@CRECURSION{{Ada proce
dures and functions may call themselves, directly or indirectly.
  This{process is called^recursion`.  While recursion often uses
 a little extra memory{and execution time, for certain types of 
problems it pays large dividends in{program simplicity.  That's 
a very worthwhile exchange!{{For example, let's write a function
 to compute the factorial of a positive{integer.  The factorial 
of an integer is the product of all the integers from{that numbe
r down to one.  Thus, Factorial(5) = 5 * 4 * 3 * 2 * 1 = 120.{Al
though we could easily write this function with a^for~loop, we'l
l use{recursion instead.  Note that if N = 1, then Factorial(N) 
= 1; otherwise,{Factorial(N) = N * Factorial(N - 1).{{@-function
 Factorial(N : in Positive) return Positive is{@0Answer : Positi
ve := 1;{@-begin{@0if N > 1 then{@3Answer := N * Factorial(N - 1
);{@0end if;{@0return Answer;{@-end Factorial;{}b[ 337B335]@-fun
ction Factorial(N : in Positive) return Positive is{@0Answer : P
ositive := 1;{@-begin{@0if N > 1 then{@2^Answer := N * Factorial
(N - 1);`{@0end if;{@0return Answer;{@-end Factorial;{{The highl
ighted line shows where this function calls itself.  Recursive{s
ubprograms always call themselves^conditionally`; otherwise the 
program would{run out of memory, no matter how large the machine
.  Here the recursive call is{inside an^if~block.{{Note that Ans
wer is initialized to 1.  If the function is called with N = 1,{
the^if~statement is False, Answer isn't modified, and^1~is retur
ned as the{value of the function.  If the function is called wit
h N = 2, the^if~statement{is True, and the highlighted line is e
xecuted.  The machine starts to compute{the expression as 2 * ..
., and then Factorial is called with N = 1.  It's as if{the mach
ine made another copy of the code for Factorial and called that.
{Actually there's only one copy of the code, but the machine mai
ntains multiple{%pointers~to it.{}b[ 338B336]@-function Factoria
l(N : in Positive) return Positive is{@0Answer : Positive := 1;{
@-begin{@0if N > 1 then{@2^Answer := N * Factorial(N - 1);`{@0en
d if;{@0return Answer;{@-end Factorial;{{When the recursive call
 is made, the system allocates additional memory for new{version
s of any local variables like Answer.  Also, the parameters like
 N are{separate for each recursive call.{{Suppose the main progr
am calls Factorial with N = 2.  Then, in computing the{expressio
n, Factorial calls itself with N = 1.  In this second call, a ne
w{local variable Answer is created, separate from the one in the
 first call.{Also, parameter N is 1 in the second call, but 2 in
 the first call.  In the{second call, the^if~statement is False,
 and 1 is returned.  In the first call,{the calculation of the e
xpression is completed, using the value 1 returned by{the second
 call.  Thus, Answer becomes 2 * 1 = 2, and the first call retur
ns{the answer 2 to the main program.{}b[ 339B337]@-function Fact
orial(N : in Positive) return Positive is{@0Answer : Positive :=
 1;{@-begin{@0if N > 1 then{@2^Answer := N * Factorial(N - 1);`{
@0end if;{@0return Answer;{@-end Factorial;{{If the main program
 calls Factorial with N = 3, the function starts to compute{the 
expression as Answer := 3 * ..., and calls Factorial with N = 2.
  In this{second call, the function starts to compute Answer := 
2 * ..., and calls{Factorial with N = 1.  In this third call, th
e^if~statement is False, and the{answer 1 is returned to the sec
ond call.  The second call finishes the{computation of the expre
ssion Answer := 2 * 1, and returns the answer 2 to the{first cal
l.  Finally, the first call finishes computing the expression wi
th{Answer := 3 * 2, and returns the answer 6 to the main program
.{{This simple function wouldn't have been complicated even with
out recursion.  In{a moment we'll discuss the Tower of Hanoi pro
blem.  The recursive solution is{very simple, but a solution wit
hout recursion would be very complicated indeed.{}b[ 340B338]In 
this question, function A calls B, and B conditionally calls A. 
 The{specification of function B is given early so that A can ca
ll it.{{@1function B (I : in Integer) return Integer;{{@1functio
n A (I : in Integer) return Integer is{@1begin{@4return B(I - 1)
 + 1;{@1end A;{{@1function B (I : in Integer) return Integer is{
@4Ans : Integer := 0;{@1begin{@4if I > 0 then{@7Ans := A(I);{@4e
nd if;{@4return Ans;{@1end B;{{If the main program calls functio
n A with a parameter equal to 2, what value{will A return:  0, 1
, 2, or 3?  You may need pencil and paper to figure this{one out
.{}Please press 0, 1, 2, or 3, or B to go back.[2341034213423342
B339]@1function B (I : in Integer) return Integer;{{@1function A
 (I : in Integer) return Integer is{@1begin{@4return B(I - 1) + 
1;{@1end A;{{@1function B (I : in Integer) return Integer is{@4A
ns : Integer := 0;{@1begin{@4if I > 0 then{@7Ans := A(I);{@4end 
if;{@4return Ans;{@1end B;{{%You're right!~ When the main progra
m calls A(2), A starts to evaluate{B(1) + 1.  The^if~statement i
n B is True, so B simply calls A(1).  The call{A(1) starts to ev
aluate B(0) + 1.  The^if~statement in this call to B is False,{s
o B(0) simply returns 0, and the call A(1) returns 0 + 1 = 1.  T
he call B(1){returns the same answer, so the call A(2) returns 1
 + 1 = 2.{}q[ 343B340Q340]@1function B (I : in Integer) return I
nteger;{{@1function A (I : in Integer) return Integer is{@1begin
{@4return B(I - 1) + 1;{@1end A;{{@1function B (I : in Integer) 
return Integer is{@4Ans : Integer := 0;{@1begin{@4if I > 0 then{
@7Ans := A(I);{@4end if;{@4return Ans;{@1end B;{{No, when the ma
in program calls A(2), A starts to evaluate B(1) + 1.  The^if`{s
tatement in B is True, so B simply calls A(1).  The call A(1) st
arts to{evaluate B(0) + 1.  The^if~statement in this call to B i
s False, so B(0) simply{returns 0, and the call A(1) returns 0 +
 1 = 1.  The call B(1) returns the same{answer, so the call A(2)
 returns 1 + 1 = 2.{}q[ 343B340Q340]@;THE TOWER OF HANOI PROBLEM
{{The "Tower of Hanoi" is a solitaire puzzle that was named when
 Hanoi was the{capital of a free country: French Indochina.  The
re are three pegs labeled A,{B, and C; one of them has a tower o
f N doughnut-shaped disks of decreasing{size, like this:{{@/|@7|
@7|{@/|@7|@7|{@.=|=@6|@7|{@-==|==@5|@7|{@,===|===@4|@7|{@+====|=
===@3|@7|{@*=====|=====@2|@7|{@'-----------------@'-------------
----@'-----------------{@/A@7B@7C{{The object is to move the ent
ire tower from one peg to another, say, from A to{B.  Only one d
isk may be moved at a time, and a larger disk may never be place
d{on top of a smaller one.  The shortest solution to the puzzle 
with N disks{requires 2**N - 1 moves.{}b[ 344B340]For example, w
e can move five disks from A to B with the following 31 moves:{(
Read them from left to right, not in columns.){{A to B,  A to C,
  B to C,  A to B,  C to A,  C to B,  A to B,  A to C,  B to C,{
B to A,  C to A,  B to C,  A to B,  A to C,  B to C,  A to B,  C
 to A,  C to B,{A to B,  C to A,  B to C,  B to A,  C to A,  C t
o B,  A to B,  A to C,  B to C,{A to B,  C to A,  C to B,  A to 
B.{{@/|@7|@7|{@/|@7|@7|{@/|@7|@7|{@/|@7|@7|{@.=|=@6|@7|{@+====|=
===@3|@7|{@*=====|=====@/===|===@2==|=={@'-----------------@'---
--------------@'-----------------{@/A@7B@7C{@4(The Puzzle After 
the First Five Moves){{Writing a program to display this series 
of moves would be very complicated{without recursion.  Let's dev
elop a recursive solution; we'll see that the{resulting Ada prog
ram is surprisingly simple!{}b[ 345B343]When we developed a recu
rsive solution for the Factorial function:{{@1if N = 1,  Factori
al(N) = 1{@1otherwise, Factorial(N) = N * Factorial(N - 1){{we e
xpressed Factorial(N) in terms of Factorial(N - 1), and gave the
 trivial{solution for N = 1.  The Ada program was easily written
 from the above.{{For the Tower of Hanoi problem, let's develop 
a solution for N disks in terms{of a solution for N - 1 disks.  
Suppose we want to move five disks from A to B,{using C as a spa
re peg.  We first move^four~disks from A to^C`, then move one{di
sk from A to B, and finally move four disks from C to B.  In gen
eral, to move{N disks from a source peg to a destination peg, we
 first move N - 1 disks from{the source to the spare, then move 
one disk from the source to the destination,{and finally move N 
- 1 disks from the spare to the destination.{{To move the^one~di
sk from the source to the destination, our program will{simply d
isplay the move.  To move N - 1 disks, the program will call its
elf.{The solution for zero disks is trivial indeed: the program 
will do nothing!{{The following program is extremely simple: thr
ee executable statements inside{an^if~block.  Yet it can display
 a very complicated series of moves!{}b[ 346B344]@&^with Text_IO
; use Text_IO;`{@&^procedure Hanoi(N : in Natural; From, To, Spa
re : in Character) is`{@&^begin`{@)^if N > 0 then`{@,^Hanoi(N - 
1, From, Spare, To);`{@,^Put_Line(From & " to " & To);`{@,^Hanoi
(N - 1, Spare, To, From);`{@)^end if;`{@&^end Hanoi;`{{To move f
ive disks from A to B, using C as a spare, we would call{%Hanoi(
5, 'A', 'B', 'C');~and the program would display the 31 moves.{{
Note that when Hanoi is called with N = 0, it does nothing.  Whe
n called with{N = 1, the^if~statement is true, and the three lin
es within the^if~block are{executed.  But the first and third li
nes do nothing, because they call Hanoi{with N = 0.  The second 
line displays, for example,^A to B`.{{When called with a larger 
value of N, the first line within the^if~block moves{N - 1 disks
 from the source to the spare peg.  The second line displays the
{move of one disk from the source to the destination, and the th
ird line moves{N - 1 disks from the spare peg to the destination
.{}b[ 347B345]Most implementations of Ada won't allow Hanoi to b
e a main program, because it{has parameters.  A short main progr
am to call Hanoi is shown here.  A slightly{longer program could
 get N and the names of the three pegs from the user.  In{this e
xample, procedure Demo^with`s a previously compiled~procedure~ra
ther than{a~package`.{{@9^with Hanoi;`{@9^procedure Demo is`{@9^
begin`{@<^Hanoi(5, 'A', 'B', 'C');`{@9^end Demo;`{{In summary, o
ur first example of recursion, Factorial, was very simple.{Howev
er, that program would have been simple even without recursion. 
 Our{second example, Hanoi, also was very simple, but the progra
m would have been{quite complicated without recursion.{{Our four
th Outside Assignment will be to write a Fibonacci function Fib,
 using{recursion.  As with Factorial, this function would be eas
y to write even{without recursion.  However, as an exercise we'l
l write it using recursion.{}b[ 348B346]@2OUTSIDE ASSIGNMENT 4 -
 EXERCISE IN RECURSION{{Your fourth Outside Assignment is to wri
te, using recursion, a function{specified by{{@0^function Fib(N 
: in Positive) return Positive;`{{Fibonacci was a mathematician 
in the Middle Ages.  The so-called^Fibonacci{Series~is a series 
of integers.  Each number in the series is the sum of the{two pr
evious numbers.  The first two Fibonacci numbers are 1.{{@%N:@$1
  2  3  4  5  6@#7@#8@#9  10  11@#12@#13@#14@#15@#16 ...{@#Fib(N
): 1  1  2  3  5  8  13  21  34  55  89  144  233  377  610  987
 ...{{Note that if N = 1 or N = 2, then Fib(N) = 1; otherwise,{F
ib(N) = Fib(N - 1) + Fib(N - 2).  Writing this function in Ada w
ill be an easy{and short assignment.  A test driver is provided 
in^FIBTEST.ADA`; a listing is{on page 15 of your printed course 
notes.  As before, if all tests are passed,{it displays "Congrat
ulations, you completed the assignment!"  If there's an{error, i
t displays the test case, the answer from your function, and the
 right{answer.{}b[ 349B347]A dummy solution is in^FIB.DUM`.  As 
before, you shouldn't change the lines{%highlighted~here:{{@0-- 
Dummy solution to Outside Assignment 4{@/^separate (Fibtest)`{@/
^function Fib(N : in Positive) return Positive is`{@/^begin`{@3r
eturn 4;{@/^end Fib;`{{{The steps to follow for Outside Assignme
nt 4 are similar to those of the last{two Outside Assignments.  
They're in your printed course notes on page 16:{}b[ 350B348]1. 
 Compile the test driver FIBTEST.ADA.  Also, make a copy of the 
dummy{@$solution by typing^COPY FIB.DUM FIB.ADA`.  You need do t
his step only once.{{2.  Edit FIB.ADA to become your real soluti
on.  You may skip this step the{@$first time through, to see err
or messages from the test driver.{{3.  Compile FIB.ADA.  If the 
compiler finds errors, go back to step 2.{{4.  Link with the nam
e of the main program Fibtest.  Then execute.  If the test{@$dri
ver displays error messages, go back to step 2.{{5.  When the me
ssage "Congratulations, you completed the assignment!" is{@$disp
layed, you'll have a chance to compare your solution with ours.{
{{Please type X to exit^ADA-TUTR~temporarily, and try Outside As
signment 4.  Work{at your own pace; there's no deadline.  Good l
uck!{}Please type X to exit, a space to go on, or B to go back.[
 351B349]@-^Congratulations on Completing Outside Assignment 4!`
{{@--- Our solution to Outside Assignment 4 (in FIB.ANS):{@-sepa
rate (Fibtest){@-function Fib(N : in Positive) return Positive i
s{@0Answer : Positive := 1;{@-begin{@0if N > 2 then{@3Answer := 
Fib(N - 1) + Fib(N - 2);{@0end if;{@0return Answer;{@-end Fib;{{
Your solution is probably quite similar to ours.  Perhaps you us
ed^else~and{didn't initialize Answer in the declarative region. 
 Perhaps you had some other{minor variation.  Our solution is pr
obably no "better" than yours, if the test{driver said, "Congrat
ulations, you completed the assignment!"{{Was this assignment^to
o~easy?  We promise that Outside Assignment 5 will be{much more 
challenging!  But first we need to discuss procedures and functi
ons{in more detail, as well as packages and information hiding, 
access types, and{exceptions.{}b[ 352B350]@;^ADA-TUTR COURSE OUT
LINE`{{{@#Introduction@=Recursion and Assignment 4{{@#The Format
 of an Ada Program@)^>  SUBPROGRAMS AND PACKAGES`{{@#Generic Ins
tantiation and@0Access Types, User Defined Types,{@&Assignment 1
@=and Derived Types{{@#Simple Declarations and Simple@+Exception
s, Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Control
 Constructs, and@'Generics, Tasking, and Assignment 6{@&Assignme
nt 2{@LMore Records and Types{@#Records, Arrays, and Assignment 
3{@LAdvanced Topics{}b[ 353B351]@<PROCEDURES AND FUNCTIONS{{When
 we compiled procedures Hello and Add into the library, we made 
it possible{for other units to^with~them and call them.  (We don
't^use~procedures and{functions, because dot notation doesn't ap
ply to them.)  We can also compile{just a^specification`, supply
ing the body later.  For example, we could compile{{@(^function 
Upper_Case(S : in String) return String;`{{and then compile the 
calling program.  When we later write the body, it must{agree wi
th the specification:{{@(^function Upper_Case(S : in String) ret
urn String is`{@,Answer : String(S'Range) := S;{@)begin{@,for I 
in S'Range loop{@/if S(I) in 'a' .. 'z' then{@2Answer(I) := Char
acter'Val(Character'Pos(S(I)) - 32);{@/end if;{@,end loop;{@,ret
urn Answer;{@)end Upper_Case;{}b[ 354B352]Functions and procedur
es may also be declared locally.  In Ada 83, such{declarations m
ust follow any simple declarations like^S : String(1 .. 5);`.{{@
'with Text_IO; use Text_IO;{@'procedure Greeting is{@*S : String
(1 .. 5) := "Hello";{@)^function Upper_Case(S : in String) retur
n String is`{@,^Answer : String(S'Range) := S;`{@)^begin`{@,^for
 I in S'Range loop`{@/^if S(I) in 'a' .. 'z' then`{@2^Answer(I) 
:= Character'Val(Character'Pos(S(I)) - 32);`{@/^end if;`{@,^end 
loop;`{@+^return Answer;`{@)^end Upper_Case;`{@'begin{@*Put_Line
(Upper_Case(S));{@'end Greeting;{{As we've seen, we can declare 
local functions and procedures to be^separate`.{These subprogram
s can in turn declare^separate~subprograms, to any depth:{}b[ 35
5B353]@2procedure Main is{@5function A return Float is separate;
{@2begin{@5...{@2end Main;{{@1^separate (Main)`{@2function A ret
urn Float is{@5procedure B is separate;{@2begin{@5...{@2end A;{{
@1^separate (Main.A)`{@2procedure B is{@5procedure C(I : in Inte
ger) is separate;{@2begin{@5...{@2end B;{{@1^separate (Main.A.B)
`{@2procedure C(I : in Integer) is ... (etc.){}b[ 356B354]Howeve
r,^is separate~may be used only at the outermost level.  The exa
mple{below is legal as it stands, but we may not make procedure 
B separate unless we{also make function A separate, thus bringin
g function A to the outermost level:{{@9procedure Main is{@<F : 
Float;{@<function A return Float is{@?Answer : Float;{@?procedur
e B is{@?begin{@B...{@?end B;{@<begin{@?...{@?return Answer;{@<e
nd A;{@9begin{@<...{@9end Main;{{A program that begins^separate 
(`...%)~must be compiled after the program that{says^is separate
`, because a separate subprogram depends on its "parent."{}b[ 35
7B355]A procedure or function specification gives the name, mode
, and type of each{parameter.  A function specification also giv
es the type of the result.  The{mode can be^in`,^out`, or^in out
`.  The subprogram may read from, but not write{to,^in~parameter
s, and it may write to, but not read from,^out~parameters.  (In{
Ada 9X, it may read^out~parameters.)  If the mode is omitted, it
's assumed to{be^in`.  Thus, these two lines have the same effec
t:{{@'^procedure Hanoi(N : in Natural; From, To, Spare : in Char
acter);`{@'^procedure Hanoi(N : Natural;@$From, To, Spare : Char
acter);`{{The parameters of a^function~must always be of mode^in
`, never^out~or^in out`.{{Note that when several parameters have
 the same mode and type, they can be{placed in one list, separat
ed by commas.  The lists themselves are separated by{semicolons.
  The two specifications above are equivalent to:{{%procedure Ha
noi(N : Natural; From: Character; To: Character; Spare: Characte
r);`{{In any event, the parameters in a^call~to a procedure or f
unction are always{separated by^commas`:{{@;^Hanoi(5, 'A', 'B', 
'C');`{}b[ 358B356]@#1.  procedure P(A; B; C : in Integer);{{@#2
.  procedure P(A, B, C : Integer; D, E : in out Float) return Ch
aracter;{{@#3.  function  F(A, B, C : Integer; D, E : in out Flo
at) return Character;{{@#4.  procedure P(A, B, C : Integer; D, E
 : in out Float);{{{Which one of the above is^legal`?{}Please pr
ess 1, 2, 3, or 4, or B to go back.[4359136023613362B357]@#1.  p
rocedure P(A; B; C : in Integer);{{@#2.  procedure P(A, B, C : I
nteger; D, E : in out Float) return Character;{{@#3.  function  
F(A, B, C : Integer; D, E : in out Float) return Character;{{  ^
4.  procedure P(A, B, C : Integer; D, E : in out Float);`{{%You'
re right!~ In a subprogram specification, the items of a list ar
e separated{by commas, and the lists are separated by semicolons
.  In a list, the mode may{be omitted; it's assumed to be^in`.{{
In number 1, the items should be separated by commas.  Number 2 
has a^return`{clause in a^procedure~specification, and number 3 
has a mode other than^in~in a{%function~specification.{}q[ 363B3
58Q358]@#1.  procedure P(A; B; C : in Integer);{{@#2.  procedure
 P(A, B, C : Integer; D, E : in out Float) return Character;{{@#
3.  function  F(A, B, C : Integer; D, E : in out Float) return C
haracter;{{@#4.  procedure P(A, B, C : Integer; D, E : in out Fl
oat);{{No, in number 1 the items should be separated by commas, 
not semicolons.  In a{subprogram specification, the items in a l
ist are separated by commas, and the{lists are separated by semi
colons.  Here a "list" means a collection of{parameters sharing 
the same mode and type (%in Integer`).{}q[ 363B358Q358]@#1.  pro
cedure P(A; B; C : in Integer);{{@#2.  procedure P(A, B, C : Int
eger; D, E : in out Float) return Character;{{@#3.  function  F(
A, B, C : Integer; D, E : in out Float) return Character;{{@#4. 
 procedure P(A, B, C : Integer; D, E : in out Float);{{No, numbe
r 2 is illegal because a^return~clause applies only to a functio
n{specification, not a procedure specification.{}q[ 363B358Q358]
@#1.  procedure P(A; B; C : in Integer);{{@#2.  procedure P(A, B
, C : Integer; D, E : in out Float) return Character;{{@#3.  fun
ction  F(A, B, C : Integer; D, E : in out Float) return Characte
r;{{@#4.  procedure P(A, B, C : Integer; D, E : in out Float);{{
No, number 3 is illegal because all parameters of a function mus
t have mode^in`.{}q[ 363B358Q358]Recall that type conversion fro
m Float to Integer in Ada rounds to the nearest{integer.  (The A
da 83 standard doesn't specify which way rounding occurs when{th
e fractional part is exactly 0.5; the Ada 9X standard specifies 
rounding away{from zero in such cases.)  This function Floor com
putes the largest integer{less than or equal to a given Float, a
lways rounding toward negative infinity:{{@1function Floor(X : i
n Float) return Integer is{@4Answer : Integer := Integer(X);{@1b
egin{@4if Float(Answer) > X then{@7Answer := Answer - 1;{@4end i
f;{@4return Answer;{@1end Floor;{}b[ 364B358]Similarly, this fun
ction Truncate converts from Float to Integer, always{truncating
 toward zero:{{@/function Truncate(X : in Float) return Integer 
is{@2Answer : Integer := Integer(X);{@/begin{@2if Answer > 0 and
 Float(Answer) > X then{@5Answer := Answer - 1;{@2elsif Answer <
 0 and Float(Answer) < X then{@5Answer := Answer + 1;{@2end if;{
@2return Answer;{@/end Truncate;{}b[ 365B363]@?DEFAULT PARAMETER
S{{The^in~parameters of a subprogram specification may be given 
default values.{Suppose, for example, that the package Integer_I
O is instantiated for the type{Integer.  Here's a simplified ver
sion of the specification for the procedure{Put (the actual spec
ification can be found in section 14.3.10 of the LRM):{{@3^proce
dure Put(Item  : in Integer;`{@A^Width : in Integer := 6;`{@A^Ba
se  : in Integer := 10);`{{This means that, in calls to Put, the
 Width and Base parameters are optional.{If Width is omitted, it
's assumed to be 6, and if Base is omitted, it's assumed{to be 1
0.  If either of these parameters is given in the call, the defa
ult{value is overridden.  (The default value for Width is shown 
here as 6.{Actually, it depends on the implementation of Ada.  O
f course, the default{value for Base is always 10.){{Default par
ameters let us make our Ada subprograms both^flexible~and^easy t
o{use`.  In other languages, we'd often have to choose between t
hese two{qualities.  For example, suppose J is an integer.  Here
 are some calls to Put:{}b[ 366B364]@4procedure Put(Item  : in I
nteger;{@BWidth : in Integer := 11;{@BBase  : in Integer := 10);
{{@3^Put(J);`{@3^Put(J, Width => 4);`{@3^Put(J, Base => 16);`{@3
^Put(J, Base => 16, Width => 4);`{{The first parameter in each c
all could have been given as^Item => J`, but{everyone remembers 
that the first parameter of Put is the item, so named{notation s
eems unnecessary for this parameter.  However, Width and Base ar
e{used less frequently.  We used named notation for these parame
ters so the{reader of our code wouldn't have to remember which p
arameter comes second and{which comes third.  Note that if we om
it the second parameter and specify the{third, we^must~use named
 notation for the third parameter; we're not allowed to{write Pu
t(J, ,16); as in some languages.{{If we were writing Put in anot
her language, we'd have to choose either making{the user specify
 the width and the base in every call (giving flexibility), or{w
riting Put with only one parameter (giving ease of use).  In Ada
, default{parameters give us both flexibility and ease of use!{}
b[ 367B365]Text_IO.New_Line has one parameter, Spacing, defaulte
d to 1.  Thus, we can call{%New_Line;~to get one CR-LF, or, for 
example,^New_Line(3);~to get three.{{Default values may also be 
given in record definitions.  If we write{{@%type Month_Type is 
(Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);{@%subtype Day
_Subtype is Integer range 1 .. 31;{@%type Date is{@(record{@+Day
@#: Day_Subtype;{@+Month : Month_Type;{@+Year  : Integer^:= 1776
`;{@(end record;{@%USA : Date;{{then^USA.Year~is set to 1776 whe
n the line declaring^USA~is elaborated.  Every{time an object of
 type Date is declared, its Year field is set to 1776.{However, 
there's a difference between default values in records and defau
lt{parameters in subprograms.  We can't write USA := (4, Jul); a
ll three fields of{the record must be specified.{}b[ 368B366]@4p
rocedure Put(Item  : in Integer;{@BWidth : in Integer := 11;{@BB
ase  : in Integer := 10);{{Which one of these is^legal`?{{@:1.  
Put(Item => 23, 5, 10);{{@:2.  Put(23, 5);{{@:3.  Put(23; 5; 10)
;{}Please press 1, 2, or 3, or B to go back.[236913703371B367]@4
procedure Put(Item  : in Integer;{@BWidth : in Integer := 11;{@B
Base  : in Integer := 10);{{{@:1.  Put(Item => 23, 5, 10);{{@9^2
.  Put(23, 5);`{{@:3.  Put(23; 5; 10);{{{%You're right!~ The thi
rd parameter may be omitted because it has a default{value.  In 
number 1, positional notation follows named, which isn't allowed
,{and in number 3, the separators should be commas.{}q[ 372B368Q
368]@4procedure Put(Item  : in Integer;{@BWidth : in Integer := 
11;{@BBase  : in Integer := 10);{{{@:1.  Put(Item => 23, 5, 10);
{{@:2.  Put(23, 5);{{@:3.  Put(23; 5; 10);{{{No, number 1 is ill
egal because positional notation may not follow named.{}q[ 372B3
68Q368]@4procedure Put(Item  : in Integer;{@BWidth : in Integer 
:= 11;{@BBase  : in Integer := 10);{{{@:1.  Put(Item => 23, 5, 1
0);{{@:2.  Put(23, 5);{{@:3.  Put(23; 5; 10);{{{No, number 3 is 
illegal because in a call, the parameters are always separated{w
ith commas, not semicolons.{}q[ 372B368Q368]@DPACKAGES{{A^packag
e~lets us group related declarations, procedures, and functions.
  A{program can^with~the package and gain access to all of these
.  However, as{we'll see, packages have many other advantages.  
Usually library units are{packages rather than individual proced
ures and functions.{{By way of example, consider a very simple p
rocedure and a very simple function:{{@)^procedure Double(Number
 : in Integer; Answer : out Integer);`{@)^function Twice(Number 
: in Integer) return Integer;`{{We could compile these individua
lly, or we could put them in a^package~and{compile that instead.
  Here's the package^specification`:{{@'^package Simple_Math is`
{@+procedure Double(Number : in Integer; Answer : out Integer)%;
`{@+function Twice(Number : in Integer) return Integer%;`{@'^end
 Simple_Math;`{{The package^body~must contain the bodies of all 
the procedures and functions{declared in the package specificati
on:{}b[ 373B368]@&^package body Simple_Math is`{@*procedure Doub
le(Number : in Integer; Answer : out Integer)^is`{@*begin{@-Answ
er := Number * 2;{@*end Double;{{@*function Twice(Number : in In
teger) return Integer^is`{@*begin{@-return Number * 2;{@*end Twi
ce;{@&^end Simple_Math;`{{The package body could optionally decl
are either or both subprograms to be{%separate`:{{ ^package body
 Simple_Math is`{@%procedure Double(Number : in Integer; Answer 
: out Integer)^is separate;`{@%function Twice(Number : in Intege
r) return Integer^is separate;`{ ^end Simple_Math;`{{Here's an e
xample of a calling program that^with`s the package and makes us
e of{the two subprograms declared in the package specification:{
}b[ 374B372]@$^with Simple_Math; use Simple_Math;`{@%procedure P
ackage_Demo is{@(I, J : Integer := 10;{@%begin{@'^Double`(Number
 => I, Answer => J);  -- This line sets J to 20.{@(J :=^Twice`(I
);@5-- This line also sets J to 20.{@%end Package_Demo;{{The pac
kage specification must be compiled first, but either the callin
g{program or the package body may be compiled second.  The calli
ng program{depends only on the package^specification`, not the p
ackage^body`.  Similarly,{the package body depends on the packag
e specification.  If the package body{declares any subprograms t
o be^separate`, these must be compiled after the{package body, b
ecause any^separate~subprogram depends on its "parent."{{A packa
ge specification that declares no subprograms (only objects, typ
es,{etc.) doesn't need a package body.{{The main program may nev
er be inside a package.  It must be a procedure or{function comp
iled directly into the library, such as HELLO or ADD.  In most{i
mplementations of Ada, the main program can't have any parameter
s, and must be{a procedure rather than a function.{}b[ 375B373]A
 package body may optionally have initialization code, introduce
d by the word{%begin`.  This code is executed only once, the fir
st time another program{elaborates the package by^with`ing it.  
For example, this package uses{initialization code to initialize
 the array B:{{@/package P is{@2function F return Float;{@/end P
;{{@/package body P is{@2A : array(1 .. 10) of Float := (others 
=> 0.0);{@2B : array(1 .. 10, 1 .. 10) of Integer;{@2function F 
return Float is{@5...{@2end F;{@.^begin`{@1^for I in 1 .. 10 loo
p`{@4^for J in 1 .. 10 loop`{@7^B(I, J) := I*J*J;`{@4^end loop;`
{@1^end loop;`{@/end P;{}b[ 376B374]Declarations made inside a p
ackage^specification~are said to be^exported~and{are available t
o programs outside the package that^with~the package.  However,{
declarations made inside the package^body~are available only ins
ide the{package.  The package body doesn't even have to be writt
en before outside{programs that^with~the package.  In this examp
le, programs outside and inside{the package may use type Answer,
 array A, and procedure R, but only procedures{P, Q and R may us
e type Question and array B.  Procedure P may be called only{by 
Q and R (and itself), and procedure Q is available only to R (an
d itself).{{@6package X is{@9type Answer is (Yes, No, Maybe);{@9
A : array(1 .. 10) of Float;{@9procedure R;{@6end X;{{@6package 
body X is{@9type Question is (Why, Who, How);{@9B : array(1 .. 1
0) of Integer;{@9procedure P is separate;{@9procedure Q is separ
ate;{@9procedure R is separate;{@6end X;{}b[ 377B375]@6package X
 is{@9type Answer is (Yes, No, Maybe);{@9A : array(1 .. 10) of F
loat;{@9procedure R;{@6end X;{{@6package body X is{@9type Questi
on is (Why, Who, How);{@9B : array(1 .. 10) of Integer;{@9proced
ure P is separate;{@9procedure Q is separate;{@9procedure R is s
eparate;{@6end X;{{True or False?  In this example, procedure P 
may call R.{}Please press T for true or F for false, or B to go 
back.[T378F379B376]@6package X is{@9type Answer is (Yes, No, May
be);{@9A : array(1 .. 10) of Float;{@9procedure R;{@6end X;{{@6p
ackage body X is{@9type Question is (Why, Who, How);{@9B : array
(1 .. 10) of Integer;{@9procedure P is separate;{@9procedure Q i
s separate;{@9procedure R is separate;{@6end X;{{%You're right!~
 R is declared in the package specification, so any program{insi
de X (and any program outside X that^with`s the package) may cal
l R.{}q[ 380B377Q377]@6package X is{@9type Answer is (Yes, No, M
aybe);{@9A : array(1 .. 10) of Float;{@9procedure R;{@6end X;{{@
6package body X is{@9type Question is (Why, Who, How);{@9B : arr
ay(1 .. 10) of Integer;{@9procedure P is separate;{@9procedure Q
 is separate;{@9procedure R is separate;{@6end X;{{True.  R is d
eclared in the package specification, so any program inside X (a
nd{any program outside X that^with`s the package) may call R.{}q
[ 380B377Q377]@9FUNCTIONS WITH INFIX NOTATION{{@1^+@#-@#*@#/@#**
@#&@#=@#<@#>@#<=@#>=`{{@4^and@#or@#xor@#abs@#not@#mod@#rem`{{Ada
 allows us to overload any of the above operators by enclosing t
he operator{in quotes following the word^function`.  For example
, having defined type Date,{we may want to define what it means 
for one date to be "less than" another.  We{could write^function
 "<"(Left, Right : in Date) return Boolean;`.  Then, our{program
 could declare^D1, D2 : Date;~and test^D1 < D2`.  This test woul
d call{our function "<", because^<~is used between two objects o
f type Date.{Similarly, we can overload "*" to give the dot prod
uct of two vectors:{{@.type Vector is array(Integer range <>) of
 Float;{@.V1, V2 : Vector(1 .. 100);{@.X : Float;{@-^function "*
"(Left, Right : in Vector) return Float is`{@1...{@-^end "*";`{@
....{@-^X := V1 * V2;  -- This calls our function "*".`{}b[ 381B
377]@1^+@#-@#*@#/@#**@#&@#=@#<@#>@#<=@#>=`{{@4^and@#or@#xor@#abs
@#not@#mod@#rem`{{There are some restrictions when using infix n
otation.  First, all of the{operators above (except^abs`,^not`,^
+`, and^-`) must be used between two{expressions, and thus the f
unction specification must have exactly two{parameters.  Traditi
onally, the two parameters are called Left and Right.  The{opera
tors^abs~and^not~must have just one expression on the right, and
^+~and^-`{may have one expression on the right, or come between 
two expressions.  These{restrictions come from the way the compi
ler handles operators.  For example,{the compiler can handle^X :
= - X;`, but it's not designed to handle^X := * X;`.{{Second, in
 Ada 83 the function "=" must return type Boolean, its two param
eters{must be of the same type, and that type must be a limited 
private type, to be{discussed later.  For all the types discusse
d so far, function "=" is^already{defined~by Ada.  Two records a
re equal if all of their corresponding fields are{equal, and two
 arrays are equal if they have the same length and all of their{
corresponding elements are equal.{}b[ 382B380]@1^+@#-@#*@#/@#**@
#&@#=@#<@#>@#<=@#>=`{{@4^and@#or@#xor@#abs@#not@#mod@#rem`{{Note
 that in Ada 83 we can't redefine function "/=".  However, if we
 redefine{"=" for some limited private type, we can use^/=`.  Ad
a will call our function{"=" and negate the result.  For example
,{{@*type Text is limited private;  -- to be discussed later{@*T
1, T2 : Text;{@)^function "="(Left, Right : in Text) return Bool
ean is`{@-...{@)^end "=";`{@*...{@*if^T1 /= T2~then ^-- Calls ou
r "=" and reverses the result.`{@-...{@*end if;{{Also, we can't 
redefine^in`,^not in`,^and then`,^or else`, or^:=`.  Technically
,{these aren't operators.{}b[ 383B381]In Ada 9X, we may redefine
^=~to return any type, not just Boolean.  However, if{we do rede
fine^=~to return type Boolean, then we have automatically also{r
edefined^/=~to call our^=~and reverse the result.{{If, on the ot
her hand, we redefine^=~to return some type other than Boolean,{
then^/=~is^not~automatically redefined.  However, in this case A
da 9X lets us{separately redefine^/=~if we want to, and it may r
eturn any type.{}b[ 384B382]Finally, functions using infix notat
ion can't be compiled directly into the{library.  They must eith
er be declared locally inside a procedure or function,{or placed
 inside a package.  This is done because many implementations of
 Ada{create files with names based on the function, procedure, o
r package being{compiled.  Since many of the operators are punct
uation marks, they would create{file names that are illegal on m
ost systems.{{For the same reason, two functions or procedures w
ith the same name can't be{compiled directly into the library; o
n many systems that would attempt to give{the same name to two d
ifferent files.  For example, the package specification{below is
 legal.  However, the package body can't declare both Display's{
%separate`, and it can't declare either "*"^separate`.{{@+packag
e P is{@.type Complex is ...{@.type Vector is ...{@-^procedure D
isplay(C : in Complex);`{@-^procedure Display(V : in Vector);`{@
-^function  "*"(Left, Right : in Complex) return Complex;`{@-^fu
nction  "*"(Left, Right : in Vector)  return Float;`{@+end P;{}b
[ 385B383]@+package K is{@.type Complex is{@1record{@4Re, Im : F
loat;{@1end record;{@.type Vector is array(Integer range <>) of 
Float;{@.function  "+"(Left, Right : in Complex) return Complex;
{@.function  "*"(Left, Right : in Complex) return Complex;{@.fun
ction  "*"(Left, Right : in Vector)  return Float;{@.function  C
onjugate(C : in Complex) return Complex;{@.procedure Display(C :
 in Complex);{@.procedure Display(V : in Vector);{@+end K;{{The 
above is a package specification.  In the package body, how many
{subprograms could be made^separate`:  0, 1, 2, 3, 4, 5, or 6?{}
Please press 0, 1, 2, 3, 4, 5, or 6, or B to go back.[2386038713
873388438853886388B384]@'package^body~K is{@*function  "+"(Left,
 Right : in Complex) return Complex is ...{@*function  "*"(Left,
 Right : in Complex) return Complex is ...{@*function  "*"(Left,
 Right : in Vector)  return Float is ...{@)^function  Conjugate(
C : in Complex) return Complex is separate;`{@*procedure Display
(C : in Complex) is ...{@)^procedure Display(V : in Vector) is s
eparate;`{@'end K;{{@&^separate (K)`{@&^function Conjugate(C : i
n Complex) return Complex is`{@'...{@&^end Conjugate;`{{@&^separ
ate (K)`{@&^procedure Display(V : in Vector) is`{@'...{@&^end Di
splay;`{{%You're right!~ Only function Conjugate and at most one
 Display can be made{%separate`.  Functions using infix notation
 can't be made^separate`, and the name{Display is overloaded.{}q
[ 389B385Q385]@+package K is{@.type Complex is{@1record{@4Re, Im
 : Float;{@1end record;{@.type Vector is array(Integer range <>)
 of Float;{@.function  "+"(Left, Right : in Complex) return Comp
lex;{@.function  "*"(Left, Right : in Complex) return Complex;{@
.function  "*"(Left, Right : in Vector)  return Float;{@.functio
n  Conjugate(C : in Complex) return Complex;{@.procedure Display
(C : in Complex);{@.procedure Display(V : in Vector);{@+end K;{{
No, the function Conjugate can be made^separate`, because its na
me isn't{overloaded and it doesn't use infix notation.  Also, on
e, but not both, Display{procedures can be made^separate.`{}q[ 3
89B385Q385]@+package K is{@.type Complex is{@1record{@4Re, Im : 
Float;{@1end record;{@.type Vector is array(Integer range <>) of
 Float;{@.function  "+"(Left, Right : in Complex) return Complex
;{@.function  "*"(Left, Right : in Complex) return Complex;{@.fu
nction  "*"(Left, Right : in Vector)  return Float;{@.function  
Conjugate(C : in Complex) return Complex;{@.procedure Display(C 
: in Complex);{@.procedure Display(V : in Vector);{@+end K;{{No,
 only function Conjugate and at most one Display can be made^sep
arate`.{Functions using infix notation can't be made^separate`, 
and the name Display is{overloaded.{}q[ 389B385Q385]@7INFORMATIO
N HIDING: PRIVATE TYPES{{Information hiding has nothing to do wi
th secrecy; it means containing certain{programming details to a
 package so that the parts of the program outside the{package ca
n't depend on them.  Thus, when these details change, other part
s of{the program aren't affected.{{Let's write the specification
 (only) for a graphics CRT controller package{without informatio
n hiding.  Then we'll improve on it by using a private type.{{Th
e package will let us create arrays in memory representing scree
ns.  We can{create as many of these "virtual screens" as we like
, and draw dots, lines, and{boxes on them in memory.  We can als
o display any virtual screen.  Here's the{package specification:
{}b[ 390B385]%package CRT_Controller is`{  ^type Color_Type  is 
(White, Black, Red, Yellow, Green, Blue);`{  ^type Screen_Type i
s array(0 .. 299, 0 .. 399) of Color_Type;`{  ^type Point is`{@%
^record`{@(^Row@$: Integer range 0 .. 299;`{@(^Column : Integer 
range 0 .. 399;`{@%^end record;`{  ^procedure Display (Screen : 
in Screen_Type);`{  ^procedure Clear@#(Screen : in out Screen_Ty
pe; To: in Color_Type := Black);`{  ^procedure Dot@%(Screen : in
 out Screen_Type; Place : in Point;`{@5^Color : in Color_Type);`
{  ^procedure Line@$(Screen : in out Screen_Type; From, To : in 
Point;`{@5^Color : in Color_Type);`{ ^ procedure Box@%(Screen : 
in out Screen_Type; Corner1, Corner2 : in Point;`{@5^Color : in 
Color_Type);{end CRT_Controller;`{{This package assumes that the
 resolution of the CRT is 300 vertically by 400{horizontally.  A
 screen is represented in memory by a two-dimensional array,{eac
h element of which contains one of six possible colors.  Procedu
res to draw{other figures (circles, etc.) could have been added 
to the package.{}b[ 391B389]That package specification makes the
 calling program very clear!  For example,{{@#^with CRT_Controll
er; use CRT_Controller;`{@#^procedure CRT_Demo is`{@&^S1, S2 : S
creen_Type;`{@#^begin`{@&^Clear(S1);`{@&^Clear(S2, To => White);
`{@&^Line(S1, From => (150, 100), To => (150, 300), Color => Gre
en);`{@&^Dot(S1, Place => (150, 200), Color => Red);`{@&^Display
(S1);`{@&^Box(S2, Corner1 => (240, 100), Corner2 => (60, 300), C
olor => Blue);`{@&^Dot(S2, Place => (150, 200), Color => Yellow)
;`{@&^Display(S2);`{@#^end CRT_Demo;`{{The first executable line
 clears memory for screen S1 to all black, because of{the defaul
t parameter in the specification of Clear.  The next line clears
 S2{to all white.  The next three lines draw a line and a dot on
 S1 and display S1.{The program then draws a box and a dot on S2
 and displays S2.  Named notation{could optionally have been use
d for the first parameter of each call, and for{the objects of t
ype Point, e.g.,^(Row => 150, Column => 100)`.{}b[ 392B390]At a 
sacrifice in clarity (not recommended!), the calling program CRT
_Demo{could draw a dot in the center of screen S1 without callin
g Dot.  Which of the{following statements would accomplish the s
ame thing as{{@4Dot(S1, Place => (150, 200), Color => Red);{{{@0
1.  S1(150, 200) := Red;{{@02.  S1(Row => 150, Column => 200) :=
 Red;{{@03.  Either of the above would work.{}Please press 1, 2,
 or 3, or B to go back.[139323943394B391]@3^Dot(S1, Place => (15
0, 200), Color => Red);`{{{@/^1.  S1(150, 200) := Red;`{{@02.  S
1(Row => 150, Column => 200) := Red;{{@03.  Either of the above 
would work.{{{%You're right!~ At a sacrifice in clarity, the app
ropriate element of S1 can be{set directly to Red to draw a dot 
in the center of the screen.  Number 2 is{wrong because the name
s Row and Column apply to type Point, not to subscripts{of the a
rray.{}q[ 395B392Q392]@4Dot(S1, Place => (150, 200), Color => Re
d);{{{@01.  S1(150, 200) := Red;{{@02.  S1(Row => 150, Column =>
 200) := Red;{{@03.  Either of the above would work.{{{No, the n
ames Row and Column apply to type Point, not to subscripts of th
e{array.  For this reason number 2 won't compile.{}q[ 395B392Q39
2]Although the calling program is very clear, there's one disadv
antage that can{be eliminated by using a private type: if the re
solution of the screen is{changed, the calling program is affect
ed.  For example, the two calls to Dot{are each intended to draw
 a dot in the center of the screen.  These calls will{have to be
 changed when the resolution changes, or the dot will no longer 
be in{the center.  Also, nothing prevents CRT_Demo from saying^S
1(150, 200) := Red;`{directly, instead of calling Dot.  This is 
a disadvantage, because referencing{the elements of the array di
rectly makes CRT_Demo very susceptible to changes{in the package
.{{It would be better to force CRT_Demo to call our procedure Do
t, and make it{impossible for CRT_Demo to use the fact the a scr
een is represented by a{two-dimensional array.  Then the represe
ntation of a screen can change without{affecting the correctness
 of CRT_Demo.{{We'll improve our package specification and calli
ng program to make Screen_Type{a^private~type, so that its detai
ls can be used only inside the package.  Since{the screen resolu
tion won't be available outside the package, we'll normalize{Row
 and Column, making them floating point numbers in the range 0.0
 .. 1.0.{}b[ 396B392]Here's our improved package specification:{
{package CRT_Controller is{@#type Color_Type  is (White, Black, 
Red, Yellow, Green, Blue);{  ^type Screen_Type is private;`{@#ty
pe Point is{@&record{@)Row@$:^Float range 0.0 .. 1.0`;{@)Column 
:^Float range 0.0 .. 1.0`;{@&end record;{@#procedure Display (Sc
reen : in Screen_Type);{@#procedure Clear@#(Screen : in out Scre
en_Type; To: in Color_Type := Black);{@#procedure Dot@%(Screen :
 in out Screen_Type; Place : in Point;{@6Color : in Color_Type);
{@#procedure Line@$(Screen : in out Screen_Type; From, To : in P
oint;{@6Color : in Color_Type);{@#procedure Box@%(Screen : in ou
t Screen_Type; Corner1, Corner2 : in Point;{@6Color : in Color_T
ype);{%private`{  ^type Screen_Type is array(0 .. 299, 0 .. 399)
 of Color_Type;`{end CRT_Controller;{}b[ 397B395]@(package CRT_C
ontroller is{@+...{@*^type Screen_Type is private;`{@+procedure 
Display (Screen : in Screen_Type);{@+procedure Clear@#(Screen : 
in out Screen_Type; ... );{@+...{@'^private`{@*^type Screen_Type
 is array(0 .. 299, 0 .. 399) of Color_Type;`{@(end CRT_Controll
er;{{Outside the package, there are only four things a calling p
rogram may do with{objects of a private type like Screen_Type:{{
1. ^Create them:~ S1, S2 : Screen_Type;{{2. ^Assign them:~ S1 :=
 S2;{{3. ^Test them for equality and inequality:~ if S1 = S2 ...
@#if S1 /= S2 ...{{4. ^Use any procedures, functions, and infix 
operators provided by the package:`{@$Clear(S1);@#Display(S2);@#
etc.{}b[ 398B396]@'^With objects of a private type, outside the 
package we may only:`{^1.  Create@%2.  Assign@%3.  Test  =  /=@%
4.  Call package subprograms`{{Note that the calling program, ou
tside the package, can no longer say{%S1(150, 200) := Red;`, bec
ause that's not one of the four things listed above.{The calling
 program is forced to call Dot.  The information that Screen_Typ
e is{an array can be used by code only^inside~the package.  Of c
ourse, the^compiler`{uses this information when compiling code o
utside or inside the package.{That's why the definition of Scree
n_Type must be in the package specification,{not the body.  But 
the^programmer~isn't allowed to use this information outside{the
 package.{{%Inside~the package there are no such restrictions.  
To write the bodies of the{subprograms, we'll have to use the st
ructure of Screen_Type and write{statements similar to^S1(150, 2
00) := Red;`.{{Here's our calling program, revised to agree with
 the improved package{specification:{}b[ 399B397]@#with CRT_Cont
roller; use CRT_Controller;{@#procedure CRT_Demo is{@&S1, S2 : S
creen_Type;{@#begin{@&Clear(S1);{@&Clear(S2, To => White);{@&Lin
e(S1, From => (%0.5`,^0.25`), To => (%0.5`,^0.75`), Color => Gre
en);{@&Dot(S1, Place => (%0.5`,^0.5`), Color => Red);{@&Display(
S1);{@&Box(S2, Corner1 => (%0.8`,^0.25`), Corner2 => (%0.2`,^0.7
5`), Color => Blue);{@&Dot(S2, Place => (%0.5`,^0.5`), Color => 
Yellow);{@&Display(S2);{@#end CRT_Demo;{{Now, if a change is mad
e only to the private part of the package specification,{CRT_Dem
o won't have to be revised.  It^will~have to be recompiled, beca
use the{Ada compiler needs the information in the private part o
f the package{specification.  (The linker won't link with obsole
te units, but will tell us{what we must recompile.)  Also, the p
ackage body may have to be rewritten.  But{if CRT_Demo was corre
ct before, it will remain correct without any revision!{The effe
cts of the change are confined to the package.  Containing the e
ffects{of changes by means of information hiding is one of Ada's
 greatest features.{}b[ 400B398]True or False?  If the private p
art of a package specification is changed, the{calling program m
ust be recompiled before the package body is recompiled.{}Please
 press T for true or F for false, or B to go back.[F401T402B399]
%You're right!~ The package body and the calling program both de
pend on the{package specification, but not on each other.  They 
can be compiled in either{order after the package specification 
is compiled.{}q[ 403B400Q400]False.  The package body and the ca
lling program don't depend on each other,{but only on the packag
e specification.  Thus they can be compiled in either{order afte
r the package specification is compiled.{}q[ 403B400Q400]If a pa
ckage exports a constant of a private type, the constant is decl
ared in{the "public" part of the package specification, but it c
an't be assigned a{value until we get to the private part.  This
 is called a^deferred constant`.{For example,{{package CRT_Contr
oller is{@#type Color_Type  is (White, Black, Red, Yellow, Green
, Blue);{@#type Screen_Type is private;{  ^Flag_Of_Italy : const
ant Screen_Type;`{@#procedure Display (Screen : in Screen_Type);
{@#...{private{@#type Screen_Type is array(0 .. 299, 0 .. 399) o
f Color_Type;{  ^Flag_Of_Italy : constant Screen_Type :=`{@&^(ot
hers => (0 .. 132 => Green, 133 .. 266 => White, 267 .. 399 => R
ed));`{end CRT_Controller;{{CRT_Demo could then say^S1 := Flag_O
f_Italy;~or^Display(Flag_Of_Italy);`.{}b[ 404B400]@6TYPE TEXT AN
D LIMITED PRIVATE TYPES{{Earlier we remarked that Ada strings ar
e of fixed length.  Section 7.6 of the{Ada 83 LRM suggests that 
we create a type Text to get around this restriction.{Instead of
 declaring objects to be Strings, we'll declare them to be of ty
pe{Text, which will simulate variable-length strings.  Then we'l
l see how this{creates a need for limited private types.{{The su
ggestion for type Text isn't found in section 7.6 of the Ada 9X 
LRM,{because Ada 9X comes with several string handling packages 
not found in Ada 83.{Some of these are{{Fixed-Length String Hand
ling:@&Ada.Strings.Fixed{Bounded-Length String Handling:@$Ada.St
rings.Bounded{Unbounded-Length String Handling:  Ada.Strings.Unb
ounded{{All of these packages are described in Appendix C of the
 Ada 9X LRM.{{However, let us return to the problem of simulatin
g variable-length strings{with the type Text, as suggested in se
ction 7.6 of the Ada 83 LRM.{}b[ 405B403]The package specificati
on in section 7.6 of the Ada 83 LRM makes use of{discriminated r
ecords.  Since we haven't yet covered that topic, we'll give a{s
implified presentation here.  Let's declare{{@3^type Text is`{@6
^record`{@9^Len : Integer range 0 .. 80 := 0;`{@9^Val : String(1
 .. 80);`{@6^end record;`{{Any appropriate maximum length may be
 used in place of 80.  It isn't necessary{to initialize the Val 
field to all blanks, because the Len field keeps track of{how mu
ch of the Val field is significant.  The Len field is given a de
fault{value of 0, so that objects of type Text will be initializ
ed to zero length.{}b[ 406B404]@3^type Text is`{@6^record`{@9^Le
n : Integer range 0 .. 80 := 0;`{@9^Val : String(1 .. 80);`{@6^e
nd record;`{{For example, we could declare^T1 : Text;`.  We coul
d then set^T1.Len := 5;~and{%T1.Val(1 .. 5) := "Hello";`.  The f
act that the last 75 characters of T1.Val{might contain garbage 
is of no consequence, because T1.Len tells our program{to consid
er only the first 5 characters of T1.Val.  Since T1.Len is a var
iable,{we've simulated variable-length strings.{{A minor disadva
ntage is that, for each object of type Text, we reserve enough{m
emory for the longest possible length (80 in this example).  Dis
criminated{records, to be covered in the section on More Records
 and Types, can overcome{this disadvantage.{}b[ 407B405]Type Tex
t will be much easier to use if we write some subprograms.  Firs
t, we{need to convert between types Text and String.  Conversion
 in both directions{is very simple:{{@2^function Str(T : in Text
) return String is`{@2^begin`{@5^return T.Val(1 .. T.Len);`{@2^e
nd Str;`{{@2^function Txt(S : in String) return Text is`{@5^Answ
er : Text;`{@2^begin`{@5^Answer.Len := S'Length;`{@5^Answer.Val(
1 .. Answer.Len) := S;`{@5^return Answer;`{@2^end Txt;`{{Now we 
can write, for example,^T1 : Text := Txt("Hello");~and we don't 
even{have to count the characters of "Hello".  Later, the progra
m might execute{%T1 := Txt("Type Text is very convenient.");~sho
wing that T1 simulates a{variable-length string.  If we^with~and
^use~Text_IO in our program, we can{write^Put_Line(Str(T1));`.{}
b[ 408B406]It would be convenient to overload the^&~operator to 
concatenate two Texts, or{a Text with a String.  We can also ove
rload four of the relational operators:{{@%^function "&"  (Left,
 Right : in Text)@/return Text;`{@%^function "&"  (Left : in Tex
t;@#Right : in String) return Text;`{@%^function "&"  (Left : in
 String; Right : in Text)@#return Text;`{@%^function "<"  (Left,
 Right : in Text)@/return Boolean;`{@%^function ">"  (Left, Righ
t : in Text)@/return Boolean;`{@%^function "<=" (Left, Right : i
n Text)@/return Boolean;`{@%^function ">=" (Left, Right : in Tex
t)@/return Boolean;`{{The bodies of these subprograms are very s
imple!  For example:{{@,^function "&"(Left, Right : in Text) ret
urn Text is`{@,^begin`{@/^return Txt(Str(Left) & Str(Right));`{@
,^end "&";`{{@,^function "<"(Left, Right : in Text) return Boole
an is`{@,^begin`{@/^return Str(Left) < Str(Right);`{@,^end "<";`
{}b[ 409B407]@3function Txt(S : in String) return Text is{@6Answ
er : Text;{@3begin{@6Answer.Len := S'Length;{@6Answer.Val(1 .. A
nswer.Len) := S;{@6return Answer;{@3end Txt;{{{True or False?  A
 call to Txt with the null string,^Txt("")`, will raise a{Constr
aint_Error.{}Please press T for true or F for false, or B to go 
back.[F410T411B408]@2^function Txt(S : in String) return Text is
`{@5^Answer : Text;`{@2^begin`{@5^Answer.Len := S'Length;`{@5^An
swer.Val(1 .. Answer.Len) := S;`{@5^return Answer;`{@2^end Txt;`
{{{%You're right!~ The first executable statement will set Answe
r.Len to 0, and{the second executable statement will do nothing.
  The check for{Constraint_Error is suppressed when a null slice
 is involved.  Thus the{function will work correctly even for th
e null string.{}q[ 412B409Q409]@3function Txt(S : in String) ret
urn Text is{@6Answer : Text;{@3begin{@6Answer.Len := S'Length;{@
6Answer.Val(1 .. Answer.Len) := S;{@6return Answer;{@3end Txt;{{
{False.  The function will work correctly even for the null stri
ng.  The first{executable statement will set Answer.Len to 0, an
d the second executable{statement will do nothing.  The check fo
r Constraint_Error is suppressed when a{null slice is involved.{
}q[ 412B409Q409]@4type Text is{@7record{@:Len : Integer range 0 
.. 80 := 0;{@:Val : String(1 .. 80);{@7end record;{{There are tw
o problems with type Text.  The way Ada assigns arrays is less t
han{ideal when assigning objects of type Text, and the way Ada t
ests for equality{is totally unacceptable.  Suppose we have^T1, 
T2 : Text;~and then we execute{%T1 := Txt("Hello");~and then^T2 
:= T1;`.  In doing the assignment, Ada will{copy all 80 characte
rs of T1.Val, even though the last 75 characters contain{garbage
 and only the first 5 characters (and the Len field) need be cop
ied.{Perhaps we could live with this inefficiency, but Ada's tes
t for equality of{arrays creates a more serious problem.{{If we 
write^T1 := Txt("aaaaaaaaaa");~and^T2 := Txt("bbbbbbbbbb");~and 
then{%T1 := Txt("Hello");~and^T2 := Txt("Hello");`, Ada will say
 that T1 /= T2,{because it compares the entire Val fields:  T1.V
al(6 .. 10) is "aaaaa", but{T2.Val(6 . .10) is "bbbbb".  We want
 Ada to compare only the first 5 characters{of T1 and T2, as bot
h Len fields are 5.  We could modify function Txt (that{converts
 from String to Text) to pad the rest of the Val field with blan
ks, so{that the test for equality would be correct, but that wou
ld reduce efficiency.{}b[ 413B409]We could also try to get aroun
d this problem by writing our own function Equal:{{@/function Eq
ual(T1, T2 : in Text) return Boolean is{@/begin{@2return Str(T1)
 = Str(T2);{@/end Equal;{{This function would work, but we might
 forget to write^if Equal(T1, T2)~and{write^if T1 = T2~instead. 
 Similarly, we could write a procedure to assign{Texts efficient
ly, and forget to use it and write^T2 := T1;`.{{Ada 9X lets us w
rite a function "=" similar to the function above:{{@/function "
="(T1, T2 : in Text) return Boolean is{@/begin{@2return Str(T1) 
= Str(T2);{@/end "=";{{This gets around the problem that we migh
t forget to write^if Equal(T1, T2)~and{write "if T1 = T2" instea
d.  However, it doesn't solve the problem of assigning{Texts eff
iciently.  For this we need a^limited private~type.{}b[ 414B412]
Ada will prevent us from assigning Texts and testing them for eq
uality if we{create a package and make type Text^limited private
`.  Outside the package there{are only^two~things we may do with
 objects of a limited private type:{{1. ^Create them:~ T1, T2 : 
Text;{{2. ^Use any procedures, functions, and infix operators pr
ovided by the package:`{@$T1 & T2@#etc.{{We can't test for equal
ity and inequality unless the package includes a{function "=".  
Also, Ada won't let us write^T2 := T1;`, but the package could{p
rovide a procedure to assign Texts.  Here's our package specific
ation:{}b[ 415B413]@-package Text_Handler is{@/^type Text is lim
ited private;`{@0function Str(T : in Text) return String;{@0func
tion Txt(S : in String) return Text;{@0function "&"(Left, Right 
: in Text) return Text;{@0...{@/^function "="(Left, Right : in T
ext) return Boolean;`{@0function "<"(Left, Right : in Text) retu
rn Boolean;{@0...{@/^procedure Set(Target : in out Text; To : in
 Text);`{@,^private`{@0type Text is{@3record{@6Len : Integer ran
ge 0 .. 80 := 0;{@6Val : String(1 .. 80);{@3end record;{@-end Te
xt_Handler;{{Note that we write^type Text is limited private`, b
ut we still introduce the{private part of the package simply wit
h the word^private`.{{The two new subprograms are as easy to wri
te as the others:{}b[ 416B414]@,^function "="(Left, Right : in T
ext) return Boolean is`{@,^begin`{@/^return Str(Left) = Str(Righ
t);`{@,^end "=";`{{@,^procedure Set(Target : in out Text; To : i
n Text) is`{@,^begin`{@/^Target.Len := To.Len;`{@/^Target.Val(1 
.. Target.Len) := To.Val(1 .. To.Len);`{@,^end Set;`{{In summary
, we used^limited private~for type Text because Ada's definition
s of{equality and assignment weren't appropriate for that type, 
and we wanted to{provide our own definitions.  However, Ada's de
finitions^were~appropriate for{Screen_Type, so we made that a^pr
ivate~type to contain the effects of changes.{{In Ada 9X, the ch
oice between private and limited private should depend on{whethe
r we need to redefine assignment, not equality, because Ada 9X l
ets us{redefine "=" even if the type isn't limited private.{}b[ 
417B415]@+package Stacks is{@.type Stack is^?`{@.procedure Push 
(S : in out Stack; Item : in  Integer);{@.procedure Pop  (S : in
 out Stack; Item : out Integer);{@+private{@.type Ivector is arr
ay(Integer range <>) of Integer;{@.type Stack is{@1record{@4Sp :
 Integer range 1 .. 11 := 1;{@4St : Ivector(1 .. 10);{@1end reco
rd;{@+end Stacks;{{Suppose we want to write a package that lets 
us create objects of type Stack,{and Push and Pop integers on th
em.  The stacks will be last in, first out.{(For now, ignore the
 possibilities of stack underflow and overflow.)  Should{type St
ack be^private~or^limited private`?{{@31.  Type Stack should be^
private`.{{@32.  Type Stack should be^limited private`.{}Please 
press 1 or 2, or B to go back.[24181419B416]@+package Stacks is{
@-^type Stack is limited private;`{@.procedure Push (S : in out 
Stack; Item : in  Integer);{@.procedure Pop  (S : in out Stack; 
Item : out Integer);{@+private{@.type Ivector is array(Integer r
ange <>) of Integer;{@-^type Stack is`{@0^record`{@3^Sp : Intege
r range 1 .. 11 := 1;`{@3^St : Ivector(1 .. 10);`{@0^end record;
`{@+end Stacks;{{%You're right!~ Similar to type Text, only part
 of the array in type Stack (the{part up through Sp - 1) is sign
ificant; the rest contains garbage.  Thus, Ada's{test for equali
ty is unsatisfactory for the same reason.  Also, if we wanted to
{assign Stacks, we would want to copy only the significant part 
of the array,{not the whole array.  Therefore, type Stack should
 be^limited private`.{}q[ 420B417Q417]@+package Stacks is{@.type
 Stack is^?`{@.procedure Push (S : in out Stack; Item : in  Inte
ger);{@.procedure Pop  (S : in out Stack; Item : out Integer);{@
+private{@.type Ivector is array(Integer range <>) of Integer;{@
.type Stack is{@1record{@4Sp : Integer range 1 .. 11 := 1;{@4St 
: Ivector(1 .. 10);{@1end record;{@+end Stacks;{{No, type Stack 
is similar to type Text in that only part of the array (the part
{up through Sp - 1) is significant; the rest contains garbage.  
Thus, Ada's test{for equality is unsatisfactory for the same rea
son.  Also, if we wanted to{assign Stacks, we would want to copy
 only the significant part of the array,{not the whole array.  T
herefore, type Stack should be^limited private`.{}q[ 420B417Q417
]@<HIERARCHICAL LIBRARIES{{Earlier we considered a package CRT_C
ontroller that had procedures to draw{dots, lines, and boxes.  S
uppose that we have compiled that package and several{calling pr
ograms, and then we wish to add a procedure to draw a circle.  I
f we{add the procedure directly to CRT_Controller, we'll have to
 recompile{CRT_Controller, and, as a result, all of the previous
ly written calling{programs, because these^with~the package.  Th
is is true even though the{previously written calling programs d
on't call the new procedure to draw a{circle.{{In Ada 9X, we can
 write a^child package~to get around this problem.  Its name{is 
CRT_Controller followed by a dot and another name, for example,{
%CRT_Controller.More`.  This package must be compiled after the 
specification of{the parent, CRT_Controller.  We do not change o
r recompile CRT_Controller.{Instead, we put our new routines, su
ch as Circle, in CRT_Controller.More and{compile it.{}b[ 421B417
]Now the previously written calling programs that^with~CRT_Contr
oller don't have{to be recompiled.  The new programs, that can c
all Circle (as well as Dot,{Line, Box, etc.) should say^with CRT
_Controller.More;`.  This automatically does{%With CRT_Controlle
r;~as well, so we don't need that second^with~statement.{However
, if we want to^use~both the parent package and the child packag
e, we{must supply both^use~statements:^use CRT_Controller; use C
RT_Controller.More;`.{{Our new Ada 9X child package specificatio
n will look like this:{{@8package^CRT_Controller.More~is{@;...{@
;procedure Circle ... ;{@;...{@8end CRT_Controller;{{A parent pa
ckage can have several children, and the children can have child
ren,{to any depth.  Also, a child can be a subprogram (procedure
 or function) as{well as a package.  Finally, the child package 
could have been made private to{its parent if we had begun with{
{@3^private~package CRT_Controller.More is{}b[ 422B420]@;^ADA-TU
TR COURSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{
{@#The Format of an Ada Program@-Subprograms and Packages`{{@#Ge
neric Instantiation and@,^>  ACCESS TYPES, USER DEFINED TYPES,`{
@&Assignment 1@<^AND DERIVED TYPES`{{@#Simple Declarations and S
imple@+Exceptions, Text_IO, and{@&Attributes@?Assignment 5{{@#Op
erators, Control Constructs, and@'Generics, Tasking, and Assignm
ent 6{@&Assignment 2{@LMore Records and Types{@#Records, Arrays,
 and Assignment 3{@LAdvanced Topics{}b[ 423B421]@BACCESS TYPES{{
Access types are sometimes called "pointers" in other languages.
  However, the{name "pointer" fell into disrepute, because of "d
angling reference" problems.{With Ada's access types, dangling r
eferences are impossible, unless we{deliberately instantiate Unc
hecked_Deallocation (discussed in the Advanced{Topics section) o
r use the Ada 9X attribute 'Unchecked_Access (discussed later{in
 this section).  So Ada uses the reserved word^access`.{{If we d
efine type Date as before, and write^USA : Date;~then USA has th
ree{fields: Day, Month, and Year.  However, if we write{{@<^type
 P is access Date;`{@<^D1, D2 : P;`{{then D1 and D2 are capable 
of^pointing to~objects of type Date.  In most{implementations of
 Ada, this means that D1 and D2 can each contain the machine{add
ress of the start of a record of type Date.  However, this detai
l depends on{the implementation of Ada.  D1 and D2 themselves do
n't have fields, but the{objects they can point to have fields.{
}b[ 424B422]@<^type P is access Date;`{@<^D1, D2 : P;`{{At prese
nt D1 and D2 point to nothing.  However, if we execute^D1 := new
 Date;`,{then, at run time, enough memory for one record of type
 Date is allocated, and{D1 is made to point to it.  This new obj
ect of type Date doesn't have a name;{only the pointer, D1, has 
a name.  By contrast, when we elaborate^USA : Date;`{we create a
n object that has a name (USA), but nothing can point to it.{{We
 can refer to the fields of the nameless object pointed to by D1
 as if D1{itself had fields.  Thus, we can write D1.Day, D1.Mont
h, and D1.Year, and use{these on either side of an assignment:^D
1.Day := 12;`.  The entire object{pointed to by D1 is^D1.all`, s
o we could write^D1.all := (12, Oct, 1492);`.  Note{that^D1.Day~
is simply an abbreviation for^D1.all.Day`.  Similarly, if A1 poi
nts{to an array rather than a record, then^A1.all(5)~may be abbr
eviated^A1(5)`.{{We can execute^D2 := new Date'(4, Jul, 1776);~g
iving the new object a value{when it's created.  We can also dec
lare^D3 : P := new Date;~to make D3 point to{an object when D3 i
s created, or even write^D3 : P := new Date'(4, Jul, 1776);`{to 
make D3 point to an object and also give the object a value.{}b[
 425B423]We can write^D3 := null;~to make D3 point nowhere.  Whe
n a pointer is declared{and no initialization is shown, it's aut
omatically initialized to^null`, so{%D4 : P;~means^D4 : P := nul
l;`.  When a pointer is null, trying to reference the{object poi
nted to (%D4.Day~or^D4.all`, etc.) will raise a Constraint_Error
.  We{can test to see if a pointer is null:^if D4 = null then~..
.^end if;`.{{Copying a pointer isn't the same as copying the obj
ect pointed to.  If we{execute^D1.all := (12, Oct, 1492);~and th
en^D2.all := D1.all;`, the entire{record is copied.  If we chang
e D1.Day with^D1.Day := 13;`, D2.Day is still 12.{{However, is w
e execute^D1.all := (12, Oct, 1492);~and then^D2 := D1;`, then t
he{address in D1 is copied to D2, so that D2 now points to the s
ame place as D1.{Thus, if we change D1.Day with^D1.Day := 13;`, 
then D2.Day is also 13, because{it references the same memory lo
cation.{{If we have^D1 := new Date'(12, Oct, 1492);~and^D2 := ne
w Date'(4, Jul, 1776);`{and then execute^D2 := D1;`, D2 now poin
ts where D1 points, and nothing any{longer points to the object 
containing (4, Jul, 1776).  Most systems cannot{automatically re
claim the memory occupied by that object.  In the Advanced{Topic
s section, we'll learn to use Unchecked_Deallocation to release 
the memory{pointed to by D2 before we execute^D2 := D1;`.{}b[ 42
6B424]In Ada 9X, it's possible to point to an object that has a 
name.  If we declare{{@5type P is access^all~Date;{@5USA :^alias
ed~Date := (4, Jul, 1776);{@5D1  : P;{{then we can make D1 point
 to USA by executing^D1 := USA'Access;`.  We can now{refer to D1
.Day, D1.Month, and D1.Year as well as USA.Day, USA.Month, and{U
SA.Year.  If we change the first declaration above to{{@8type P 
is access^constant~Date;{{and then declare USA and D1 as above, 
and execute^D1 := USA'Access;`, then D1{has read-only access to 
USA.  That is, we can read, but not store into, D1.Day,{D1.Month
, and D1.Year (as well as the whole record D1).  We can still re
ad and{store into USA.Day, USA.Month, USA.Year, and the whole re
cord USA.  If we want{to prevent ourselves from storing directly
 into USA, we can write{{@0USA :^aliased constant~Date := (4, Ju
l, 1776);{{We can still execute^D1 := USA'Access;`, but now we c
an't update USA either{directly or through D1; we can only read 
it.{}b[ 427B425]The^'Access~attribute in Ada 9X performs an^acce
ssibility check~to assure that{the lifetime of the object pointe
d to is at least as long as the lifetime of{the access type.  Th
is eliminates the danger of dangling references, that is,{pointi
ng to an object that no longer exists in memory.  For example, t
he{highlighted line below is illegal and will be caught by the c
ompiler:{{  package Schedule is@.with Schedule; use Schedule;{@%
type Date is ...;@-procedure Test is{@%type P is access all Date
;@'Today : aliased Date;{@%...@=^T@%: P := Today'Access; -- ille
gal`{  end Schedule;@4begin{@F...{@Cend Test;{{The highlighted l
ine is illegal because^T~could be stored in a global variable{(s
ome variable declared outside the procedure^Test`), or be passed
 to another{routine.  Procedure^Test~could then reach its end, c
ausing^Today~to cease to{exist, because^Today~is declared inside
^Test`.  But the copy of^T~could still{exist, and it would then 
point to an object that no longer exists in memory,{with unpredi
ctable results.  Ada guards against the dangling reference probl
em{that plagues some other languages.{}b[ 428B426]However, Ada l
ets us get around the accessibility check if we want to.  The{pr
evious example becomes legal if we replace^Today'Access~with{%To
day'Unchecked_Access`:{{package Schedule is@,with Schedule; use 
Schedule;{@#type Date is ...;@+procedure Test is{@#type P is acc
ess all Date;@%Today : aliased Date;{@#...@;^T@%: P := Today'Unc
hecked_Access; -- legal`{end Schedule;@2begin{@B...{@?end Test;{
{In this case, the programmer must be very careful to assure tha
t no copies of^T`{are ever referenced when the object pointed to
 (%Today`) has gone out of{existence.{{We'll discuss accessibili
ty checks further when we talk about access parameters{in the se
ction on More Records and Types.{}b[ 429B427]Access types are es
pecially useful for creating^linked lists`.  A simple linked{lis
t can be thought of as a chain.  Each link contains some useful 
data{(perhaps an integer, perhaps pages of information), and a p
ointer to the next{item in the chain.  There's also a pointer, u
sually called Head, that points to{the first link in the chain. 
 The last link points nowhere.{{A linked list of integers might 
look something like this:{@'^ ____@'__________@*__________@*____
______ `{@'^|  --|---->| Int@#10 |@#,--->| Int@#27 |@#,--->| Int
@#34 |`{@'^|____|@%| Next  ---|---'@$| Next  ---|---'@$| Next nu
ll|`{@'^ Head@&|__________|@(|__________|@(|__________|`{{To add
 another integer to the chain, keeping the integers in ascending
 order,{we simply break the chain at the appropriate point and i
nsert another link.{{To set up our linked list, we'd like to wri
te^type P is access Link;~and write{{@<^type Link is`{@?^record`
{@B^Int  : Integer;`{@B^Next : P;`{@?^end record;`{}b[ 430B428]H
owever, the declaration of type P involves Link, and the declara
tion of type{Link involves P, so neither declaration can come fi
rst!  Ada provides a special{means of solving this problem.  We 
can write{{@<^type Link;`{@<^type P is access Link;`{@<^type Lin
k is`{@?^record`{@B^Int  : Integer;`{@B^Next : P;`{@?^end record
;`{{The first line is called an^incomplete type declaration`.  I
t simply tells the{compiler that type Link exists.  That's all t
he information the compiler needs{to compile the second line.  T
he second line tells the compiler that objects of{type P will co
ntain pointers, but for this line the compiler doesn't need to{k
now details of the objects pointed to.  The second line must be 
followed by{the full declaration of type Link.{}b[ 431B429]@4typ
e Person is{@7record{@:Name : String(1 .. 10);{@:Age  : Natural;
{@7end record;{@4type P is access Person;{@4P1 : P := new Person
'("Susan@%", 21);{@4P2 : P := new Person'("John@&", 35);{@4...{@
4P2 := P1;{@4P1.Age := 22;{{{@?What is P2.Age?{{@?1.  P2.Age is 
21.{{@?2.  P2.Age is 22.{{@?3.  P2.Age is 35.{}Please press 1, 2
, or 3, or B to go back.[243214333433B430]@4type Person is{@7rec
ord{@:Name : String(1 .. 10);{@:Age  : Natural;{@7end record;{@4
type P is access Person;{@4P1 : P := new Person'("Susan@%", 21);
{@4P2 : P := new Person'("John@&", 35);{@4...{@4P2 := P1;{@4P1.A
ge := 22;{{{%You're right!~ The last line changed P1.Age to 22. 
 Since the previous line{made P2 point where P1 points, P2.Age i
s also 22.{}q[ 434B431Q431]@4type Person is{@7record{@:Name : St
ring(1 .. 10);{@:Age  : Natural;{@7end record;{@4type P is acces
s Person;{@4P1 : P := new Person'("Susan@%", 21);{@4P2 : P := ne
w Person'("John@&", 35);{@4...{@4P2 := P1;{@4P1.Age := 22;{{{No,
 the last line changed P1.Age to 22.  Since the previous line ma
de P2 point{where P1 points, P2.Age is also 22.{}q[ 434B431Q431]
Let's use an access type to write a program that gets integers i
n random order{from the keyboard, maintaining a linked list of t
hem.  When^0~is input, the{program outputs the integers in ascen
ding order.  This program will be a good{stepping-stone to Outsi
de Assignment 5.  To simplify inserting an integer into{the link
ed list, Head will point to an unused Link, which will in turn p
oint to{the first actual link in the chain:{{% ____@&__________@
)__________@)__________@)__________{|  --|--->| Int@&|@#,-->| In
t@#10 |@#,-->| Int@#27 |@#,-->| Int@#34 |{|____|@$| Next  ---|--
-'@#| Next  ---|---'@#| Next  ---|---'@#| Next null|{ Head@%|___
_______|@'|__________|@'|__________|@'|__________|`{{We could cr
eate our linked list using arrays rather than an access type.{Ho
wever, we'd have to specify the size of the arrays, placing a li
mit on the{number of integers the program can handle.  With the 
access type, the only{limit is the amount of available memory.  
We'll be able to move our program to{a larger machine to increas
e this limit, without changing any code - not even{one line to s
pecify the size of an array.{{Here's our program ...{}b[ 435B431
]@(with Text_IO; use Text_IO;{@(procedure LL_Demo is{@+package M
y_Int_IO is new Integer_IO(Integer); use My_Int_IO;{@+type Link;
{@+type P is access Link;{@+type Link is{@.record{@1Int  : Integ
er;{@1Next : P;{@.end record;{@*^Head : P := new Link;`{@*^I@$: 
Integer;`{@*^procedure Add_I_To_Linked_List is separate;`{@*^pro
cedure Display_Linked_List is separate;`{@(begin{@*^Put("Type an
 integer: ");  Get(I);  Skip_Line;`{@*^while I /= 0 loop`{@-^Add
_I_To_Linked_List;`{@-^Put("Type an integer: ");  Get(I);  Skip_
Line;`{@*^end loop;`{@*^Display_Linked_List;`{@(end LL_Demo;{}b[
 436B434]^separate (LL_Demo)`{^procedure Display_Linked_List is`
{@#^Tmp : P := Head.Next;@*-- Skip unused link at the head of th
e list.`{^begin`{@#^while Tmp /= null loop`{@&^Put(Tmp.Int);  Ne
w_Line;@)-- Display integer in the current link.`{@&^Tmp := Tmp.
Next;@9-- Go to next link in the list.`{@#^end loop;`{^end Displ
ay_Linked_List;`{{^separate (LL_Demo)`{^procedure Add_I_To_Linke
d_List is`{@#^Tmp : P := Head;@'-- Begin search of where to inse
rt at start of list.`{^begin`{@#^while Tmp /= null and then Tmp.
Next /= null and then Tmp.Next.Int < I loop`{@&^Tmp := Tmp.Next;
  -- Note use of "and then" to avoid trying to reference`{@#^end
 loop;@,-- the object pointed to when the pointer is null.`{@#^T
mp.Next := new Link'(I, Tmp.Next);  -- Create new link and inser
t in list.`{^end Add_I_To_Linked_List;`{{The best way to follow 
these two subprograms is to draw a linked list on a{piece of scr
ap paper and "hand execute" the subprograms.{}b[ 437B435]@3type 
Link; ^-- 1`{@3type P is access Link;{@3type Link is{@6record{@9
F : Float; ^-- 2`{@9S : String(1 .. 10); ^-- 3`{@9A : array(1 ..
 10) of Integer; ^-- 4`{@6end record;{@3L1 : Link; ^-- 5`{@3P1 :
 P;{{Which commented line in the above is^illegal`?{}Please pres
s 1, 2, 3, 4, or 5, or B to go back.[44381439244034415442B436]@3
type Link;  -- 1{@3type P is access Link;{@3type Link is{@6recor
d{@9F : Float;  -- 2{@9S : String(1 .. 10);  -- 3{@8^A : array(1
 .. 10) of Integer;  -- 4`{@6end record;{@3L1 : Link;  -- 5{@3P1
 : P;{{{%You're right!~ Inside a record definition, the name of 
a field must be{followed by a type name, not^array`.  We would f
irst have to say something like{%type List is array(Integer rang
e <>) of Integer;`, and then change the field{definition to{{@8^
A : List(1 .. 10);`{}q[ 443B437Q437]@3type Link;  -- 1{@3type P 
is access Link;{@3type Link is{@6record{@9F : Float;  -- 2{@9S :
 String(1 .. 10);  -- 3{@9A : array(1 .. 10) of Integer;  -- 4{@
6end record;{@3L1 : Link;  -- 5{@3P1 : P;{{{No, the first line i
s legal.  Ada allows an incomplete type declaration to{precede t
he declaration of an access type, provided the complete type{dec
laration follows.{}q[ 443B437Q437]@3type Link;  -- 1{@3type P is
 access Link;{@3type Link is{@6record{@9F : Float;  -- 2{@9S : S
tring(1 .. 10);  -- 3{@9A : array(1 .. 10) of Integer;  -- 4{@6e
nd record;{@3L1 : Link;  -- 5{@3P1 : P;{{{No, the declaration of
 F inside the record definition is legal, because Ada{records ma
y contain fields of any type.{}q[ 443B437Q437]@3type Link;  -- 1
{@3type P is access Link;{@3type Link is{@6record{@9F : Float;  
-- 2{@9S : String(1 .. 10);  -- 3{@9A : array(1 .. 10) of Intege
r;  -- 4{@6end record;{@3L1 : Link;  -- 5{@3P1 : P;{{{No, the de
claration of S inside the record definition is legal, because Ad
a{records may contain fields of any type.{}q[ 443B437Q437]@3type
 Link;  -- 1{@3type P is access Link;{@3type Link is{@6record{@9
F : Float;  -- 2{@9S : String(1 .. 10);  -- 3{@9A : array(1 .. 1
0) of Integer;  -- 4{@6end record;{@3L1 : Link;  -- 5{@3P1 : P;{
{{No, the declaration of L1 as type Link is legal.  Even though 
type P was{declared to be^access Link~and we ordinarily would de
clare objects to be of{type P, we may also directly declare obje
cts to be of type Link.  Of course,{nothing can point to such ob
jects.{}q[ 443B437Q437]In Ada 9X an access type can access a sub
program.  Thus, the system can decide{%at run time~which of seve
ral subprograms to call.  This is called^Dynamic{Selection`.  Fo
r example:{{@$package P is{@&^type Int_Function is access functi
on(X : in Integer) return Integer;`{@'F : array(1 .. 2) of Int_F
unction;{@'function Square(X : in Integer) return Integer;{@'fun
ction Cube(X : in Integer) return Integer;{@$end P;{{@$with P; u
se P;{@$procedure Dynamic_Selection_Demo is{@'X, Y : Integer;{@$
begin{@'F(1) := Square'Access;{@'F(2) := Cube'Access;{@'X := 3;{
@'for I in 1 ..2 loop{@)^Y := F(I)(X); -- Decides at run time wh
ich function to call.`{@'end loop;{@$end Dynamic_Selection_Demo;
{}b[ 444B437]@'F(1) := Square'Access;{@'F(2) := Cube'Access;{@'X
 := 3;{@'for I in 1 ..2 loop{@)^Y := F(I)(X); -- Decides at run 
time which function to call.`{@'end loop;{{Note that^F(I)(X)~is 
simply an abbreviation for^F(I).all(X)`.  The first time{through
 the loop, the highlighted line above will call the function Squ
are and{set Y to 9; the second time through the loop the same li
ne will call Cube and{set Y to 27.{{In the section on More Recor
ds and Types, under Tagged Records and Dynamic{Dispatching, we'l
l learn another way to make an Ada 9X system decide at run{time 
which of several subprograms to call.{}b[ 445B443]In Ada 9X, poi
nters to subprograms may also be used as parameters ("dummy{argu
ments") of other subprograms. For example:{{@3procedure Demo (%F
cn : in Int_Function`) is{@6X, Y : Integer;{@3begin{@6...{@6Y :=
 Fcn(X);{@6...{@3end Demo;{{If F(1) was set to Square'Access, we
 could then call Demo with^Demo(F(1));`, and{Demo would set Y to
 Square(X).  If F(2) is Cube'Access and we call^Demo(F(2));`,{De
mo then sets Y to Cube(X).  When Demo calls function Square or f
unction Cube,{this action is called^call back`.{}b[ 446B444]@7US
ER DEFINED TYPES AND PORTABILITY{{In some implementations of Ada
, Integers are represented by 32-bit two's{complement numbers, g
iving the range -2_147_483_648 .. 2_147_483_647.  Other{implemen
tations use 16-bit two's complement Integers, giving the range{-
32768 .. 32767.  However, some of the 16-bit implementations als
o provide a{32-bit type called Long_Integer.{{Suppose we need a 
variable called Number to count from zero to one million.  We{co
uld declare^Number: Integer;~for the 32-bit implementation, and 
change this{to^Number : Long_Integer;~when we port the program t
o a machine running a{16-bit version that provides Long_Integer.
  However, we could also declare{{@4^type Counter is range 0 .. 
1_000_000;`{@4^Number : Counter;`{{and both implementations of A
da will automatically select the appropriate{internal representa
tion for our type Counter!  The 32-bit Ada will select{Integer, 
and the 16-bit Ada will select Long_Integer.  This gives us the{
advantage that no code has to be changed when the program is por
ted.  Counter{is called a^user-defined type`.  Of course, we mus
t use explicit type{conversion to mix objects of type Counter wi
th objects of other types.{}b[ 447B445]Similarly, different impl
ementations of Ada provide different representations{for type Fl
oat, and some provide a type Long_Float.  We can declare{{@<^typ
e Real is digits 8;`{@<^F : Real;`{{and be certain that F will h
ave at least 8 digits of accuracy on any machine{that accepts th
is type declaration.  A range constraint is optional.{{User defi
ned types also apply to fixed point numbers; these will be discu
ssed{in the section on More Records and Types.{{It's possible to
 make a declaration that will be accepted by only some{implement
ations of Ada.  For example, if we declare{{@3^type X is digits 
30 range 0.0 .. 100.0;`{{some implementations of Ada might have 
to report that there's no available type{that gives at least 30 
digits of accuracy.{{No language can give perfectly portable pro
grams, but Ada truly advanced the{state of the art in portabilit
y.{}b[ 448B446]@ADERIVED TYPES{{Derived types are created to pre
vent accidental mixing of objects.  Unlike{subtypes, derived typ
es are distinct types.  For example,{{@.^type No_Of_Apples  is n
ew Integer;`{@.^type No_Of_Oranges is new Integer range 0 .. 100
;`{@.^NOA : No_Of_Apples;`{@.^NOO : No_Of_Oranges;`{@.^I@#: Inte
ger;`{@/...{@.^NOA := NOA + NOO;  -- illegal`{@.^NOA := NOA + NO
A;`{@.^NOA := NOA + I;  -- illegal`{@.^NOA := NOA + No_Of_Apples
(I);`{@.^NOA := NOA + No_Of_Apples(NOO);`{{A derived type is den
oted by the reserved word^new~followed by an existing type{like 
Integer.  The operations that Ada knows for Integers, such as ad
dition,{are "inherited" by the derived types so that, for exampl
e, Ada knows how to add{two objects of type No_Of_Oranges.  As t
he examples above show, we can't mix{types accidentally, but we 
can deliberately mix them by converting first.{}b[ 449B447]In su
mmary,{{{@*^Subtypes~are usually created to provide range constr
aints:{{@0^subtype Day_Subtype is Integer range 1 .. 31;`{{{@'^D
erived types~are usually created to prevent accidental mixing:{{
@3^type No_Of_Apples  is new Integer;`{@3^type No_Of_Oranges is 
new Integer~...^;`{{{@)^User-defined types~are usually created t
o gain portability:{{@4^type Counter is range 0 .. 1_000_000;`{@
4^type Real@$is digits 8;`{}b[ 450B448] type Meters@,is new Floa
t;{ type Seconds@+is new Float;{ type Meters_Per_Second is new F
loat;{ ...{ function "*"(Left : in Meters_Per_Second; Right : in
 Seconds) return Meters is{ begin{@$return Meters(Left) * Meters
(Right);{ end "*";{ function "*"(Left : in Seconds; Right : in M
eters_Per_Second) return Meters is{ begin{@$return Right * Left;
{ end "*";{ function "/"(Left : in Meters; Right : in Seconds) r
eturn Meters_Per_Second is{ begin{@$return Meters_Per_Second(Lef
t) / Meters_Per_Second(Right);{ end "/";{{@1The above program se
gment is an example of ...{@11.  derived types.{@12.  user-defin
ed types.{@13.  subtypes.{}Please press 1, 2, or 3, or B to go b
ack.[145124523453B449] type Meters@,is^new~Float;{ type Seconds@
+is^new~Float;{ type Meters_Per_Second is^new~Float;{{{%You're r
ight!~ The reserved word^new~in the segment above tells us that 
we're{defining derived types.{}q[ 454B450Q450] type Meters@,is n
ew Float;{ type Seconds@+is new Float;{ type Meters_Per_Second i
s new Float;{{{No, examples of user-defined types are{{@5type Co
unter is range 0 .. 1_000_000;{@5type Real@$is digits 8;{}q[ 454
B450Q450] type Meters@,is new Float;{ type Seconds@+is new Float
;{ type Meters_Per_Second is new Float;{{{No, subtypes are usual
ly created to provide range constraints.{}q[ 454B450Q450]@;^ADA-
TUTR COURSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 
4{{@#The Format of an Ada Program@-Subprograms and Packages`{{@#
Generic Instantiation and@0Access Types, User Defined Types,{@&A
ssignment 1@=and Derived Types{{@#Simple Declarations and Simple
@'^>  EXCEPTIONS, TEXT_IO, AND`{@&Attributes@>^ASSIGNMENT 5`{{@#
Operators, Control Constructs, and@'Generics, Tasking, and Assig
nment 6{@&Assignment 2{@LMore Records and Types{@#Records, Array
s, and Assignment 3{@LAdvanced Topics{}b[ 455B450]@CEXCEPTIONS{{
When an error occurs during the elaboration or execution of a st
atement, Ada is{said to^raise an exception`.  Ordinarily this st
ops the program, but Ada{programs can trap exceptions and execut
e a special block of code when one{occurs.  This code is called 
an^exception handler`.{{We can define our own exceptions, but fi
ve of them are predefined by Ada:{{%Constraint_Error`{@%This is 
the exception encountered most often by beginners, because it ca
n{be caused by a number of different things.  It can be raised b
y a subscript out{of range, a subtype out of range (USA.Day := 3
2;), an attribute used improperly{(Integer'Value("12X3") or Mont
h_Type'Val(13)), assigning an array of one length{to a destinati
on of another (H : String(1 .. 5) := "Hi";), or by attempting to
{access an object with a null pointer.{{%Numeric_Error`{@%Many i
mplementations of Ada raise this on an arithmetic overflow or an
{attempt to divide by zero.  The newest implementations of Ada r
aise{Constraint_Error instead.  (In Ada 9X, Numeric_Error merely
 renames{Constraint_Error.){}b[ 456B454]%Program_Error`{@%This i
s rarely encountered by beginners, but it can be raised by skipp
ing{around the^return~statement in a function and running into t
he^end~statement.{{%Storage_Error`{@%This is raised by running o
ut of memory, as with a recursive program{calling itself uncondi
tionally or an attempt to create an infinitely large{linked list
.{{%Tasking_Error`{@%This will be discussed in the section on Ta
sking.{{An exception handler is introduced by the reserved word^
exception`; its{structure is similar to that of a^case~construct
.  We'll see an example in a{moment.  Unlike a^case~construct, a
n exception handler need not account for all{the possibilities.{
{An exception handler can be placed in a subprogram, in the init
ialization code{of a package, in a task (to be discussed in the 
section on Tasking), or in a{block (to be discussed later in thi
s section).  Here's a procedure with an{exception handler that h
andles an exception,^Wrong`, that we declare ourselves,{as well 
as the built-in exceptions^Constraint_Error~and^Numeric_Error`:{
}b[ 457B455] with Text_IO; use Text_IO;{ procedure Exception_Dem
o is{@$package My_Int_IO is new Integer_IO(Integer); use My_Int_
IO;{@$I@%: Integer;{@#^Wrong : exception;`{ begin{@$loop{@'New_L
ine(2);  Put("Type a positive integer. ");  Get(I);  Skip_Line;{
@'if I <= 0 then{@)^raise Wrong;`{@'end if;{@'Put("The square is
 ... ");{@&^Put(I*I); -- Raises Constraint_Error or Numeric_Erro
r if I is too large.`{@$end loop;{^exception`{@#^when Constraint
_Error | Numeric_Error =>`{@'Put(" ... too big.");{@#^when Wrong
 =>`{@'New_Line;{@'Put("I said Positive integer!");{ end Excepti
on_Demo;{}b[ 458B456]We can deliberately raise an exception (eit
her user-defined or built-in) with{the^raise~statement, as in^ra
ise Wrong;~or^raise Constraint_Error;`.  Also,{ordinary statemen
ts can raise exceptions.  In our sample program,^Put(I*I);`{rais
es Constraint_Error or Numeric_Error if I is too large.  When an
 executable{statement raises an exception, the exception handler
 is executed^instead of~the{rest of the procedure, function, etc
.  Our program keeps asking for integers{and displaying their sq
uares until an exception is raised.  Then, the exception{handler
 is executed, and there's no way to get back into the procedure 
to ask{for another integer (short of a recursive call).  Even a^
goto~from the{exception handler to the main part of the procedur
e is forbidden.  Soon we'll{show how the block construct can ove
rcome this problem, so that our program{will continue to ask for
 more integers even after an exception is handled.{{As with^case
~constructs, an exception handler may use the vertical bar to{de
note multiple choices (%when Constraint_Error | Numeric_Error =>
~block of{code), and it may say^when others =>~to handle all cas
es not covered earlier.{But there's no way to test, inside the e
xception handler,^which line~raised the{exception.  We can only 
test^which kind~of exception was raised.{{Don't use exceptions w
here a simple^if~will do.  In our program, trapping the{arithmet
ic overflow was OK, but the^if~could have handled I <= 0 without
{raising Wrong.  This exception was declared only to give a simp
le example.{}b[ 459B457]@>1.  Constraint_Error{{@>2.  Numeric_Er
ror{{@>3.  Program_Error{{@>4.  Storage_Error{{@>5.  Tasking_Err
or{{{Assuming Rainbow_Color and Traffic_Light_Color are defined 
as before, which of{the above exceptions would be raised by^Rain
bow_Color'Value("AMBER")`?{}Please press 1, 2, 3, 4, or 5, or B 
to go back.[14602461346244635464B458]@=^1.  Constraint_Error`{{@
>2.  Numeric_Error{{@>3.  Program_Error{{@>4.  Storage_Error{{@>
5.  Tasking_Error{{{%You're right!~ Using an attribute improperl
y in this way will raise{Constraint_Error.{}q[ 465B459Q459]@>1. 
 Constraint_Error{{@>2.  Numeric_Error{{@>3.  Program_Error{{@>4
.  Storage_Error{{@>5.  Tasking_Error{{{No, Numeric_Error is usu
ally raised by arithmetic overflow, or attempted{division by zer
o.{}q[ 465B459Q459]@>1.  Constraint_Error{{@>2.  Numeric_Error{{
@>3.  Program_Error{{@>4.  Storage_Error{{@>5.  Tasking_Error{{{
No, Program_Error is usually raised by skipping around the^retur
n~statement in{a function.{}q[ 465B459Q459]@>1.  Constraint_Erro
r{{@>2.  Numeric_Error{{@>3.  Program_Error{{@>4.  Storage_Error
{{@>5.  Tasking_Error{{{No, Storage_Error is raised by running o
ut of memory.{}q[ 465B459Q459]@>1.  Constraint_Error{{@>2.  Nume
ric_Error{{@>3.  Program_Error{{@>4.  Storage_Error{{@>5.  Taski
ng_Error{{{No, Tasking_Error is raised only by programs using ta
sking, which we haven't{yet discussed.{}q[ 465B459Q459]A block c
onstruct lets us declare objects in the^executable~region of the
{program.  For example, in the following, I and F come into exis
tence where{they're declared, and go out of existence at the fol
lowing^end~statement:{{@<procedure Block_Demo is{@?Q : Float;{@<
begin{@?Q := 0.0;{@>^declare`{@A^I : Integer;`{@A^F : Float;`{@>
^begin`{@A^I := 5;`{@A^F := Q;`{@>^end;`{@?Q := Q + 3.0;{@<end B
lock_Demo;{{However, the usual use of a block is to localize an 
exception handler, not to{bring objects into existence in the ex
ecutable region of a program.  The{declarative part of the block
 is optional.  For example, let's rewrite{Exception_Demo to make
 use of a block with an exception handler.{}b[ 466B459] with Tex
t_IO; use Text_IO;{ procedure Exception_Demo is{@$package My_Int
_IO is new Integer_IO(Integer); use My_Int_IO;{@$I@%: Integer;{@
$Wrong : exception;{ begin{@$loop{@&^begin`{@*New_Line(2);  Put(
"Type a positive integer. ");  Get(I);  Skip_Line;{@*if I <= 0 t
hen{@-raise Wrong;{@*end if;{@*Put("The square is ... ");{@*Put(
I*I);{@&^exception`{@*when Constraint_Error | Numeric_Error =>{@
-Put(" ... too big.");{@*when Wrong =>{@-New_Line;  Put("I said 
Positive integer!");{@&^end;`{@$end loop;{ end Exception_Demo;{}
b[ 467B465]Note that in our rewritten program, a block with an e
xception handler has been{created inside the loop.  Now, if an e
xception occurs, the handler will be{executed instead of the res
t of the^block`, not the rest of the^procedure`.{Thus, the loop 
will still be executed, and the program will continue to ask{for
 integers after an exception is handled.{{There are two advantag
es to confining exception handlers to small blocks.{First, we na
rrow down the range of statements that might have raised the{exc
eption.  Recall that the handler can't test which line raised th
e exception,{but it must have been one of the lines in the block
.  (If an exception is{raised outside the block, our program pro
vides no handler for it.)  Second,{program execution will contin
ue after the end of the block.{{If an exception occurs for which
 there's no handler, the exception reaches the{next higher level
.  For example, if the block in Exception_Demo somehow raises{St
orage_Error and doesn't handle it, an exception handler for the 
whole{procedure would get a chance to handle it.  (In our case, 
there is none.)  If{it's still unhandled, it's as if the^call~to
 Exception_Demo raised{Storage_Error.  If the caller doesn't han
dle it, the exception reaches the{caller's caller, etc.  If the 
exception reaches the main program and is still{unhandled, the p
rogram is stopped and the system displays the name of the{except
ion.  However, exceptions that are handled don't even reach the 
caller.{}b[ 468B466]In the unusual case of an exception raised i
n the^declarative~region, the unit{raising the exception (subpro
gram, block, etc.) is^not~given a chance to handle{it.  Exceptio
ns raised in the declarative region immediately reach the next{h
igher level.{{In a handler, the word^raise~may be used without a
 name of an exception to{re-raise whatever exception brought con
trol to the handler.  This is especially{useful after^when other
s =>`, because any one of a number of exceptions might{have tran
sferred control there.  For example,{{@1when others =>{@4Put_Lin
e("I don't know what went wrong.");{@4-- Close files and do gene
ral cleanup.{@3^raise;`{{This lets us do some processing of the 
error, and still lets the next higher{level do additional proces
sing.  Note that it's superfluous to say simply^when{others => r
aise;~because the exception will reach the next higher level eve
n if{that code is omitted.  Any unhandled exception reaches the 
next higher level.{{An error occurring^in an exception handler~i
s unhandled and reaches the next{higher level (unless it occurs 
in a block with its own exception handler).{}b[ 469B467]In Ada 9
X, it's possible to get some information about an exception, eve
n in{the^when others~branch of an exception handler.  The packag
e Ada.Exceptions{provides a type Exception_Occurrence and three 
functions (Exception_Name,{Exception_Message, and Exception_Info
rmation) that take an object of type{Exception_Occurrence and re
turn a String.  We can declare an object of type{Exception_Occur
rence and use it in an exception handler as follows:{{@,...{@+^F
ault : Ada.Exceptions.Exception_Occurrence;`{@,...{@)begin{@,...
{@)exception{@,...{@,when^Fault :~others =>{@/...{@/Text_IO.Put_
Line(%Ada.Exceptions.Exception_Name(Fault)`);{@/...{{A warning: 
 When a handler for Storage_Error is reached, there may not be{e
nough memory to use Text_IO or Exception_Name, etc.  An attempt 
to do so may{just re-raise Storage_Error, bypassing your handler
.{}b[ 470B468]@*with Text_IO; use Text_IO;@-separate (One){@*pro
cedure One is@7procedure Two is{@-procedure Two is separate;@-Ca
in : exception;{@*begin@Bbegin{@-Two;@Craise Cain;{@*exception@>
exception{@-when others =>@9when others =>{@0Put_Line("1");@9Put
_Line("2");{@*end One;@?end Two;{{{@6What will the above program
 display?{{@61.  The program will display 1.{{@62.  The program 
will display 2.{}Please press 1 or 2, or B to go back.[24711472B
469]@*with Text_IO; use Text_IO;@-separate (One){@*procedure One
 is@7procedure Two is{@-procedure Two is separate;@-Cain : excep
tion;{@*begin@Bbegin{@,^Two;~@A^raise Cain;`{@*exception@>except
ion{@-when others =>@8^when others =>`{@0Put_Line("1");@8^Put_Li
ne("2");`{@*end One;@?end Two;{{{%You're right!~ Two handles the
 exception, so it never reaches One.{}q[ 473B470Q470]@*with Text
_IO; use Text_IO;@-separate (One){@*procedure One is@7procedure 
Two is{@-procedure Two is separate;@-Cain : exception;{@*begin@B
begin{@-Two;@Craise Cain;{@*exception@>exception{@-when others =
>@9when others =>{@0Put_Line("1");@9Put_Line("2");{@*end One;@?e
nd Two;{{{No, Two handles the exception, so it never reaches One
.{}q[ 473B470Q470]@?MORE ABOUT TEXT_IO{{We're almost ready for O
utside Assignment 5.  For that assignment, we had to{cover type 
Text, access types, and exceptions.  We also need to learn a lit
tle{more about Text_IO before we do the assignment.{{Text_IO is 
used for input and output to and from text files as well as inpu
t{and output to and from the terminal.  Text files are files tha
t can be listed{at the terminal.  (Binary files and random acces
s files are handled with the{packages Sequential_IO and Direct_I
O, which will be discussed in the Advanced{Topics section.){{The
 full specification of Text_IO appears in section 14.3.10 of the
 LRM.  It's{rather long, and some of the procedures and function
s are rarely used.  So{there's a simplified specification of Tex
t_IO in your printed course notes,{starting on page 17.  Please 
consult your printed course notes during the{following discussio
n.{{Note that there's a limited private type called File_Type.  
For each file that{our program will use, we must create an objec
t of this type, for example,{%F1, F2 : File_Type;`.  We can then
 use these objects in the procedures Create{and Open, to associa
te file names with the objects of type File_Type.{}b[ 474B470]No
te that the I/O procedures, such as New_Line, Put, and Get, have
 one version{for use with the terminal, and another version for 
use with a file.  The file{version takes an object of type File_
Type,^not~the name of the file.  The file{must first have been C
reated or Opened.{{The exception Status_Error is raised by tryin
g to do I/O on a closed file.{Mode_Error is raised by trying to 
read from a file opened or created with mode{Out_File, or by try
ing to write to a file of mode In_File.  Name_Error is{raised by
 trying to Open a file that doesn't exist, or by trying to Creat
e a{file with a name not allowed by the system.  End_Error is ra
ised by trying to{read past an end-of-file.{{New_Line creates on
e or more blank lines on^output`, and Skip_Line skips one or{mor
e lines of^input`.  We can Put characters and strings, and we ca
n Put_Line a{string.  We can Get a character, and Get_Line a str
ing.  Note that when we{Get_Line a string, the procedure returns
 the number of characters that were in{the line.  Thus, if we ha
ve^S : String(1 .. 80);  Len : Integer;~and we execute{%Get_Line
(S, Len);~and the user types^Hello~followed by CR, Len will be s
et to{5, S(1 .. 5) will be set to "Hello", and the rest of S wil
l be unmodified.{{The generic package Integer_IO can be instanti
ated for any integer type,{including user-defined types and deri
ved types like Counter and No_Of_Apples.{}b[ 475B473]When we cal
l Put in our instantiation of Integer_IO, we can optionally spec
ify{the width and the base.{{The generic package Float_IO can be
 instantiated for any floating point type,{such as Float and the
 user-defined type Real that we created earlier.  Put{allows us 
optionally to specify the number of places before and after the{
decimal point, and the size of the optional exponent field.{{The
 generic package Enumeration_IO can be instantiated for any enum
eration{type.  Put allows us optionally to specify the width.{{T
ext_IO contains another generic package Fixed_IO for fixed point
 types, not{shown in our simplified version.  Fixed point types 
will be discussed in the{section on More Records and Types.{{To 
illustrate the use of Text_IO, here's a simple program that prom
pts for the{names of an old input file and a new output file, an
d copies the input file to{the output.  It's assumed that the in
put file is an ASCII text file no wider{than 80 characters, and 
that it contains no special control characters such as{form feed
s:{}b[ 476B474]@(^with Text_IO; use Text_IO;`{@(^procedure Filec
opy is`{@+^F1, F2 : File_Type;`{@+^S@&: String(1 .. 80);`{@+^Len
@$: Integer;`{@(^begin`{@+^Put("Input file: ");  Get_Line(S, Len
);`{@+^Open(File => F1, Mode => In_File, Name => S(1 .. Len));`{
@+^Put("Output file: ");  Get_Line(S, Len);`{@+^Create(File => F
2, Mode => Out_File, Name => S(1 .. Len));`{@+^while not End_Of_
File(F1) loop`{@.^Get_Line(F1, S, Len);`{@.^Put_Line(F2, S(1 .. 
Len));`{@+^end loop;`{@+^Close(F1);`{@+^Close(F2);`{@(^end Filec
opy;`{{In many systems, all files are closed automatically when 
the main program{terminates, and this program would work even wi
thout^Close(F1);~and^Close(F2);`.{{This program also appears on 
page 19 of your printed course notes.{}b[ 477B475]There's no way
 to test whether a file already exists without trying to Open it
{and trapping the Name_Error if the file doesn't exist.  The fol
lowing function{determines whether a file name represents an exi
sting file.  It appears on page{19 of your printed course notes:
{{@+^with Text_IO; use Text_IO;`{@+^function Exists(File_Name : 
in String) return Boolean is`{@.^F@&: File_Type;`{@.^Answer : Bo
olean := True;`{@+^begin`{@.^begin`{@1^Open(F, In_File, File_Nam
e);`{@1^Close(F);`{@.^exception`{@1^when Name_Error => Answer :=
 False;`{@.^end;`{@.^return Answer;`{@+^end Exists;`{}b[ 478B476
]@@1.  Status_Error{{@@2.  Mode_Error{{@@3.  Name_Error{{@@4.  E
nd_Error{{{@&Which exception is raised by attempting to do I/O o
n a closed file?{}Please press 1, 2, 3, or 4, or B to go back.[1
479248034814482B477]@?^1.  Status_Error`{{@@2.  Mode_Error{{@@3.
  Name_Error{{@@4.  End_Error{{{%You're right!~ Status_Error is 
raised by an attempt to do I/O on a closed file.{}q[ 483B478Q478
]@@1.  Status_Error{{@@2.  Mode_Error{{@@3.  Name_Error{{@@4.  E
nd_Error{{{No, Mode_Error is raised by an attempt to read from a
 file of mode Out_File, or{write to a file of mode In_File.{}q[ 
483B478Q478]@@1.  Status_Error{{@@2.  Mode_Error{{@@3.  Name_Err
or{{@@4.  End_Error{{{No, Name_Error is raised by an attempt to 
Open a file that doesn't exist, or{Create a file with an illegal
 name.{}q[ 483B478Q478]@@1.  Status_Error{{@@2.  Mode_Error{{@@3
.  Name_Error{{@@4.  End_Error{{{No, End_Error is raised by an a
ttempt to read past an end-of-file.{}q[ 483B478Q478]@.OUTSIDE AS
SIGNMENT 5 - WRITING A SIMPLE LINE EDITOR{{We're finally ready f
or the next Outside Assignment!  This assignment will give{you a
 chance to write a program of greater complexity than the previo
us{assignments.  By the time you've completed Outside Assignment
 5, you should{feel comfortable with Ada.  The full set of requi
rements for the line editor we{want you to write are in your pri
nted course notes, starting on page 20.  We'll{discuss them brie
fly here.  No test driver is supplied, but after you've{written 
the program, we'll give you some tests to perform manually on yo
ur line{editor.  You've completed the assignment when your edito
r passes all the tests.{{Imagine that your screen editor is unav
ailable to a particular user, perhaps{because the user is dialin
g your computer from a remote location, and your{screen editor w
rites directly to the screen.  You want to write a line editor.{
While your computer already has a line editor called EDLIN, it's
 difficult to{learn to use.  The line editor you'll write, calle
d Ledit, will take almost no{effort to learn.  The only commands
 are LIST and EXIT.{{The user begins each line of text with a li
ne number, similar to Basic.  Line{numbers must be integers betw
een 1 and 29999.  Regardless of the order in which{lines are ent
ered, Ledit maintains a linked list of lines in order by number,
{so that it can List the text in order, or write it to a file.{}
b[ 484B478]Line numbers need not be consecutive, and they may be
 preceded by any number of{spaces.  For example, if we type{{%40
 -- This is a comment.{@#20 begin{10 with Text_IO; use Text_IO;{
@&30 end Add;`{{and then type^LIST`, the editor displays{{@#10 w
ith Text_IO; use Text_IO;{@#20 begin{@#30 end Add;{@#40 -- This 
is a comment.{{To^insert~lines, we merely type lines with interm
ediate line numbers.  In our{example, if we now type{{%15 proced
ure Hello is{LIST`{{we'll see{}b[ 485B483]@#10 with Text_IO; use
 Text_IO;{@#15 procedure Hello is{@#20 begin{@#30 end Add;{@#40 
-- This is a comment.{{To^replace~a line, we simply retype the l
ine with the same line number as the{line to be replaced, and to
^delete~a line, we type only the line number.  If{we now type{{%
15 procedure Add is{40{LIST`{{we'll see{{@#10 with Text_IO; use 
Text_IO;{@#15 procedure Add is{@#20 begin{@#30 end Add;{}b[ 486B
484]Thus the user can insert, replace, and delete lines by line 
numbers, without{learning any commands!  If the user forgets the
 space after the line number, no{harm is done; Ledit takes^20beg
in~the same as^20 begin`.  However, the user can{indent code by 
adding^extra~spaces after the line number.  The following{exampl
e has three^extra~spaces after each line number (four spaces tot
al):{{%24@$Put(2 + 2);{26@$New_Line;{18@$package My_Int_IO is ne
w Integer_IO(Integer); use My_Int_IO;{LIST`{{@#10 with Text_IO; 
use Text_IO;{@#15 procedure Add is{@#18@$package My_Int_IO is ne
w Integer_IO(Integer); use My_Int_IO;{@#20 begin{@#24@$Put(2 + 2
);{@#26@$New_Line;{@#30 end Add;{{When Listing, Ledit always all
ows exactly five spaces for the line number, so{that the text li
nes up correctly:{}b[ 487B485]%LIST`{{@$2 This is a sample listi
ng,{@#20 showing how the text{  200 lines up, even when{ 2000 so
me line numbers are{20000 longer than others.{{When we type^EXIT
`, Ledit writes the output file^without~the line numbers.  The{t
ext above would all start in column 1 of the output file.{{For L
edit to be useful with files larger than a page, it must be poss
ible to{list a range of lines:{{%LIST 20 - 30`{{This is only a s
ummary of the requirements for Ledit.  Please refer to pages{20-
24 of your printed course notes for the actual requirements.  As
 a point of{reference, our solution requires about 180 lines of 
Ada on four pages.{{Here are the steps to follow for Outside Ass
ignment 5.  They can also be found{in the printed course notes o
n page 25:{}b[ 488B486]1.  Carefully read the requirements start
ing on page 20 of the printed course{@$notes.  Take your time.{{
2.  Write the Ada code, compile, and link.  Call the main progra
m Ledit.  If{@$you have any questions about what Ledit should do
, you can compile and run{@$our solution, which is in LEDIT.ANS.
{{3.  Refer to pages 26-28 of the printed course notes for instr
uctions on{@$testing your line editor.  If any tests are failed,
 go back to step 2.{{4.  When all the tests are passed, you've c
ompleted the assignment and will{@$have a chance to compare your
 solution with ours.{{{Please type X to exit^ADA-TUTR~temporaril
y, and try Outside Assignment 5.  It{will probably take several 
days.  Take your time; there's no deadline.  Good{luck!{}Please 
type X to exit, a space to go on, or B to go back.[ 489B487]@-^C
ongratulations on Completing Outside Assignment 5!`{{If you like
, you can compare your solution with ours, which is in LEDIT.ANS
.  A{listing starts on page 29 of your printed course notes.  No
te that a single{procedure handles adding, deleting, and replaci
ng lines.  Replacing is done by{first deleting, then adding a li
ne.{{Your solution might be very different from ours, but if it 
passed all the{tests, consider it correct.{{Early in this course
 we used the generic package Integer_IO.  Let's now learn{how to
 write our own generic packages, procedures, and functions.{}b[ 
490B488]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Recursion 
and Assignment 4{{@#The Format of an Ada Program@-Subprograms an
d Packages`{{@#Generic Instantiation and@0Access Types, User Def
ined Types,{@&Assignment 1@=and Derived Types{{@#Simple Declarat
ions and Simple@+Exceptions, Text_IO, and{@&Attributes@?Assignme
nt 5{{@#Operators, Control Constructs, and@#^>  GENERICS, TASKIN
G, AND ASSIGNMENT 6`{@&Assignment 2{@LMore Records and Types{@#R
ecords, Arrays, and Assignment 3{@LAdvanced Topics{}b[ 491B489]@
DGENERICS{{It would be easy to write a package that creates a si
ngle stack of 10 Integers,{and lets us Push and Pop on it.  Howe
ver, the code would be about the same{regardless of the size of 
the stack, and regardless of the type of objects on{the stack.  
For example, a second package that creates a stack of 50 Dates{w
ould look about the same.  We can write one^generic~package, and
 instantiate{it for any size and almost any type we need.  The s
pecification is:{{@4^generic`{@7^Size : Positive;`{@7^type Dummy
 is private;`{@4^package Stack_Package is`{@7^procedure Push(Obj
ect : in Dummy);`{@7^function Pop return Dummy;`{@4^end Stack_Pa
ckage;`{{Since both Size and type Dummy are generic, both must b
e specified when we{instantiate the package:{{@'^package Stack_O
f_10_Integers is new Stack_Package(10, Integer);`{@'^package Sta
ck_Of_50_Dates@$is new Stack_Package(50, Date);`{}b[ 492B490]If 
the generic part says^type Dummy is private;~then the subprogram
 or package{body may do only three things with objects of type D
ummy: create them, assign{them, and test them for equality or in
equality.  Note that this is similar to{the list of things we ma
y do with a private type^outside~an ordinary package.{In this ca
se, we're listing what we can do^inside~the generic package.  Ca
lling{the package's subprograms isn't on our list, because they'
re not written yet!{We're listing the things we can do when we w
rite the body of the package.  Of{course, once we write some sub
programs, other subprograms can call them.{{Although we can do o
nly three things with objects of a private type inside a{generic
 package, we can instantiate that package with almost any type a
t all.{Our Stack_Package can be instantiated for Dates, Strings 
(see the next{paragraph), Rainbow_Colors, Floats, and any type f
or which we can assign{objects and test them for equality.  That
 means any type except a limited type.{We can't instantiate Stac
k_Package for type Text_IO.File_Type (a limited{private type), o
r for task types (discussed later), because in our package{we're
 allowed to assign and test for equality objects of type Dummy.{
{Since we can't create objects of an unconstrained array type, i
f we want to{instantiate Stack_Package for Strings, we must use 
a constrained subtype of{String.  For example, we could write^su
btype Name is String(1 .. 30);~and then{write^package Stack_Of_5
0_Names is new Stack_Package(50, Name);`.{}b[ 493B491]We could i
nstantiate our package even for limited types like Text_IO.File_
Type{if the generic part had said^type Dummy is limited private;
`.  However, the only{thing our package could do with objects of
 that type is create them.{Ordinarily, that's not very useful.{{
If the generic part says^type Dummy is ( <> );~then we can insta
ntiate the{package (or subprogram) for any discrete type.  That 
means any enumeration or{integer type: Character, Boolean, Count
er, No_Of_Apples, etc.  Inside the{package, attributes like 'Fir
st are available.{{If the generic part says^type Dummy is range 
<>;~then we can instantiate for{any integer type.  Inside the pa
ckage, we can do things that can be done with{all integer types,
 such as add, etc.{{If the generic part says^type Dummy is delta
 <>;~then we can instantiate for{any fixed point type, to be dis
cussed in the section on More Records and Types.{{Finally, if th
e generic part says^type Dummy is digits <>;~then we can{instant
iate for any floating point type, such as Float or the Real we c
reated.{}b[ 494B492]In Ada 9X, some additional forms are allowed
.  If the generic part says^type{Dummy( <> ) is private;~then we
 can instantiate with unconstrained types like{String, provided 
that the body initializes any objects it creates of that type.{{
If the generic part says^type Dummy is tagged private;~then we c
an instantiate{with any tagged type, to be covered in the sectio
n on More Records and Types.{{If the generic part says^type Dumm
y is new X;~or^type Dummy is new X with{private;~then we can ins
tantiate with type^X~or with any type derived from^X`.{If^with p
rivate~is included, then we must instantiate with a tagged type.
{{In all cases above, we can follow^Dummy~with^( <> )~to allow i
nstantiating with{unconstrained types.  The body must initialize
 any objects it creates with an{unconstrained type.  We can also
 replace^is~in the generic part with^is private`{to allow instan
tiating with abstract types, to be covered later.{{If the generi
c part says^type Dummy is mod <>;~then we can instantiate with a
ny{modular type, to be covered in the section on More Records an
d Types.{{Finally, if the generic part says^with package Dummy i
s new P( <> );~where^P~is{the name of a generic package, then we
 can instantiate with any package that we{obtained by instantiat
ing^P`.{}b[ 495B493]The specification of a generic subprogram mu
st be given separately from the{body.  For example, we can't eli
minate the highlighted line in this function:{{@(generic{@+type 
Dummy_Float is digits <>;{@+type Dummy_Vector is array (Integer 
range <>) of Dummy_Float;{@'^function Sum(V : in Dummy_Vector) r
eturn Dummy_Float;`{@(function Sum(V : in Dummy_Vector) return D
ummy_Float is{@+Answer : Dummy_Float := 0.0;{@(begin{@+for I in 
V'Range loop{@.Answer := Answer + V(I);{@+end loop;{@+return Ans
wer;{@(end Sum;{}b[ 496B494]We can instantiate Sum and call it a
s follows:{{@/^type Vector is array(Integer range <>) of Float;`
{@/^V1 : Vector(1 .. 10);`{@/^X  : Float;`{@/^function Sumv is n
ew Sum(Float, Vector);`{@0...{@/^X := Sumv(V1);`{}b[ 497B495]@)g
eneric{@,type Dummy is range <>;{@)procedure Display(Item : in D
ummy);{{@)type No_Of_Apples is new Integer;{@)type Counter is ra
nge 0 .. 1_000_000;{@)type Answer is (Yes, No, Maybe);{@)procedu
re Display_Apples@#is new Display(No_Of_Apples);  -- 1{@)procedu
re Display_Counters is new Display(Counter);@'-- 2{@)procedure D
isplay_Answers  is new Display(Answer);@(-- 3{{{@)Which commente
d line in the above program segment is^illegal`?{}Please press 1
, 2, or 3, or B to go back.[349814992500B496]@)generic{@,type Du
mmy is range <>;{@)procedure Display(Item : in Dummy);{{@)type N
o_Of_Apples is new Integer;{@)type Counter is range 0 .. 1_000_0
00;{@)type Answer is (Yes, No, Maybe);{@)procedure Display_Apple
s@#is new Display(No_Of_Apples);  -- 1{@)procedure Display_Count
ers is new Display(Counter);@'-- 2{@(^procedure Display_Answers 
 is new Display(Answer);@(-- 3`{{{%You're right!~ When the gener
ic part says^type Dummy is range <>;`, the{procedure may be inst
antiated for any integer type.  Answer is a discrete type,{but n
ot an integer type.{{In the Advanced Topics section, we'll show 
an example of a generic function.{}q[ 501B497Q497]@)generic{@,ty
pe Dummy is range <>;{@)procedure Display(Item : in Dummy);{{@)t
ype No_Of_Apples is new Integer;{@)type Counter is range 0 .. 1_
000_000;{@)type Answer is (Yes, No, Maybe);{@)procedure Display_
Apples@#is new Display(No_Of_Apples);  -- 1{@)procedure Display_
Counters is new Display(Counter);@'-- 2{@)procedure Display_Answ
ers  is new Display(Answer);@(-- 3{{{No, when the generic part s
ays^type Dummy is range <>;`, the procedure may be{instantiated 
for any integer type.  No_Of_Apples is a type derived from{Integ
er, so it's an integer type.{}q[ 501B497Q497]@)generic{@,type Du
mmy is range <>;{@)procedure Display(Item : in Dummy);{{@)type N
o_Of_Apples is new Integer;{@)type Counter is range 0 .. 1_000_0
00;{@)type Answer is (Yes, No, Maybe);{@)procedure Display_Apple
s@#is new Display(No_Of_Apples);  -- 1{@)procedure Display_Count
ers is new Display(Counter);@'-- 2{@)procedure Display_Answers  
is new Display(Answer);@(-- 3{{{No, when the generic part says^t
ype Dummy is range <>;`, the procedure may be{instantiated for a
ny integer type.  The definition of the user-defined type{Counte
r has the word^range`, so Counter is an integer type.{}q[ 501B49
7Q497]@DTASKING{{Here are two versions of a program with two par
allel tasks.  Since the main{program is a task, these two versio
ns are equivalent.{{@)with Text_IO; use Text_IO;@)with Text_IO; 
use Text_IO;{@)procedure Task_Demo is@0procedure Task_Demo is{@+
^task A;~@:^task A;`{@+^task body A is~@3^task body A is`{@+^beg
in~@<^begin`{@.^Put_Line("b");~@3^Put_Line("a");`{@.^Put_Line("b
");~@3^Put_Line("a");`{@+^end A;~@;^end A;`{@)begin@@^task B;`{@
+^Put_Line("a");~@3^task body B is`{@+^Put_Line("a");~@3^begin`{
@)end Task_Demo;@:^Put_Line("b");`{@Q^Put_Line("b");`{@N^end B;`
{@Lbegin{@Onull;{@Lend Task_Demo;{}b[ 502B497]Our program could 
have specified as many tasks as we like.  Also, our tasks{could 
have declarations between^task body ... is~and^begin`.  If the c
omputer{has several processors, and the Ada compiler makes use o
f that fact, the tasks{could actually run simultaneously.  Other
wise, the compiler may (but doesn't{have to) write code to^time 
slice~among the tasks, making them^appear~to run{simultaneously.
  One implementation of Ada we tried time slices, and the output
{of the program looked something like this:{{ab{{ab{{{This happe
ned because Put_Line is equivalent to Put plus New_Line, and thu
s{Put_Line can get interrupted before the CR-LF is output.  Here
 one task{displayed "a", the other task displayed "b", and then 
both tasks sent CR-LF.{{Another implementation of Ada we tried w
on't time-slice unless told to with a{%pragma`, covered in the A
dvanced Topics section.  So the output of the same{program with 
that implementation of Ada looked like this:{}b[ 503B501]a{a{b{b
{{In this case one task ran to completion before the other task 
started.  The{point is that both implementations of Ada ran our 
program correctly, but with{different results.{{When data is pas
sed between tasks, we often don't want the process interrupted.{
For example, suppose one task updates a record with several fiel
ds, such as a{Date.  Another task reads the record.  We don't wa
nt the second task to{interrupt the first in the middle of updat
ing a record.  Otherwise, the second{task might read an updated 
Day field, an updated Month field, and an old Year{field, which 
would be meaningless.  Ada has an elegant solution to this{probl
em, called the^rendezvous`.{{In this example, we assume that the
 main program created both procedure Caller{and task Server, and
 defined type Date:{}b[ 504B502]@&procedure Caller is@*task Serv
er is{@)D : Date;@4entry Update(Item : in out Date);{@Cend Serve
r;{@&begin@8task body Server is{@(^-----;~@3begin{@(^-----;  -- 
Block 1~@)^-----;  -- Block 3`{@(^-----;~@5^-----;`{@E^accept Up
date(Item : in out Date) do`{@(^Server.Update(D);~@-^-----;  -- 
Block 4`{@H^-----;`{@(^-----;~@5^end Update;`{@(^-----;  -- Bloc
k 2~@)^-----;  -- Block 5`{@(^-----;~@5^-----;`{@&end Caller;@2e
nd Server;{{Code blocks 1 and 3 run in parallel (perhaps simulta
neously, as discussed).{Then Caller waits at the call to Server.
Update while Server executes block 4.{Block 4 is called the crit
ical section of code, where records might be updated,{etc.  When
 this^rendezvous~is over, blocks 2 and 5 run in parallel.  If Ca
ller{reaches the call before Server reaches^accept`, Caller will
 wait patiently{there for Server.  If Server reaches^accept~firs
t, it will wait patiently there{for a caller.{}b[ 505B503]@&proc
edure Caller is@*task Server is{@)D : Date;@3^entry~Update(Item 
: in out Date);{@Cend Server;{@&begin@8task body Server is{@)---
--;@4begin{@)-----;  -- Block 1@+-----;  -- Block 3{@)-----;@7--
---;{@E^accept~Update(Item : in out Date)^do`{@(^Server.Update(D
);~@.-----;  -- Block 4{@I-----;{@)-----;@7end Update;{@)-----; 
 -- Block 2@+-----;  -- Block 5{@)-----;@7-----;{@&end Caller;@2
end Server;{{The call to Update looks like a procedure call.  We
 can't^use~a task, so the{call requires dot notation.  The^entry
~specification looks like a procedure{specification, with^entry~
replacing^procedure`.  The task specification may have{any numbe
r of^entry~statements; if it has none, we write simply^task Serv
er;`.{The^accept~block looks like a procedure without declaratio
ns, but^accept`{replaces^procedure`, and^do~replaces^is begin`. 
 An^accept~with no parameters{and no statements may be written s
imply as^accept Update;`.{}b[ 506B504]In Ada 9X there's another 
way, simpler than the rendezvous, to assure that one{task won't 
try to read an item while another task is writing it.  It's call
ed{a^protected~object.  For example:{{@$type Date is ...@4^prote
cted body~Prot_Date^is`{@$...@Efunction Read return Date is{@#^p
rotected~Prot_Date^is~@1begin{@'function Read return Date;@.retu
rn Item;{@'procedure Write(D : in Date);@(end Read;{@#^private~{
@'Item : Date;@9procedure Write(D : in Date) is{@#^end~Prot_Date
;@:begin{@OItem := D;{@Lend Write;{@H^end~Prot_Date;{{The syntax
 is similar to a package or a task, and the calls to Read and Wr
ite{are similar to task calls:^D : Date;~...^D := Prot_Date.Read
;~...{%Prot_Date.Write(D);`.  Ada 9X guarantees that calls to th
e protected{subprograms, in this case Read and Write, won't exec
ute simultaneously.{{This is a protected^object`.  We'll learn a
bout Ada 9X protected^types~shortly.{}b[ 507B505]@-procedure Mas
ter is@.task Slave is{@Qentry Sync;{@Nend Slave;{@Ntask body Sla
ve is{@-begin@<begin{@0-----;@;-----;{@0-----;  -- Block 1@/----
-;  -- Block 3{@0-----;@;-----;{@0Slave.Sync;@6accept Sync;{@0--
---;@;-----;{@0-----;  -- Block 2@/-----;  -- Block 4{@0-----;@;
-----;{@-end Master;@6end Slave;{{{True or False?  Statements in
 blocks 1 and 4 could execute simultaneously.{}Please press T fo
r true or F for false, or B to go back.[F508T509B506]@-procedure
 Master is@.task Slave is{@Qentry Sync;{@Nend Slave;{@Ntask body
 Slave is{@-begin@<begin{@0-----;@;-----;{@0-----;  -- Block 1@/
-----;  -- Block 3{@0-----;@;-----;{@/^Slave.Sync;~@4^accept Syn
c;`{@0-----;@;-----;{@0-----;  -- Block 2@/-----;  -- Block 4{@0
-----;@;-----;{@-end Master;@6end Slave;{{{%You're right!~ Maste
r will wait patiently at^Slave.Sync~for Slave to reach{%accept`,
 or Slave will wait patiently at^accept~for Master to reach{%Sla
ve.Sync;`.  Therefore, blocks 1 and 4 can't execute simultaneous
ly.{}q[ 510B507Q507]@-procedure Master is@.task Slave is{@Qentry
 Sync;{@Nend Slave;{@Ntask body Slave is{@-begin@<begin{@0-----;
@;-----;{@0-----;  -- Block 1@/-----;  -- Block 3{@0-----;@;----
-;{@0Slave.Sync;@6accept Sync;{@0-----;@;-----;{@0-----;  -- Blo
ck 2@/-----;  -- Block 4{@0-----;@;-----;{@-end Master;@6end Sla
ve;{{{False.  Master will wait patiently at^Slave.Sync~for Slave
 to reach^accept`, or{Slave will wait patiently at^accept~for Ma
ster to reach^Slave.Sync;`.{Therefore, blocks 1 and 4 can't exec
ute simultaneously.{}q[ 510B507Q507]If several tasks call an ent
ry before the server reaches^accept`, the calls are{queued first
-in, first-out.{{We can write a^select~block to accept any of se
veral different calls:{{@8^select`{@<accept A;{@8^or`{@<accept B
(I : in Integer) do{@?-----;{@<end B;{@8^or`{@<accept C;{@8^end 
select;`{{When^select~is reached, the task waits for a call to A
 or B or C.  If calls to{more than one entry are pending, one wi
ll be chosen arbitrarily.{{A^delay~statement, used in ordinary c
ode, will delay a specified number of{seconds (plus any system o
verhead).  For example,{}b[ 511B507]@CA;{@B^delay 5.0;`{@CB;{{wi
ll call A, delay five seconds (plus system overhead), and then c
all B.{However, when used in a^select~block, the meaning is a bi
t different.  It's{used to implement an^impatient server`.  For 
example,{{@@^select`{@Daccept A;{@@^or`{@Daccept B;{@@^or`{@C^de
lay 5.0;`{@DC;{@@^end select;`{{will wait up to five seconds for
 a call to A or B.  If no call is received, C{will be called.{{%
Guards~can be used to switch alternatives of a^select~block on a
nd off.  For{example,{}b[ 512B510]@@J : Integer;{@@...{@?^select
`{@B^when J = 1 =>`{@Caccept A;{@?^or`{@B^when J = 2 =>`{@Caccep
t B;{@?^end select;`{{Here A is an alternative only if the condi
tion (J = 1) is true; B is an{alternative only if J = 2.  If J /
= 1, then no call to A will be accepted, even{if one is pending.
  If every branch of a^select~block has a guard and all{guards a
re false, Program_Error is raised.{}b[ 513B511]In Ada 9X, we hav
e^protected types`.  For example:{{ ^protected type~P^is~@-^prot
ected body~P^is`{@$^entry~One;@7^entry~One^when~X > Y^is`{@$^ent
ry~Two(I : in Integer);@'^begin`{ ^private~@@...{@%X, Y : Intege
r;@2^end~One;{@%...{ ^end~P;@>^entry~Two(I : in Integer)^when~Tr
ue^is`{@F^begin`{@J...{@F^end~Two;{@C^end~P;{{We can declare^Q :
 P;  J : Integer;~and then call^Q.One;~and^Q.Two(J);`.  In the{b
ody, each entry has a^barrier`, similar to the guards discussed 
earlier.  Here{a call to One can be accepted only if X > Y; othe
rwise, the call is queued.  A{call to Two can always be accepted
 because the barrier is simply True.  At the{end of each call, a
ll the barriers are re-evaluated.{{An entry can requeue itself o
n another entry.  For example, the body of Two can{execute^reque
ue One;~to requeue itself on entry One.{}b[ 514B512]Ada 9X also 
lets us write{{@?^select`{@B^delay 10.0;`{@CC;{@?^then abort`{@C
A;{@CB;{@?^end select;`{{Here if the statements in the second bl
ock (the calls to A and B) take more{than 10.0 seconds, they are
 abandoned and the first block (the call to C) is{executed inste
ad.{{Tasks "die" in three ways.  The least elegant way is for a 
task to^abort~it,{e.g.,^abort Server;`.  This is drastic, becaus
e Server might be doing anything.{A better way is for a family o
f tasks each to include^terminate;~as one{alternative in a^selec
t~block.  (A "family" of tasks is the set of tasks{created by on
e "parent," for example, the main program.)  When calls to the{e
ntries in the tasks all cease, all tasks in the family will reac
h the{%terminate~alternative, and all will die together.{}b[ 515
B513]But the most orderly way for a task to die is for it simply
 to reach its last{statement.  For example, task T below will co
ntinue to accept calls to T.A and{T.B until a task calls T.Shutd
own.  At that time, T will die.{{@+task T is@6task body T is{@.e
ntry A;@6^Done : Boolean := False;`{@.entry B;@4begin{@-^entry S
hutdown;~@.^while not Done loop`{@+end T;@>^select`{@Saccept A d
o{@V-----;{@Send A;{@O^or`{@Saccept B do{@V-----;{@Send B;{@O^or
`{@R^accept Shutdown;`{@R^Done := True;`{@O^end select;`{@L^end 
loop;`{@Jend T;{}b[ 516B514]Trying to call an entry of a task th
at has died will raise Tasking_Error.{Also, a task can't termina
te until all the tasks it creates terminate.  In{particular, the
 main program can't return to the operating system until all{tas
ks in the program have died.  Programmers must be careful to avo
id possible{deadlocks.  Ada solves many problems that plague oth
er languages, but{unfortunately the deadlock problem remains uns
olved.{{A^select~block may have an^else~alternative.  Here's an 
example of a very{impatient server.  If a call to A or B is pend
ing it will be served, otherwise,{C will be called:{{@@^select`{
@Daccept A do{@G-----;{@Dend A;{@@^or`{@Daccept B do{@G-----;{@D
end B;{@@^else`{@DC;{@@^end select;`{}b[ 517B515]type Date is ..
.@5task body Data_Protector is{task Data_Protector is@2Save_D : 
Date;{@#entry Read_Date(D : out Date);@'Done@#: Boolean := False
;{@#entry Write_Date(D : in Date);@$begin{@#entry Shutdown;@6acc
ept Write_Date(D : in Date) do{end Data_Protector;@8Save_D := D:
{@Hend Write_Date;{@Hwhile not Done loop{@Kselect{@Naccept Read_
Date(D : out Date) do{@QD := Save_D;{@Nend Read_Date;{@Kor{@Nacc
ept Write_Date(D : in Date) do{@QSave_D := D;{True or False?  Th
is task must@0end Write_Date;{serve at least one call to@1or{Wri
te_Date before it will@5accept Shutdown;{accept calls to Read_Da
te.@4Done := True;{@Kend select;{@Hend loop;{@Eend Data_Protecto
r;{}Please press T for true or F for false, or B to go back.[T51
8F519B516]type Date is ...@5task body Data_Protector is{task Dat
a_Protector is@2Save_D : Date;{@#entry Read_Date(D : out Date);@
'Done@#: Boolean := False;{@#entry Write_Date(D : in Date);@$beg
in{@#entry Shutdown;@5^accept Write_Date(D : in Date) do`{end Da
ta_Protector;@7^Save_D := D:`{@G^end Write_Date;`{@Hwhile not Do
ne loop{@Kselect{@M^accept Read_Date(D : out Date) do`{@P^D := S
ave_D;`{@M^end Read_Date;`{@Kor{@M^accept Write_Date(D : in Date
) do`{@P^Save_D := D;{You're right!~ The extra^accept~@-^end Wri
te_Date;`{block outside the loop forces us@+or{to call Write_Dat
e at least once@.accept Shutdown;{before we can call Read_Date.@
1Done := True;{@Kend select;{@Hend loop;{@Eend Data_Protector;{}
q[ 520B517Q517]type Date is ...@5task body Data_Protector is{tas
k Data_Protector is@2Save_D : Date;{@#entry Read_Date(D : out Da
te);@'Done@#: Boolean := False;{@#entry Write_Date(D : in Date);
@$begin{@#entry Shutdown;@6accept Write_Date(D : in Date) do{end
 Data_Protector;@8Save_D := D:{@Hend Write_Date;{@Hwhile not Don
e loop{@Kselect{@Naccept Read_Date(D : out Date) do{@QD := Save_
D;{@Nend Read_Date;{@Kor{@Naccept Write_Date(D : in Date) do{@QS
ave_D := D;{True.  The extra^accept~block@1end Write_Date;{outsi
de the loop forces us to@.or{call Write_Date at least once@1acce
pt Shutdown;{before we can call Read_Date.@1Done := True;{@Kend 
select;{@Hend loop;{@Eend Data_Protector;{}q[ 520B517Q517]The^se
lect~block can be used in a caller as well as a server.  The fol
lowing{block waits up to five seconds to call entry A in task T.
  If T isn't ready to{accept the call in five seconds, the block
 calls procedure B instead.  This is{called an impatient custome
r:{{@@^select`{@C^T.A;`{@@^or`{@C^delay 5.0;`{@C^B;`{@@^end sele
ct;`{{A very impatient customer can be implemented with^else`.  
This block calls T.A{only if T is ready to accept the call immed
iately, otherwise, it calls B.{{@A^select`{@D^T.A;`{@A^else`{@D^
B;`{@A^end select;`{}b[ 521B517]Task^types~may be declared.  Thi
s permits us to create an array of tasks, and{it lets us bring t
asks into existence via access types.  Tasks begin executing{as 
soon as they're brought into existence.  For example,{{@;^task t
ype X is`{@>^entry E;`{@;^end X;`{@;^type P is access X;`{@;^X1 
: P;`{@;^A : array(1 .. 10) of X;`{@;^task body X is`{@?...{@;^e
nd X;`{{Entries to these tasks are called thus:{{@;^A(5).E;`{@;^
X1 := new X;`{@;^X1.all.E;~or just^X1.E;`{}b[ 522B520]Ada comes 
with a package Calendar; the specification is in section 9.6 of 
the{LRM.  The part that concerns us here is shown below.  Type D
uration is a fixed{point type built into Ada; the^delay~statemen
t discussed earlier takes an{object of type Duration.{{@'^packag
e Calendar is`{@*^type Time is private;`{@*^function Clock retur
n Time;`{@*^function "+"(Left : Time; Right : Duration) return T
ime;`{@*^function "-"(Left : Time; Right : Time)@%return Duratio
n;`{@+...{@'^end Calendar;`{{Not shown are a few other operators
, and subprograms to convert between type{Time and the year, mon
th, day, and number of seconds since midnight.{{Let's write a pr
ogram segment, using Calendar, that calls A every five seconds:{
}b[ 523B521]@6^with Calendar; use Calendar;`{@7...{@6^Next_Event
 : Time := Clock + 5.0;`{@7...{@6^loop`{@9^delay Next_Event - Cl
ock;`{@9^A;`{@9^Next_Event := Next_Event + 5.0;`{@6^end loop;`{{
Note that this loop accounts for the time required to call A.  I
nstead of{delaying 5.0, we calculate the time of the next call i
n Next_Event, and delay{that time minus the current time, which 
we obtain by calling Clock.  Thus the{program will go through th
e loop once every 5.0 seconds, even if it takes a{little time to
 call A.  In Ada 9X, we may write^delay until Next_Event;~which{
guarantees that no higher-priority task will interrupt the calcu
lation of{Next_Event - Clock, thereby causing the delay to be to
o long.{{The^-~and^+~operators in this example all use infix fun
ctions from Calendar.{{We're now ready for Outside Assignment 6!
  It will be much simpler than Outside{Assignment 5.{}b[ 524B522
]@3OUTSIDE ASSIGNMENT 6 - EXERCISE IN TASKING{{On page 33 of you
r printed course notes is a listing of^TASKING.DUM`.  This{progr
am calls a task entry to display^Tick!~on the screen every five 
seconds{until it has been displayed nine times.{{Every time^dela
y~is executed, the message^(5-second delay)~is displayed so that
{the delay will be visible on the screen.  The program is entire
ly in lower{case, because your assignment is to modify it.  If y
ou make your modifications{in upper case, it will be easy to see
 what you have changed.{{We want you to change the declaration o
f T from a single task to an^array~of{three tasks.  The tasks ar
e numbered 1, 2, and 3.  Task 1 is to be activated{every^two~fiv
e-second intervals.  Task 2 is to be activated every^three~five-
{-second intervals, and task 3, every^four`.  Also, instead of d
isplaying^Tick!`,{each task will identify itself by number, for 
example,^Task number 3 is{starting`.  Output should look as show
n on page 35 of your printed notes.{}b[ 525B523]We recommend tha
t you create an array of three counters.  Each counter counts{do
wn from its period (2, 3, or 4) to zero by one count every inter
val.  When a{counter reaches zero, the corresponding task entry 
is called, and the counter{is reset to its period.  All three co
unters should be initialized to zero, so{that all three tasks di
splay their messages immediately upon activation of the{program.
  You should use the rendezvous mechanism to inform each task of
 its{number (1, 2, or 3).  Your program should use a loop to do 
an orderly shutdown{of all three tasks at the end.{{Here are the
 steps to follow for Outside Assignment 6.  They're also in your
{printed course notes on page 34:{}b[ 526B524]1.  Make a copy of
 TASKING.DUM by typing^COPY TASKING.DUM TASKING.ADA`.{@$Compile,
 link, and execute the program to make sure it displays^Tick!~ni
ne{@$times, with a 5-second delay after each "Tick."{{2.  Edit T
ASKING.ADA to become your solution.  Make your changes in upper 
case.{{3.  Compile TASKING.ADA, link, and execute.{{4.  Compare 
your output with page 35 of the printed course notes.  If there 
are{@$any errors, go back to step 2.{{5.  When your output agree
s with the printed course notes, you've finished the{@$assignmen
t and will have a chance to compare your solution with ours.{{{P
lease type X to exit^ADA-TUTR~temporarily, and try Outside Assig
nment 6.  Work{at your own pace; there's no deadline.  Good luck
!{}Please type X to exit, a space to go on, or B to go back.[ 52
7B525]@-^Congratulations on Completing Outside Assignment 6!`{{I
f you like, you can compare your solution with ours, which is in
 TASKING.ANS.{A listing is on page 36 of your printed course not
es.  Your solution might be{different from ours, but if your^out
put~agrees with page 35 of the printed{notes, your solution is c
orrect.{{You've learned a great deal of Ada!  Let's go on to dis
cuss some more records{and types.{}b[ 528B526]@;^ADA-TUTR COURSE
 OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{{@#The Fo
rmat of an Ada Program@-Subprograms and Packages`{{@#Generic Ins
tantiation and@0Access Types, User Defined Types,{@&Assignment 1
@=and Derived Types{{@#Simple Declarations and Simple@+Exception
s, Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Control
 Constructs, and@'Generics, Tasking, and Assignment 6`{@&Assignm
ent 2{@H^>  MORE RECORDS AND TYPES`{@#Records, Arrays, and Assig
nment 3{@LAdvanced Topics{}b[ 529B527]@3RECORD DISCRIMINANTS AND
 RECORD VARIANTS{{The definition of a record type can have^discr
iminants`, which have the same{form as formal parameters ("dummy
 arguments") of subprograms, except that the{mode is omitted.  D
efault values may be supplied.  For example,{{@'type Matrix is a
rray(Integer range <>, Integer range <>) of Float;{@'type Square
_Matrix%(Size : Positive := 9)~is{@*record{@-Sq : Matrix%(1 .. S
ize, 1 .. Size)`;{@*end record;{{Although objects of type Matrix
 can be rectangular, objects of type{Square_Matrix must be squar
e.  In declaring these objects, we use the same{syntax as a subp
rogram call, with either positional or named notation:{{@#^A : S
quare_Matrix(7);  -- a 7-by-7 matrix`{@#^B : Square_Matrix(Size 
=> 5);  -- a 5-by-5 matrix`{@#^C : Square_Matrix;  -- a 9-by-9 m
atrix, using the default value of Size`{}b[ 530B528]Of course, s
ubtypes of discriminated records can be declared.  For example,{
{@/^subtype Chess_Board is Square_Matrix(Size => 8);`{{A record 
discriminant is used in the definition of type Text in the{Text_
Handler package specification of section 7.6 of the Ada 83 LRM:{
{@2Maximum : constant := ... ;{@2subtype Index is Integer range 
0 .. Maximum;{@2...{@1^type Text(Maximum_Length : Index) is`{@4^
record`{@7^Pos@#: Index := 0;`{@7^Value : String(1 .. Maximum_Le
ngth);`{@4^end record;`{{With the simplified version of type Tex
t presented earlier, every object of{type Text occupied enough m
emory for the longest string we expected to handle{(e.g., 80 cha
racters).  With this version, each object of type Text that we{c
reate can have just the Maximum_Length we need, and its effectiv
e length Pos{can vary from zero to that Maximum_Length.  The rec
ord discriminant complicates{the package specification only very
 slightly; see the Ada 83 LRM, section 7.6.{}b[ 531B529]The defi
nition of a record type can have a^variant`, which also has the 
same{form as a subprogram formal parameter without the mode.  Ho
wever, the syntax of{a^case~construct is used to specify part of
 the record.  Although a record can{have several discriminants, 
it can have only one variant, and the variant part{must appear l
ast in the record.  For example,{{@8type Sex_Type is (Male, Fema
le);{@8type Person%(Sex : Sex_Type)~is{@;record{@>Age : Natural;
{@=^case Sex is`{@@^when Male =>`{@C^Bearded  : Boolean;`{@@^whe
n Female =>`{@C^Children : Natural;`{@=^end case;`{@;end record;
{{If the sex of the person is Male, we want the record to includ
e a Boolean{showing whether he's bearded, but if the sex is Fema
le, we want the record to{include an Integer (subtype Natural), 
showing the number of children she has.{}b[ 532B530]@8type Sex_T
ype is (Male, Female);{@8type Person(Sex : Sex_Type) is{@;record
{@>Age : Natural;{@>case Sex is{@Awhen Male =>{@DBearded  : Bool
ean;{@Awhen Female =>{@DChildren : Natural;{@>end case;{@;end re
cord;{{Objects are declared and given values as we'd expect:{{  
^John : Person(Sex => Male) := (Sex => Male, Age => 21, Bearded 
=> False);`{  ^Mary : Person(Sex => Female) := (Sex => Female, A
ge => 18, Children => 0);`{{Attempting to reference John.Childre
n or Mary.Bearded will raise{Constraint_Error.  Subtypes may be 
declared as follows:{{@7^subtype Man is Person(Male);`{@7^subtyp
e Woman is Person(Female);`{}b[ 533B531]type Computer_Size is (H
andheld,Notebook,Portable,Desktop,Mainframe,Cluster);{type Compu
ter(Size : Computer_Size) is{@#record{@&K_Mem : Positive;{@&Disk
s : Natural;{@&case Size is{@)when Cluster =>{@,Number_Of_Units 
: Positive;{@,Data_Rate@': Float;{@)when others =>{@,null;{@&end
 case;{@#end record;{My_PC@': Computer(Desktop) := (Desktop, K_M
em => 4096, Disks => 2);  ^-- 1`{Company_LAN : Computer(Cluster)
 := (Cluster, K_Mem => 24576, Disks => 8); ^-- 2`{{Which comment
ed declaration in the above program is^illegal`?{}Please press 1
 or 2, or B to go back.[25341535B532]type Computer_Size is (Hand
held,Notebook,Portable,Desktop,Mainframe,Cluster);{type Computer
(Size : Computer_Size) is{@#record{@&K_Mem : Positive;{@&Disks :
 Natural;{@&case Size is{@)when Cluster =>{@,Number_Of_Units : P
ositive;{@,Data_Rate@': Float;{@)when others =>{@,null;{@&end ca
se;{@#end record;{My_PC@': Computer(Desktop) := (Desktop, K_Mem 
=> 4096, Disks => 2);@#-- 1{%Company_LAN : Computer(Cluster) := 
(Cluster, K_Mem => 24576, Disks => 8);  -- 2`{{%You're right!~ T
he initialization of Company_LAN fails to include fields for{Num
ber_Of_Units and Data_Rate.{}q[ 536B533Q533]type Computer_Size i
s (Handheld,Notebook,Portable,Desktop,Mainframe,Cluster);{type C
omputer(Size : Computer_Size) is{@#record{@&K_Mem : Positive;{@&
Disks : Natural;{@&case Size is{@)when Cluster =>{@,Number_Of_Un
its : Positive;{@,Data_Rate@': Float;{@)when others =>{@,null;{@
&end case;{@#end record;{My_PC@': Computer(Desktop) := (Desktop,
 K_Mem => 4096, Disks => 2);@#-- 1{Company_LAN : Computer(Cluste
r) := (Cluster, K_Mem => 24576, Disks => 8);  -- 2{{No, the decl
aration of My_PC and its initialization are correct.  When Size 
is{Desktop, the^others~clause of the^case~applies, so there are 
no Number_Of_Units{and Data_Rate fields in this case.{}q[ 536B53
3Q533]@4TAGGED RECORDS AND DYNAMIC DISPATCHING{{In Ada 9X, a rec
ord may be^tagged`.  This allows us later to derive a new type{f
rom the original and add fields.  For example, if Day_Of_Week_Ty
pe is suitably{declared along with Day_Subtype and Month_Type, A
da 9X lets us write{{@5type Date is^tagged`{@8record{@;Day@#: Da
y_Subtype;{@;Month : Month_Type;{@;Year  : Integer;{@8end record
;{{@5type Complete_Date is^new~Date^with`{@8record{@;Day_Of_Week
 : Day_Of_Week_Type;{@8end record;{{Now objects of type Date hav
e three fields: Day, Month, and Year, but objects{of type Comple
te_Date have four fields: Day, Month, Year, and Day_Of_Week.{}b[
 537B533]If we want to derive a new type without adding any new 
fields, we write, for{example,{{@2type New_Date is^new~Date^with
 null record;`{{If a tagged record is to be a private type, the 
declaration in the package{specification contains the words^tagg
ed private`, like this:{{@9type Date is^tagged private`;{{The ac
tual structure of the record is declared in the private part of 
the{package specification exactly as any other tagged record:{{@
9private{@<...{@<type Date is^tagged`{@?record{@BDay@#: Day_Subt
ype;{@BMonth : Month_Type;{@BYear  : Integer;{@?end record;{}b[ 
538B536]We can convert objects of a derived type to the parent t
ype.  For example, if{we have^CD : Complete_Date;~we can write^D
ate(CD)`.  This is useful in making{software reusable.  For exam
ple, suppose we have written a procedure to Display{a Date:{{@8p
rocedure Display(D : in Date);{{If we now wish to write a proced
ure to Display a Complete_Date, we could call{on the procedure w
e've already written.  If the above procedure and the{associated
 types are defined in package P, we could write:{{@)with Text_IO
, P; use P;{@)procedure Display(CD : in Complete_Date) is{@,-- C
all previous procedure to display the first 3 fields.{@+^Display
(Date(CD));`{@,-- Now display the fourth field.{@,Text_IO.Put_Li
ne(Day_Of_Week_Type'Image(CD.Day_Of_Week));{@)end Display;{{Thus
 the procedure to display a Date was reused when we wrote the pr
ocedure to{display a Complete_Date.{}b[ 539B537]Although type Da
te and the types derived from it are all different types, we{can
 refer to all the types collectively as^Date'Class`.  The attrib
ute^'Class`{can be applied to the name of any tagged type.  If w
e declare an object to be{of type^Date'Class`, we must initializ
e it so that the compiler will know the{exact type of the object
.  The type of this object can't change at run time.{For example
, if we write^D : Date'Class := Date'(12, Dec, 1815);~we can't l
ater{write^D := Complete_Date'(4, Jul, 1776, Thu);`.  This would
 change the type of{the object D and make it grow larger by addi
ng a new field, Day_Of_Week.  This{isn't permitted.{{However, we
 can declare an access type to Date'Class without being specific
{about the exact type to be accessed:{{@8type Ptr is access^Date
'Class`;{{Now objects of type Ptr can point to objects of type D
ate at one time and to{objects of type Complete_Date at another.
  Also, we could build a linked list,{with some of the links of 
type Date and some of type Complete_Date.  This is{called a^hete
rogeneous~linked list.{}b[ 540B538]Let's suppose that we declare
, in the specification for a package P, type Date{(a tagged reco
rd), type Complete_Date derived from Date with an extra field,{a
nd two overloaded procedures Display, one to display a Date and 
one to display{a Complete_Date.  Suppose that the specification 
for P also includes the{definition for type Ptr:{{@8type Ptr is 
access^Date'Class`;{{Now suppose that our program, which^with`s 
and^use`s P, declares an array A of{two pointers of type Ptr.  L
et A(1) point to a Date and A(2) point to a{Complete_Date.  The 
program to follow shows how the system will decide^at run{time~w
hich of two overloaded versions of Display to call, depending on
 the type{of A(I).all:{}b[ 541B539]@$package P is{@'...{@'type D
ate is^tagged~record ...{@'type Complete_Date is^new~Date^with~r
ecord ...{@'type Ptr is access^Date'Class`;{@'procedure Display(
D : in Date);{@'procedure Display(D : in Complete_Date);{@$end P
;{{@$with P; use P;{@$procedure Dynamic_Dispatching_Demo is{@'A 
: array(1 .. 2) of Ptr;{@$begin{@'A(1) := new Date'(12, Dec, 181
5);{@'A(2) := new Complete_Date'(4, Jul, 1776, Thu);{@'for I in 
A'Range loop{@*Display(%A(I).all`);  -- Decides at run time whic
h Display to call.{@'end loop;{@$end Dynamic_Dispatching_Demo;{{
This is called^dynamic dispatching~or^tagged type dispatching`, 
and is available{only in Ada 9X, not in Ada 83.{}b[ 542B540]In A
da 9X, the formal parameters ("dummy arguments") of a subprogram
 may also{be of a class-wide type.  For example, in a package th
at has defined both of{our Display procedures and the associated
 types, we can write:{{@)procedure Show(X : in^Date'Class`) is{@
)begin{@,Display(%X`);  -- Decides at run time which Display to 
call.{@)end Show;{{It this case, the exact type of X is not know
n until run time, and can vary{from one call of Show to the next
.  Therefore, the statement^Display(X);~will{decide at run time 
which version of Display to call.{{Related to this are^access pa
rameters~in Ada 9X.  Instead of writing{{@6procedure Show(X :^in
~Date'Class);{{we can write{{@4procedure Show(X :^access~Date'Cl
ass);{}b[ 543B541]@4procedure Show(X :^access~Date'Class);{{In t
his case, Show is no longer called with an object belonging to D
ate'Class{(that is, a Date or a Complete_Date), but rather with 
an object of any access{type pointing to objects belonging to Da
te'Class.  For example, we could now{call Show with an object of
 the type Ptr we defined earlier:{{@/D : Ptr := new Complete_Dat
e(4, Jul, 1776, Thu);{@/Show(D);{{Show again decides at run time
 which version of Display to call, but now Show{must dereference
 the access value passed to it:{{@'procedure Show(X :^access~Dat
e'Class) is{@'begin{@*Display(%X.all`);  -- Decides at run time 
which Display to call.{@'end Show;{}b[ 544B542]The^accessibility
 check~which we discussed earlier when we talked about access{ty
pes has to be performed at run time in the case of access parame
ters.  The{Ada 9X compiler automatically generates code to do th
is.  For access types{pointing to named objects, discussed earli
er, the accessibility check is{performed at compile time.  In bo
th cases the purpose of the accessibility{check is to insure tha
t no object of an access type can ever point to an object{that n
o longer exists.{{Here's our sample tagged type dispatching prog
ram, rewritten to make use of{access parameters:{}b[ 545B543]@#p
ackage P is{@&...{@&type Date is tagged record ...{@&type Comple
te_Date is new Date with record ...{@&type Ptr is access Date'Cl
ass;{@&procedure Display(D : in Date);{@&procedure Display(D : i
n Complete_Date);{@%^procedure Show(X : access Date'Class);  -- 
Body calls Display(X.all);`{@#end P;{{@#with P; use P;{@#procedu
re Dynamic_Dispatching_Demo is{@&A : array(1 .. 2) of Ptr;{@#beg
in{@&A(1) := new Date'(12, Dec, 1815);{@&A(2) := new Complete_Da
te'(4, Jul, 1776, Thu);{@&for I in A'Range loop{@(^Show(A(I));`{
@&end loop;{@#end Dynamic_Dispatching_Demo;{{Again, the^for~loop
 first displays a Date and then displays a Complete_Date.{}b[ 54
6B544]@4ABSTRACT TYPES AND ABSTRACT SUBPROGRAMS{{@+package P is{
@.type Abstract_Date is^abstract~tagged null record;{@.procedure
 Display(%AD : in Abstract_Date`)^is abstract`;{@+end P;{{In thi
s example for Ada 9X only, type Abstract_Date is an^abstract typ
e`.  We{can't declare objects of that type, but we can derive ot
her types from it.  For{example, we can derive type Date by addi
ng three fields, and then derive type{Complete_Date from type Da
te by adding one more field.{{The^abstract procedure~does not ha
ve a body, only a specification.  However, it{lets us write proc
edures built around types derived from the abstract type.{For ex
ample, we could write overloaded procedures Display for types Da
te and{Complete_Date (these procedures will have bodies as well 
as specifications).{Also, by declaring an access type to type Ab
stract_Date, we could again make{use of dynamic dispatching to o
ur overloaded versions of Display:{}b[ 547B545]@%package P is{@(
type Abstract_Date is abstract tagged null record;{@(procedure D
isplay(AD : in Abstract_Date) is abstract;{@%end P;{{@%with P; u
se P;{@%package Q is{@(...{@(type Ptr is access Abstract_Date;{@
(type Date is new Abstract_Date with record ... -- Day, Month, Y
ear{@(type Complete_Date is new Date with record ... -- Day_Of_W
eek{@(procedure Display(D : in Date);{@(procedure Display(CD : i
n Complete_Date);{@%end Q;{{The advantage of this is that we can
 write package P, with all its abstract{procedures, before we wr
ite the code in package Q detailing what the derived{types (Date
 and Complete_Date) look like.{}b[ 548B546]@3FIXED POINT, MODULA
R, AND UNIVERSAL TYPES{{The only fixed point type defined in pac
kage Standard is Duration.  However,{Ada lets us define our own 
fixed point types.  We specify the accuracy with the{reserved wo
rd^delta`, and a range constraint is required.  For example,{{@/
^type Voltage is delta 0.01 range -20.0 .. 20.0;`{{This guarante
es that the objects of type Voltage will be represented with at{
least an accuracy of 1/100.  Since the computer is binary, Ada w
ill choose an{internal representation at least as accurate as 1/
128.  It might use even{greater accuracy, for example, 1/256.  I
n any event, it's guaranteed that the{accuracy is at least as go
od as that requested.{{It's possible to make a request that a pa
rticular implementation of Ada can't{handle.  For example, if we
 write{{@.^type Voltage is delta 1.0E-10 range 0.0 .. 1.0E9;`{{t
he Ada compiler that we're using may have to report that it has 
no internal{representation that satisfies this requirement.  (Al
most any^delta~would be{unreasonable if Ada didn't require range
 constraints on all fixed point types.){}b[ 549B547]@0type Volta
ge is delta 0.01 range -20.0 .. 20.0;{{The set of numbers that c
an be represented exactly by any Ada that accepts a{type definit
ion like the above is called the^model numbers~of that type.  Th
is{applies to floating types as well as fixed, for example,{{@4^
type W is digits 5 range 0.0 .. 100.0;`{{A particular implementa
tion may represent additional numbers exactly; these are{called^
safe numbers`.  The safe numbers are a superset of the model num
bers;{their range usually is a little larger.{{We can add and su
btract objects of a fixed point type.  However, if we multiply{o
r divide them in Ada 83, we must immediately convert the result 
to the same or{another numeric type before we can store it.  For
 example,{{@,^V1, V2, V3 : Voltage;`{@-...{@,^V1 := V2 + V3;  --
 legal`{@,^V1 := V2 * V3;  -- illegal in Ada 83, legal in Ada 9X
`{@,^V1 := Voltage(V2 * V3);  -- legal`{}b[ 550B548]In Ada 9X, w
e can multiply two numbers of a fixed point type without an{expl
icit type conversion if the type of the multiply is uniquely det
ermined.{In the previous example,{{@,^V1, V2, V3 : Voltage;`{@-.
..{@,^V1 := V2 * V3;  -- illegal in Ada 83, legal in Ada 9X`{{th
e multiplication is legal in Ada 9X because storing the result i
nto V1{uniquely determines the type of the product of V2 and V3.
{{Note that^V1 := V1 * V2 * V3~is illegal because the intermedia
te result has no{uniquely determined type.{{Also note that if we
 have^procedure Display(V : in Voltage);~then in Ada 9X we{can w
rite{{@>^Display(V2 * V3);`{{because the type of V2 * V3 is uniq
uely determined by the procedure call.{{Text_IO contains a gener
ic package Fixed_IO for I/O of fixed point types.{}b[ 551B549]Ad
a 9X also provides^modular types`.  These are unsigned integers,
 and the{arithmetic is performed modulo a specified number so th
at overflow can never{occur.  For example, in Ada 9X we can writ
e:{{@7^type Unsigned_Byte is mod 256;`{{The modulus doesn't have
 to be a power of two, but it often is.  If we now{declare^A : U
nsigned_Byte := 100;~and^B : Unsigned_Byte := 200;~then the resu
lt{of^A + B~will be 300 mod 256, or 44.{{In Ada 9X, the package^
Interfaces~is supplied, and it defines a modular type{for each s
igned integer type.  For example, an implementation of Ada 9X mi
ght{define the types^Unsigned_8`,^Unsigned_16`, and^Unsigned_32`
.  Type^Unsigned_8`{corresponds to the example^Unsigned_Byte~abo
ve.{}b[ 552B550]When we declare a variable in Ada, we give its t
ype.  But when we declare a{constant, we may or may not give its
 type.  For example,{{@3^L  : constant Integer := 30;`{@3^M  : c
onstant := 1000;`{@3^E  : constant Float := 2.718281828;`{@3^Pi 
: constant := 3.141592654;`{{Also, when we write a number, such 
as 3.0 or 29_999, we usually don't qualify{it with a type (for e
xample,^Float'(3.0)`).{{Suppose an implementation of Ada provide
s types Integer, Long_Integer, Float,{and Long_Float.  How can A
da determine the types of M, Pi, 3.0, and 29_999?  M{and 29_999 
are said to be of type^universal_integer`; they can assume any{i
nteger type as required.  Pi and 3.0 are said to be of type^univ
ersal_real~and{can assume any floating or fixed point type as re
quired.{{We can't explicitly declare objects to be of universal 
types.  However, we can{write{}b[ 553B551]@9M  : constant := 100
0;{@9Pi : constant := 3.141592654;{@8^I  : Integer;`{@8^LI : Lon
g_Integer;`{@8^F  : Float;`{@8^LF : Long_Float;`{@9...{@8^I := M
;  LI := M;`{@8^I := 29_999;  LI := 29_999;`{@8^F := Pi;  LF := 
Pi;`{@8^F := 3.0;  LF := 3.0;`{{and in each case the constant as
sumes the correct type.  The result of{multiplying or dividing t
wo numbers of a fixed point type is said to be of type{%universa
l_fixed`.  This result must be explicitly converted to some nume
ric{type before it can be stored.{{Most of the attributes that p
roduce integer results, like^Pos`, are of type{universal_integer
.  For example, with the declarations above, we could write{{@:^
I  := Character'Pos('A');`{@:^LI := Character'Pos('A');`{}b[ 554
B552]Which one of the following declarations is^illegal`?{{{@.1.
@#type Rate is digits 6;{{@.2.@#type Distance is digits 6 range 
0.0 .. 1.0E6;{{@.3.@#type Current is delta 0.1;{{@.4.@#type Temp
 is delta 0.05 range -200.0 .. 450.0;{}Please press 1, 2, 3, or 
4, or B to go back.[3555155625574558B553]@.1.@#type Rate is digi
ts 6;{{@.2.@#type Distance is digits 6 range 0.0 .. 1.0E6;{{@-^3
.@#type Current is delta 0.1;`{{@.4.@#type Temp is delta 0.05 ra
nge -200.0 .. 450.0;{{{%You're right!~ A fixed point type declar
ation must have a range constraint.{}q[ 559B554Q554]@.1.@#type R
ate is digits 6;{{@.2.@#type Distance is digits 6 range 0.0 .. 1
.0E6;{{@.3.@#type Current is delta 0.1;{{@.4.@#type Temp is delt
a 0.05 range -200.0 .. 450.0;{{{No, number 1 is legal.  A user d
efined floating point type need not have a{range constraint.{}q[
 559B554Q554]@.1.@#type Rate is digits 6;{{@.2.@#type Distance i
s digits 6 range 0.0 .. 1.0E6;{{@.3.@#type Current is delta 0.1;
{{@.4.@#type Temp is delta 0.05 range -200.0 .. 450.0;{{{No, num
ber 2 is legal.  A user defined floating point type may have a r
ange{constraint.{}q[ 559B554Q554]@.1.@#type Rate is digits 6;{{@
.2.@#type Distance is digits 6 range 0.0 .. 1.0E6;{{@.3.@#type C
urrent is delta 0.1;{{@.4.@#type Temp is delta 0.05 range -200.0
 .. 450.0;{{{No, number 4 is legal.  A fixed point type declarat
ion must have a range{constraint.{}q[ 559B554Q554]@;^ADA-TUTR CO
URSE OUTLINE`{{{@#Introduction@=Recursion and Assignment 4{{@#Th
e Format of an Ada Program@-Subprograms and Packages`{{@#Generic
 Instantiation and@0Access Types, User Defined Types,{@&Assignme
nt 1@=and Derived Types{{@#Simple Declarations and Simple@+Excep
tions, Text_IO, and{@&Attributes@?Assignment 5{{@#Operators, Con
trol Constructs, and@'Generics, Tasking, and Assignment 6{@&Assi
gnment 2{@LMore Records and Types{@#Records, Arrays, and Assignm
ent 3{@H^>  ADVANCED TOPICS`{}b[ 560B554]@DRENAMING{{A subprogra
m can be renamed in Ada.  This allows us to avoid the dot notati
on{without a^use~clause.  For example, if our program^with`s Tex
t_IO, we can write:{{@(^procedure Print(Object : in String) rena
mes Text_IO.Put_Line;`{{We can now call Print instead of Text_IO
.Put_Line.  The old name is still{available.  Note that renaming
 can change the names of the formal parameters{("dummy arguments
").  Renaming can also add, delete, or change default values.{Wh
en used in a package, a renaming declaration like the above goes
 in the{%specification`, not the body.  In Ada 9X, the specifica
tion can say simply{%procedure Print(Object : in String);`, and 
the package^body~can supply the body{of Print with the^renames~d
eclaration above.{{We can also rename task entries as procedures
.  This is the only way to avoid{the dot notation when calling a
 task entry.{{A function can be renamed as an infix operator, if
 it has the right number and{types of parameters.  Also, an infi
x operator can be renamed as a function.{For example, earlier we
 defined type Vector and wrote:{}b[ 561B559]@-^function "*"(Left
, Right : in Vector) return Float;`{{This could be renamed as fo
llows:{{@'^function Dot_Product(X, Y : in Vector) return Float r
enames "*";`{{Renaming can get around the restriction that libra
ry subprograms can't be infix{operators.  We can use a normal fu
nction name for the library, and rename it as{an infix operator 
for our program.  Similarly, we can get around the rule that{lib
rary subprograms can't overload each other.  We can give subprog
rams{distinct names in the library, and rename them in our progr
am to overload each{other.{{An attribute that takes a parameter,
 such as^Pred~and^Succ`, can be renamed as a{function.  Record c
omponents can be renamed.  If^D~is of the type^Date~we had{earli
er, we can write^J : Integer renames D.Year;`.  Exceptions can a
lso be{renamed, as in^No_Such_File : exception renames Text_IO.N
ame_Error;`.{{A subtype can be used to achieve the effect of ren
aming a type, for example,{%subtype File is Text_IO.File_Type;`.
{}b[ 562B560]@:PACKAGES STANDARD AND ASCII{{Ada comes with a pac
kage Standard.  However, unlike all the other packages,{Standard
 is needed by^every~Ada compilation unit.  Therefore, Standard i
s{automatically^with`ed and^use`d in every compilation.  It need
 not be mentioned{in a context clause.  Standard contains the de
finitions built into the Ada{language, such as^type Boolean is (
False, True);`.  A listing of the package{specification is in Ap
pendix C of the LRM.  Thus, the full name for the type{Boolean i
s Standard.Boolean, the full name for Integer is Standard.Intege
r,{etc.  Naturally, this normally need not concern the programme
r.  The dot{notation is automatic because Standard is automatica
lly^use`d in every{compilation.{{However, inside package Standar
d is a package ASCII.  Since this package is{part of Standard, w
e never have to write a^with~clause for it.  But ASCII isn't{aut
omatically^use`d.  If we want the dot notation for ASCII to be a
utomatic, we{have to provide a^use~clause.  As the listing in th
e LRM shows, ASCII contains{names for all the unprintable ASCII 
characters, such as BEL, ESC, etc.  It also{provides names for m
any punctuation marks, in case your terminal or printer{doesn't 
have them.  For example, Dollar, At_Sign, etc.  Finally, it prov
ides{names for all lower case letters, from LC_A to LC_Z.{}b[ 56
3B561]For example, either of the following programs will display
^a$b~and ring the{bell or beep the terminal:{{@'with Text_IO; us
e Text_IO;{@'procedure Ab is{@'begin{@*Put_Line(%ASCII.LC_A & AS
CII.Dollar & ASCII.LC_B & ASCII.BEL`);{@'end Ab;{{@'with Text_IO
; use Text_IO;{@'procedure Ab is{@)^use ASCII;`{@'begin{@*Put_Li
ne(%LC_A & Dollar & LC_B & BEL`);{@'end Ab;{{Note the placement 
of^use ASCII;~in the second example.  It's similar to the{placem
ent of^use My_Int_IO;~in ADD.ADA, which we discussed early in th
e course.{}b[ 564B562]@8AN ALTERNATIVE TO INFIX NOTATION{{Earlie
r we learned to define and use infix operators like{{@.type Vect
or is array(Integer range <>) of Float;{@-^function "*"(Left, Ri
ght : in Vector) return Float;`{@.A, B : Vector(1 .. 10);{@.F@$:
 Float;{@....{@-^F := A * B;`{{An alternative notation equivalen
t to^F := A * B;~is^F := "*"(A, B);`.  Why{would anyone want to 
use this clumsier notation?  If our function is in a{package Mat
h that the calling program^with`s but for some reason doesn't^us
e`, we{could use dot notation and write^F := Math."*"(A, B);`.  
But we couldn't use dot{notation directly with infix operators, 
as in F := A Math.* B; or even{F := A Math."*" B;.  Both of thos
e are illegal.  The alternative notation can{also be used to emp
hasize that an operator comes from package Standard.  For{exampl
e, if I, J, and K are Integers, we could write^I := Standard."*"
(J, K);`,{which is equivalent to^I := J * K;`.{}b[ 565B563]Assum
ing X, Y, and Z have been declared Float, which one of the follo
wing is{%illegal`?{{@:1.  X := Y / Z;{{@:2.  X := Y Standard."/"
 Z;{{@:3.  X := Standard."/"(Y, Z);{}Please press 1, 2, or 3, or
 B to go back.[256615673568B564]@:1.  X := Y / Z;{{@9^2.  X := Y
 Standard."/" Z;`{{@:3.  X := Standard."/"(Y, Z);{{{%You're righ
t!~ The syntax of number 2 is illegal.  To specify the package{S
tandard, we have to use the syntax of number 3.  Normally, of co
urse, the{syntax of number 1 is used.{}q[ 569B565Q565]@:1.  X :=
 Y / Z;{{@:2.  X := Y Standard."/" Z;{{@:3.  X := Standard."/"(Y
, Z);{{{No, number 1 is the syntax that would ordinarily be used
 for division, and is{legal.{}q[ 569B565Q565]@:1.  X := Y / Z;{{
@:2.  X := Y Standard."/" Z;{{@:3.  X := Standard."/"(Y, Z);{{{N
o, number 3 is the correct way to specify package Standard expli
citly.{}q[ 569B565Q565]@@MORE ATTRIBUTES{{Ada provides a wide va
riety of attributes.  All of them are listed and defined{in Appe
ndix A of the LRM.  The most important ones that we haven't yet{
discussed are these:{{%First~and^Last~can be used with any scala
r type or subtype (including floating{and fixed), not just discr
ete types and subtypes.  For example,^Float'Last~is{the highest 
number your particular Ada represents with type Float.{{For any 
real type or subtype (floating or fixed),^Small~and^Large~are th
e{smallest and largest positive model numbers.  Thus^Float'Small
~is the{difference between zero and the next larger number in ty
pe Float.  Also, for{any floating point (sub)type,^Epsilon~is th
e difference between^one~and the{next larger number.  We'll use^
Epsilon~in a generic function later.{{For a floating point (sub)
type,^Digits~returns the value given for^digits~in{the declarati
on, and for a fixed point (sub)type,^Delta~returns the value giv
en{for^delta~in the declaration.  These attributes may not seem 
too useful,{because the programmer already knows what he or she 
wrote in the declarations.{However, they're useful in generic pa
ckages and subprograms.  For example, if{the generic part says^t
ype Dummy is delta <>;`, the body can use^Dummy'Delta`.{}b[ 570B
554]For any discrete (sub)type,^Width~gives the maximum length t
hat the attribute{%Image~can produce. ^Boolean'Width~is 5 becaus
e "False" has length 5.  With our{earlier definition of Rainbow_
Color,^Rainbow_Color'Width~is 6.  For versions of{Ada using 16-b
it Integers,^Integer'Width~is also 6, the length of "-32768".{{%
Count~is used with the name of a task entry.  It returns the num
ber of calls{presently queued on the entry. ^Terminated~is of ty
pe Boolean.  It's used with{a task name, and tells if the task i
s terminated.{{Let's write a generic function to compute the squ
are root for any floating{point type, using Newton-Raphson itera
tion.  This method simply says that if G{is a guess of the squar
e root of X, the next guess is the average of G and X/G.{For exa
mple, if we want to compute the square root of 9.0 and our first
 guess{is 9.0, successive guesses are 5.0, 3.4, 3.02352941, 3.00
009155, 3.00000000.{Note that convergence is very rapid.  Howeve
r, the problem in writing a program{like this is knowing when to
 stop the iteration.  We'll use the attribute{%Epsilon`.  Since 
G*G/X should be 1.0, we'll quit when the absolute value of the{d
ifference between G*G/X and 1.0 is less than or equal to 3.0 tim
es Epsilon.{Recall that^Dummy'Epsilon~is the difference between 
1.0 and the next higher{number for type Dummy.  If we use 1.0 ti
mes Epsilon, the loop might never{terminate, and if we use 10.0 
times Epsilon, we might not get full precision.{So we'll use 3.0
 times Epsilon.  Here's our function:{}b[ 571B569] ^generic`{@$^
type Dummy is digits <>;`{ ^function Sqrt(X :in Dummy) return Du
mmy;`{ ^function Sqrt(X :in Dummy) return Dummy is`{@$^Guess : D
ummy := X;`{ ^begin`{@$^if X < 0.0 then`{@'^raise Constraint_Err
or;`{@$^end if;`{@$^while X /= 0.0 and then abs(Guess*Guess/X - 
1.0) > 3.0*Dummy'Epsilon loop`{@'^Guess := (X/Guess + Guess) * 0
.5;`{@$^end loop;`{@$^return Guess;`{ ^end Sqrt;`{{We tested our
 Sqrt with an implementation of Ada having types Float,{Long_Flo
at, and Long_Long_Float.  The last gives at least 33 decimal dig
its of{precision.  Sqrt was instantiated for all three floating 
point types, as was{Float_IO to display the results.  When teste
d with the three types, all{displayed digits of the answers were
 correct.{}b[ 572B570]@:SEQUENTIAL_IO AND DIRECT_IO{{Text_IO cre
ates, reads and writes text files that can be typed on the scree
n or{printed.  Ada also provides packages^Sequential_IO~and^Dire
ct_IO,~which create,{read, and write binary files.  These files 
usually can't be typed or printed,{but they tend to be more effi
cient than text files, because the computer{doesn't have to conv
ert numbers between its internal representation and ASCII{to rea
d and write binary files.{{Sequential_IO and Direct_IO are both 
generic, and can be instantiated for any{type.  The specificatio
ns are in sections 14.2.3 and 14.2.5 of the LRM.  Like{Text_IO, 
they have procedures to Create, Open, and Close files, but the I
/O{procedures are called Read and Write, rather than Put, Get, P
ut_Line, and{Get_Line.  Sequential_IO always reads and writes se
quentially, but Direct_IO is{capable of random access.  In Direc
t_IO, an optional extra parameter in Read{and Write tells the pr
ocedure the position in the file to read From or write{To.{{Text
_IO and instantiations of Sequential_IO and Direct_IO each defin
e their^own`{File_Type, so we can't open a file with one package
 and then do I/O with{another.  Direct_IO provides a File_Mode o
f Inout_File as well as the usual{In_File and Out_File.{}b[ 573B
571]If you like, you can examine the file ADA_TUTR.ADA for an ex
ample of the use of{Direct_IO. ^ADA-TUTR~creates a subtype for a
 block of characters and then{instantiates Direct_IO for that su
btype.  It then opens ADA_TUTR.DAT with mode{In_File so that it 
can read blocks of characters by random access.  This{enables^AD
A-TUTR~to find and display any screen quickly.  The preliminary{
comments in ADA_TUTR.ADA describe the format of the data file AD
A_TUTR.DAT in{detail.{{You may also want to examine the files DA
T2TXT.ADA and TXT2DAT.ADA.  These two{programs are used when ins
talling^ADA-TUTR~on non-PC computers.  Their use is{described on
 pages 42-43 of your printed course notes.  They^with~both Text_
IO{and Direct_IO, because they access a text file as well as a r
andom access file.{However, to avoid confusion between the two p
ackages, they^use~neither Text_IO{nor the instantiation of Direc
t_IO.  Dot notation is used instead.{}b[ 574B572]Which commented
 line is^illegal`?{{@$with Text_IO, Sequential_IO; use Text_IO, 
Sequential_IO; ^-- 1`{@$procedure IO is{@'subtype Line is String
(1 .. 80);{@'type Screen is array(1 .. 24) of Line;{@'package Li
ne_IO is new Sequential_IO(Line); use Line_IO; ^-- 2`{@'package 
Screen_IO is new Sequential_IO(Screen); use Screen_IO; ^-- 3`{@$
begin{@'null;{@$end IO;{}Please press 1, 2, or 3, or B to go bac
k.[157525763577B573]@#^with Text_IO, Sequential_IO; use Text_IO,
 Sequential_IO;  -- 1`{@$procedure IO is{@'subtype Line is Strin
g(1 .. 80);{@'type Screen is array(1 .. 24) of Line;{@'package L
ine_IO is new Sequential_IO(Line); use Line_IO;  -- 2{@'package 
Screen_IO is new Sequential_IO(Screen); use Screen_IO;  -- 3{@$b
egin{@'null;{@$end IO;{{%You're right!~ We can't^use~a generic p
ackage, only its instantiations,{because we can't call the subpr
ograms in a generic package.  The first line{should read{{@/^wit
h Text_IO, Sequential_IO; use Text_IO;  -- 1`{}q[ 578B574Q574]@$
with Text_IO, Sequential_IO; use Text_IO, Sequential_IO;  -- 1{@
$procedure IO is{@'subtype Line is String(1 .. 80);{@'type Scree
n is array(1 .. 24) of Line;{@'package Line_IO is new Sequential
_IO(Line); use Line_IO;  -- 2{@'package Screen_IO is new Sequent
ial_IO(Screen); use Screen_IO;  -- 3{@$begin{@'null;{@$end IO;{{
No, the instantiation of Sequential_IO for the subtype Line is c
orrect.{}q[ 578B574Q574]@$with Text_IO, Sequential_IO; use Text_
IO, Sequential_IO;  -- 1{@$procedure IO is{@'subtype Line is Str
ing(1 .. 80);{@'type Screen is array(1 .. 24) of Line;{@'package
 Line_IO is new Sequential_IO(Line); use Line_IO;  -- 2{@'packag
e Screen_IO is new Sequential_IO(Screen); use Screen_IO;  -- 3{@
$begin{@'null;{@$end IO;{{No, the instantiation of Sequential_IO
 for the type Screen is correct.{}q[ 578B574Q574]@6SUBPROGRAM PA
RAMETERS WITH GENERICS{{The generic part of a subprogram or pack
age can specify a dummy^subprogram~as{well as a dummy^type`.  Th
is is similar to using subprograms as parameters{in Algol and Pa
scal, and to using the little-known keyword EXTERNAL in Fortran.
{In Ada, we simply precede the dummy subprogram specification wi
th the keyword{%with~in the generic part.  This use of the word^
with~has nothing to do with{context clauses.  Here's the specifi
cation of a generic function that has one{dummy function specifi
cation in the generic part:{{^generic`{@#^with function Dummy(X 
: in Float) return Float;`{^function Definite_Integral(Lower_Lim
it, Upper_Limit : in Float) return Float;`{{We could then write 
a function Cos, instantiate Definite_Integral for it, and{use th
e instantiation as follows:{{^Answer : Float;`{^function Cos(X :
 in Float) return Float;`{^function Definite_Integral_Of_Cos is 
new Definite_Integral(Cos);`{ ...{^Answer := Definite_Integral_O
f_Cos(Lower_Limit => 0.0, Upper_Limit => 1.5708);`{}b[ 579B574]g
eneric{  ^with function Dummy(X : in Float) return Float;`{funct
ion Definite_Integral(Lower_Limit, Upper_Limit : in Float) retur
n Float;{{function Definite_Integral(Lower_Limit, Upper_Limit : 
in Float) return Float is{@#Mult : array(0 .. 6) of Float := (1.
0, 4.0, 2.0, 4.0, 2.0, 4.0, 1.0);{@#Sum  : Float := 0.0;{@#X@$: 
Float;  -- the independent variable{begin{@#for I in 0 .. 6 loop
{@&X@#:= Lower_Limit + (Float(I) / 6.0) * (Upper_Limit - Lower_L
imit);{@&Sum := Sum + Mult(I) *^Dummy(X)`;{@#end loop;{@#return 
Sum * (Upper_Limit - Lower_Limit) / 18.0;{end Definite_Integral;
{{This is one possible body for the generic function Definite_In
tegral.  (The{specification is repeated for reference.)  This fu
nction integrates the{function Dummy between the two limits by e
valuating Dummy at seven points and{using Simpson's rule.  (Defi
nite_Integral could be improved by making the{number of points a
 generic parameter, instead of fixing it at seven.){}b[ 580B578]
@7REPRESENTATION CLAUSES AND SYSTEM{{Ada normally represents an 
enumeration type internally with successive integers{starting at
 zero.  For example, if we write{{@0^type Command is (Left, Righ
t, Forward, Back);`{{the compiler will normally represent Left w
ith 0, Right with 1, etc.  Usually{this doesn't concern the prog
rammer.  However, after the above declaration, we{can specify th
e internal representation with a^representation clause~like this
:{{@&^for Command use (Left => 1, Right => 2, Forward => 4, Back
 => 8);`{{We might want to do that if, for example, we're sendin
g a value of type Command{to some hardware which will interpret 
the bit patterns.  The values must be{assigned in increasing ord
er with no duplications, but gaps are permitted.  The{attributes
 Succ, Pred, Pos, and Val are^not~affected.  Thus^Command'Pos(Ba
ck)`{is still 3.{{We can specify the^Size`, in bits, of the obje
cts of a given type:{}b[ 581B579]@9^type Num is range 0 .. 100;`
{@9^for Num'Size use 8;`{{We can specify the^Storage_Size~for a 
task type and for a collection of{%access`ed objects like a link
ed list.  If^Monitor~is a task and the{specification for our lin
ked list says^type P is access Link;`, we can write{{@5^for Moni
tor'Storage_Size use 16_384;`{@5^for P'Storage_Size use 32_768;`
{{The attributes Size and Storage_Size can also be used in the u
sual way:{{@5^I : Integer := Monitor'Storage_Size;`{{We can spec
ify the attribute Small for a fixed point type:{{@/^type Voltage
 is delta 0.01 range -20.0 .. 20.0;`{@/^for Voltage'Small use 1.
0/128.0;`{{Before discussing the remaining types of representati
on clauses, we must{briefly mention the package^System~that come
s with Ada. ^System~contains{implementation dependent specificat
ions.{}b[ 582B580]A brief outline of package System is in sectio
n 13.7 of the LRM.  However, the{full package specification shou
ld appear in the documentation that came with{your compiler.  Fo
r all compilers that meet the Ada Standard, the description{of i
mplementation dependent features (including the specification of
 package{System) is always in Appendix F of the documentation.  
Of interest here is the{type Address.  In our examples, we'll as
sume that System.Address is some{integer type.  (Under DOS, type
 System.Address may be a bit more complicated.){{Representation 
clauses can use the reserved word^at~followed by a constant of{t
ype System.Address to specify the absolute address of a variable
, a constant,{a task entry, a procedure, or a package.  The pack
age System must be visible.{This feature is useful for memory-ma
pped I/O and interrupt handlers, etc.  For{example:{{@5Modem_Con
trol : Integer;{@4^for Modem_Control use at 16#7C00#;`{@5task In
terrupt_Handler is{@8entry Clock_Interrupt;{@7^for Clock_Interru
pt use at 16#100#;`{@5end Interrupt_Handler;{@5procedure Keystro
ke;{@4^for Keystroke use at 16#200#;`{}b[ 583B581]Finally, we ca
n use^at`,^mod`, and^range~to specify how records are stored.{Fo
r example,{{@3type Very_Short_Integer is range 0 .. 15;{@3type P
acked is{@6record{@9A, B, C, D : Very_Short_Integer;{@6end recor
d;{@2^for Packed use`{@5^record at mod 2;`{@8^A at 0 range 0 .. 
3;`{@8^B at 0 range 4 .. 7;`{@8^C at 1 range 0 .. 3;`{@8^D at 1 
range 4 .. 7;`{@5^end record;`{{This forces A and B to be stored
 in bits 0 .. 3 and 4 .. 7 of byte 0 of the{record, and C and D 
to be packed into byte 1.  The optional clause^record at{mod 2;~
specifies that all records of type Packed will begin at even add
resses.{{An implementation of Ada need not accept most represent
ation clauses to meet{the standard.  If any clause is rejected, 
an error message will be displayed.{}b[ 584B582]@0type Answer is
 (Yes, No, Maybe);{@0for Answer use (Yes => 1, No => 2, Maybe =>
 4);{{What is Answer'Val(2)?{{{1.  Answer'Val(2) is No.{{2.  Ans
wer'Val(2) is Maybe.{}Please press 1 or 2, or B to go back.[2585
1586B583]@/^type Answer is (Yes, No, Maybe);`{@0for Answer use (
Yes => 1, No => 2, Maybe => 4);{{{%You're right!~ The representa
tion clause doesn't affect the attributes Pos and{Val, and posit
ions are numbered from zero.  So^Answer'Val(2)~is^Maybe`.{}q[ 58
7B584Q584]@0type Answer is (Yes, No, Maybe);{@0for Answer use (Y
es => 1, No => 2, Maybe => 4);{{{No, the representation clause d
oesn't affect the attributes Pos and Val, and{positions are numb
ered from zero.  So Answer'Val(2) is Maybe.{}q[ 587B584Q584]@0UN
CHECKED CONVERSION AND UNCHECKED DEALLOCATION{{Ada comes with a 
generic function^Unchecked_Conversion~and a generic procedure{%U
nchecked_Deallocation`.  They can be instantiated for any type. 
 Both are{somewhat dangerous to use, but we'll describe them bri
efly.  Their{specifications are:{{@+^generic`{@.^type Source is 
limited private;`{@.^type Target is limited private;`{@+^functio
n Unchecked_Conversion(S : SOURCE) return Target;`{{@+^generic`{
@.^type Object is limited private;`{@.^type Name@#is access Obje
ct;`{@+^procedure Unchecked_Deallocation(X : in out Name);`{{Unc
hecked_Conversion "converts" from one type to another without do
ing any{arithmetic or bit manipulation.  In other words, it lets
 us look at an object{of one type as if it were of another type.
  The effect is similar to the use{of EQUIVALENCE in Fortran.  T
he results may be unpredictable unless the two{types occupy the 
same amount of storage.{}b[ 588B584]One use of Unchecked_Convers
ion might be to allow us to^and~two Integers.  Some{Ada compiler
s come with a package that enables us to do that, but many{compi
lers have no such package.  Suppose that types Integer and Boole
an occupy{the same amount of storage.  If our program says^with 
Unchecked_Conversion;~we{could write{{@%^function Int_To_Bool is
 new Unchecked_Conversion(Integer, Boolean);`{@%^function Bool_T
o_Int is new Unchecked_Conversion(Boolean, Integer);`{@%^functio
n "and"(Left, Right : in Integer) return Integer is`{@%^begin`{@
(^return Bool_To_Int(Int_To_Bool(Left) and Int_To_Bool(Right));`
{@%^end "and";`{{Using Unchecked_Conversion usually destroys pro
gram portability.{{Unchecked_Deallocation allows us to free the 
memory occupied by an object{associated with a pointer.  Normall
y, the system reclaims memory when it's{needed.  However, the ex
ecution time for that so-called^garbage collection`{tends to be 
long and unpredictable.  Suppose we have^type P is access Link;~
and{%Head : P;`.  Also suppose that we no longer need the object
 pointed to by Head`,{and we're sure that no other pointer point
s to the same object as Head.  If our{program says^with Unchecke
d_Deallocation;~we can write{}b[ 589B587]@,^procedure Free is ne
w Unchecked_Deallocation(Link, P);`{@-...{@,^Free(Head);`{{This 
will release the memory occupied by the object pointed to by^Hea
d`, and{then set^Head~to^null`.  But there's a danger.  If there
's another pointer that{pointed to the same object, it now point
s to released memory.  A reference to{that pointer will have unp
redictable results.  In general, it's best to let the{system han
dle the reclaiming of memory.  That way there's no danger of dan
gling{references.{}b[ 590B588]@DPRAGMAS{{A^pragma~is a message t
o the compiler.  The pragmas that are predefined by Ada{are all 
described in Appendix B of the LRM; we'll discuss the most impor
tant{ones here.  A particular implementation of Ada need not hon
or all the{predefined pragmas, and it may add some of its own.  
(One implementation of Ada{adds a pragma Time_Slice, used with t
asking.)  Unlike representation clauses,{unimplemented predefine
d pragmas do^not~cause error messages; the compiler{simply ignor
es them.  This enhances program portability.  Any additional{pra
gmas added by a particular implementation of Ada will be explain
ed in{Appendix F of the compiler documentation.  The most import
ant predefined{pragmas are these:{{The statements^pragma List(On
);~and^pragma List(Off);~turn on and off the{compiler listing.  
Also,^pragma Page;~will cause the compiler listing to start{a ne
w page, if the listing is turned on.  These pragmas are allowed 
almost{anywhere in the program.{{Within the declarative region w
e can write^pragma Optimize(Time);~or^pragma{Optimize(Space);~to
 ask the compiler to optimize the program for minimum{execution 
time or minimum memory usage.{}b[ 591B589]We can write^pragma In
line(`...%);~with the name of a subprogram to ask the{compiler t
o write inline code in place of every call to the subprogram.  E
ven{implementations of Ada that honor this pragma will ignore it
 if the subprogram{is recursive.{{We can call a subprogram writt
en in another language by writing^pragma{Interface(`...%,~...%);
~after the subprogram specification.  The two arguments are{the 
name of the language and the subprogram name.  Consult the compi
ler{documentation for information on bringing the object file in
to the Ada library.{Pragma Interface is used primarily in Ada 83
.  Ada 9X replaces pragma Interface{with^pragma Import~and adds^
pragma Export~to allow a program written in another{language to 
call an Ada subprogram.  Unlike pragma Interface, these two Ada 
9X{pragmas can be used to share objects as well as subprograms. 
 Ada 9X also adds{%pragma Convention~to specify that objects of 
a type should be stored using the{conventions of another languag
e.  Pragmas Import and Export take three{arguments: the name of 
the language, the Ada name of the subprogram or object,{and an o
ptional external linker name for the subprogram or object.  Prag
ma{Convention takes two arguments: the name of the language and 
the Ada name of{the type whose storage convention is being speci
fied.{}b[ 592B590]We can ask the compiler to minimize memory occ
upied by a record or array by{writing, after the type declaratio
n,^pragma Pack(`...%);~with the name of the{type.  Note that the
 specification for package Standard (in Appendix C of the{LRM) c
ontains^pragma Pack(String);~after the definition of type String
.{{Package System defines a subtype of Integer called Priority. 
 We can assign a{priority to a task by writing, in the specifica
tion,^pragma Priority(`...%);~with{an argument of subtype System
.Priority.  Higher numbers denote greater urgency.{{The pragma^S
uppress~can be used to ask the compiler to turn off certain chec
ks,{such as Constraint_Error.  It's dangerous and shouldn't be u
sed unless{absolutely necessary because of time or memory constr
aints.{}b[ 593B591]In the author's opinion, which one of these i
s^not~dangerous?{{{@61.  Unchecked_Deallocation{{@62.  pragma Pa
ck{{@63.  pragma Suppress{}Please press 1, 2, or 3, or B to go b
ack.[259415953596B592]@61.  Unchecked_Deallocation{{@5^2.  pragm
a Pack`{{@63.  pragma Suppress{{{%You're right!~ The worst^pragm
a Pack~could do is slow the program down, and{this pragma is use
d in package Standard.  Unchecked_Deallocation could allow a{poi
nter to point to memory that has been released, with unpredictab
le results.{Pragma Suppress could allow a program to use a subsc
ript that's out of range,{etc.{}q[ 597B593Q593]@61.  Unchecked_D
eallocation{{@62.  pragma Pack{{@63.  pragma Suppress{{{No, Unch
ecked_Deallocation is dangerous because it could allow a pointer
 to{point to memory that has been released, with unpredictable r
esults.{}q[ 597B593Q593]@61.  Unchecked_Deallocation{{@62.  prag
ma Pack{{@63.  pragma Suppress{{{No, pragma Suppress is dangerou
s because it could allow a program to use a{subscript that's out
 of range, etc.{}q[ 597B593Q593]@<LOOSE ENDS AND PITFALLS{{In th
is final section, we cover some miscellaneous topics that were o
mitted{earlier for simplicity.  We also mention some common erro
rs made by Ada{programmers.  If you're a beginner, you aren't ex
pected to understand every{paragraph until you've gained more ex
perience, so we won't ask questions in{this section.{{Some termi
nals and printers don't support the entire ASCII character set. 
 In{an Ada program, the vertical bar^|~may be replaced with the 
exclamation mark^!`,{as in^when 3 ! 5 =>`.  Also, a pair of shar
p signs^#~may be replaced with a pair{of colons^:`, as in^16:7C0
3:`.  The quotation marks around a string constant may{be replac
ed with percent signs if the string doesn't contain any quotatio
n{marks.  In that case, any percent signs within the string must
 be doubled.{These character replacements shouldn't be used in p
rograms if the equipment{will support the standard characters.{{
An expression is called^static~if it can be evaluated at compile
 time.  In{almost every case where a constant normally appears, 
a static expression may{also be used.  For example, an address r
epresentation clause normally takes{a constant of type System.Ad
dress.  A static expression of this type is also{acceptable, as 
in^for Clock_Interrupt use at 16*16;`.{}b[ 598B593]The unary min
us is always an operator and never part of a constant.  Thus^-5`
{is actually a static expression and not a constant.  Normally, 
this doesn't{concern the programmer, because, as we just said, s
tatic expressions can{usually appear where a constant appears.  
However, in a few special situations{we can get into trouble.  F
or example, in Ada 83 we can write{%for I in 10 .. 20 loop~and^A
 : array(10 .. 20) of Float;~but we can't omit the{words^Integer
 range~in^for I in Integer range -10 .. 10 loop~and{%A : array(I
nteger range -10 .. 10) of Float;`!  (Ada 9X lets us write these
{without^Integer range`, however.){{Also, if a package P declare
s^type Count is new Integer;~then the unary minus{operator for t
hat type is part of the package.  If our program^with`s but{does
n't^use~P, we can write^A : P.Count := 1;~but not^B : P.Count :=
 -1;`.{We either have to^use~the package,^rename~P."-", or write
{%B : P.Count := P."-"(1);`.  Because we sometines don't want to
^use~the package{except to avoid writing^P."-"(1)`, Ada 9X lets 
us write{{@;with P;^use type P.Count`;{}b[ 599B597]@;with P;^use
 type P.Count`;{{This automatically^use`s only the infix operato
rs belonging to the type{P.Count.  Other operators belonging to 
P.Count, and other identifiers in the{package P still require do
t notation with the above^use type~clause.{{The operators have p
recedence, so that 1 + 2 * 3 means 1 + (2 * 3).  The{precedence 
of all the operators is given in section 4.5 of the LRM.  A{prog
rammer should never have to look these up, because parentheses s
hould be{used for any cases that aren't obvious.  Unary minus ha
s a low precedence, so{%-A mod B~means^-(A mod B)`.{{If we write
^A, B : array(1 .. 5) of Float;~then A and B have^different`{ano
nymous types, and we can't write^A := B;`.  To fix this, write{%
type Vector5 is array(1 .. 5) of Float;~and then^A, B : Vector5;
`.{{Ada will automatically convert from a universal type to a na
med type, but not{from a named type to a universal.  For example
,{{@3^C1 : constant Integer := 1;  -- legal`{@3^C2 : constant In
teger := 2;  -- legal`{@3^C3 : constant := C1 + C2;@$-- illegal`
{}b[ 600B598]When arrays are assigned, the subscripts don't have
 to match; only the lengths{and types need match.  But in Ada 83
 (not Ada 9X), if a formal parameter{("dummy argument") of a sub
program is a constrained array, the subscripts in{the call to th
e subprogram must match.  For example, the last line here will{r
aise Constraint_Error in Ada 83:{{@/^subtype Name is String(1 ..
 30);`{@/^John : Name;`{@/^Line : String(1 .. 80);`{@/^procedure
 Display(Person : in Name);`{@0...{@/^John := Line(51 .. 80);@#-
- legal`{@/^Display(Line( 1 .. 30));  -- legal`{@/^Display(Line(
51 .. 80));  -- illegal in Ada 83`{}b[ 601B599]When a subprogram
 formal parameter is an^un`constrained array, beginners often{wr
ongly assume that the subscripts will start with one.  For examp
le,{{@5^Line : String(1 .. 80);`{@5^procedure Display(S : in Str
ing) is`{@5^begin`{@8^for I in 1 .. S'Length loop`{@<...^S(I)~..
.{{This will raise Constraint_Error if we call^Display(Line(51 .
. 80));`.  The^for`{statement should be changed to say^for I in 
S'Range loop`.{{Remember that elaboration occurs at run time.  T
he following raises{Program_Error by trying to activate a task b
efore elaborating its body:{{@:^task type T is~...^end T;`{@:^ty
pe P is access T;`{@:^T1 : P := new T;`{@:^task body T is~...^en
d T;`{{The third line should be changed to^T1 : P;~and the state
ment^T1 := new T;`{should be placed in the executable region.{}b
[ 602B600]Similarly, this procedure tries to activate a function
 before elaborating its{body.  The initialization of J should be
 moved to the executable region:{{@0^procedure Test is`{@3^funct
ion X return Integer;`{@3^J : Integer := X;  -- Raises Program_E
rror.`{@3^function X return Integer is`{@3^begin`{@6^return 5;`{
@3^end X;`{@0^begin`{@3^null;`{@0^end Test;`{{A^return~statement
 in a function is used with an object:^return Answer;`.{However,
^return~may also appear without an object in a^procedure`; we si
mply{write^return;`.  Normally, a procedure returns after execut
ing its last{statement, but an early return is possible by this 
method.  Well structured{programs don't use this feature of Ada.
{}b[ 603B601]Some implementations of Ada provide a package^Low_L
evel_IO~which includes{overloaded procedures^Send_Control~and^Re
ceive_Control~to interface various{hardware devices directly.  T
his package is completely implementation{dependent, so you'll ha
ve to consult Appendix F of your compiler documentation.{{Many i
mplementations of Ada allow you to insert^machine code~into a pr
ogram.{Some implementations do this with a pragma, such as^pragm
a Native`, which can be{inserted in the middle of a procedure, f
unction, etc.  Other implementations{provide a package called^Ma
chine_Code~which usually contains a rather complex{record defini
tion representing the format of a machine instruction.  In this{
case, we can write a procedure or function that^with`s Machine_C
ode.  In place{of the usual Ada statements in the executable reg
ion, we write record{aggregates, each one representing a machine
 code instruction.  Since the method{of inserting machine code i
nto a program varies from one implementation to the{next, you'll
 have to consult the compiler documentation.{}b[ 604B602]In the 
unusual case of a^for~loop index hiding an explicitly declared o
bject of{the same name, the explicitly declared object^can~be re
ferenced inside the{loop.  Simply use dot notation with the name
 of the compilation unit (function,{procedure, etc.)  For exampl
e, the following is legal:{{@;procedure Main is{@>Ix : Float;{@>
J  : Integer;{@;begin{@>Ix := 3.2;{@>for Ix in 1 .. 10 loop{@@^M
ain.Ix~:= 6.0;{@AJ := Ix;{@>end loop;{@;end Main;{{%Inside~the l
oop,^Ix~refers to the loop index, and the explicitly declared{ob
ject can be referenced by writing^Main.Ix`. ^Outside~the loop,^I
x~refers to{the explicitly declared object, and the loop index d
oesn't exist.{}b[ 605B603]In the rare case of an aggregate conta
ining just one element, we must use named{notation rather than p
ositional notation.  For example, the last line is{illegal in th
e following program segment, because the right hand side is a{Fl
oat rather than an array of one Float.{{@0type Vector is array(I
nteger range <>) of Float;{@/^A : Vector(1 .. 1);`{@0...{@/^A :=
 (1 => 2.3);  -- legal`{@/^A := (2.3);  -- illegal`{{It's OK to 
use positional notation in calls to subprograms with only one{pa
rameter, for example,^Put_Line("Hello");`.{}b[ 606B604]Ada 9X in
cludes seven^annexes`, described in Appendixes G through M of th
e Ada{9X LRM.  An Ada 9X compiler may implement any, all, or non
e of these.  Consult{appendixes G through M of your compiler doc
umentation for details.  The{optional Ada 9X annexes are as foll
ows:{{1. ^Systems Programming:~ Access to machine operations, in
terrupt support,{@$shared variable control, task identification,
 etc.{{2. ^Real-Time Systems:~ Dynamic task priorities, scheduli
ng, dispatching,{@$queueing, monotonic time, etc.  An implementa
tion that provides this must{@$provide Systems Programming as we
ll.{{3. ^Distributed Systems:~ Multiple partitions of an Ada pro
gram executing{@$concurrently.{{4. ^Information Systems:~ Decima
l types for handling monetary values.{@$"Picture" strings to sim
plify output of monetary amounts.{{5. ^Numerics:~ Complex number
s, improved accuracy requirements for floating-{@$-point arithme
tic, random number generation, etc.{}b[ 607B605]6. ^Safety and S
ecurity:~ Adds requirements on compilers for safety-critical{@$s
ystems.{{7. ^Interface to Other Languages:~ Features for writing
 mixed-language{@$programs.{}b[ 608B606]Well, we haven't covered
^all~there is to know about Ada, but this has been a{very thorou
gh course.  If you've come this far and completed the six Outsid
e{Assignments, you should be a very good Ada programmer.  To be 
an excellent Ada{programmer, start doing all your casual program
ming in Ada.  If you need a{simple program to balance your check
book, write it in Ada!  At this point,{switching to Ada for all 
your programming will do you much more good than{further instruc
tion from a tutorial program.{{The best way to answer any remain
ing questions about Ada is to "ask the{compiler" by writing a br
ief test program, especially if your compiler is{validated.  You
 can also look in the LRM, which, by definition, does cover^all`
{of the Ada language.  However, the LRM isn't easy reading!{{The
 best way to debug a short program is often to execute it by han
d, with{pencil and paper.  You can also add extra statements to 
the program to display{intermediate results, and remove them lat
er.{{We wish you success with Ada, and welcome your comments and
 suggestions!{{Now, you can press B to go back,{{@2or, for one l
ast time ...{}@:... type a space to go on.[ 101B607]            
