home *** CD-ROM | disk | FTP | other *** search
- <COMMENT This is a lesson file for the Lovelace Ada tutorial>
- <COMMENT A program called genlesson is used to transform this file into a set>
- <COMMENT of useful HTML files for use by Mosaic & other WWW browsers.>
-
- <TUTOR NAME="Lovelace">
- <LESSON NUMBER=6>
- <AUTHOR NAME="David A. Wheeler" EMAIL="wheeler@ida.org">
- <AUTHOR ADDRESS="<A HREF="dwheeler.htm">David A. Wheeler (wheeler@ida.org)</A>">
-
- <COMMENT $Id: lesson6.les,v 1.8 1995/09/22 21:38:21 wheeler Exp wheeler $ >
-
- <COMMENT A lesson is divided into 1 or more "sections".>
- <COMMENT Each section has a title; SECTION starts a new section.>
-
- <SECTION NAME="Type Float">
- For the next few sections we'll learn a little more about
- Ada types. We've already seen Ada's built-in type Integer.
- <P>
- Like Integer, Ada also has a predefined type called <EM>Float</EM>.
- Float can store fractional values and `large' values.
- <EM>Float</EM> is used when you don't care about the
- minimum or maximum range of numbers, nor about the minimum
- accuracy of the value - the Ada compiler
- will choose whatever is most `natural' for the machine.
- Type `Float' is not appropriate if you
- <EM>do</EM> care about the range or accuracy;
- Ada has ways to specify these.
- <P>
- Float has all the arithmetic
- (+, -, *, /, **, etc.) and comparison (=, /=, >, >=, <, <=)
- operations you'd expect.
- The ``**'' operator means ``exponentiate'', a common
- operation very useful for programs doing significant computation.
- <P>
- Ada insists that types be correct in operations, and there
- aren't any predefined operations for mixing Integer and Float using
- +, -, *, or /. Thus, if you're using an Integer and Float together,
- put a function called `Float()' around the Integer variables to
- cause them to be converted into floating-point values.
- This makes it clear when such conversions are taking place, which is
- sometimes important in understanding what a program is doing.
- Also, whenever you set a Float to a constant, the constant must
- be written with a period in it, or the compiler will complain.
- <P>
- Here are some examples:
- <PRE>
- with Float_Text_IO;
- use Float_Text_IO;
- procedure Think is
- A, B : Float := 0.0; -- A and B initially zero; note the period.
- I, J : Integer := 1;
- begin
- A := B + 7.;
- I := J * 3;
- B := Float(I) + A;
- Put(B);
- end Think;
- </PRE>
- <P>
- It's important that you understand the general limitations of floating
- point numbers on digital computers.
- Floating point numbers are usually stored as a
- binary approximation using a limited number of bits.
- The upshot is that results are usually only
- approximately the value you'd expect.
- Even numbers that are represented exactly in decimal may only
- be approximate when converted to an internal floating point number.
- Thus, be wary of using "=" to compare
- two floating point numbers.
- This isn't specific to Ada - Fortran, C, Pascal, and so on
- all do the same thing.
- For more information on this subject, see
- <A HREF="biblio.htm#goldberg1991">David Goldberg's 1991
- survey on floating-point arithmetic</A>.
-
- <QUESTION Type=Multiple-Choice>
- In procedure Think defined above, what will be printed out as
- the final value of B?
- <CHOICES>
- <CHOICE ANS=1>10.0
- <CHOICE ANS=2>0.0
- <CHOICE ANS=3>7.0
- </CHOICES>
- <ANSWER ANS=1>
- <RESPONSES>
- <WHEN ANS=1>
- Right!
- <WHEN ANS=2>
- Sorry.
- <WHEN ANS=3>
- Sorry.
- </RESPONSES>
- <SECTION NAME="Boolean">
- Ada also predefines a simple type called <EM>Boolean</EM>,
- which can only have two values, <EM>True</EM> and <EM>False</EM>.
- All of the comparison operations (=, >=, /=, etc.) have result
- values of type Boolean.
- All conditions (such as what goes after an <EM>if</EM> and <EM>while</EM>)
- must be of type Boolean.
- <P>
- There are a few special infix operations that take two Booleans and
- result in a Boolean: and, or, and xor (exclusive-or),
- with their usual meanings.
- The value of `True and False' is False, while the value of `True or False'
- is True.
- `Exclusive or' is true if either of two conditions, but not both, is true.
- <P>
- There is also the prefix operation ``not''.
- If a boolean variable A has the value True, `not A' has the value False.
- <P>
- Although you can probably guess what the values of any combination
- of values is, here they are officially:
- <PRE>
- --- When ---+------------------- Then -----------------
- A B | (A and B) (A or B) (A xor B) (not A)
- True True | True True False False
- True False | False True True False
- False True | False True True True
- False False | False False False True
- </PRE>
- <P>
- Normally Ada will evaluate these
- expressions in whatever order is most efficient for the machine.
- If it's important to evaluate them in a certain order
- and to stop evaluating them when the answer is known, there are
- versions of `and' and `or' that are called `short-circuit operations'.
- These operations
- will execute strictly left-to-right and will not execute anything
- if they don't have to.
- C's && and || operations work this way.
- The short-circuit version of `and' is `and then'; the short-circuit
- version of `or' is `or else'. For example, if
- you want to do something if K isn't zero and
- 1.0/K is more than B, but you realize that the latter test <EM>must</EM>
- be done after the former:
- <P>
- <PRE>
- if K /= 0 and then 1.0/Float(K) > B then ...
- </PRE>
-
- <QUESTION Type=Multiple-Choice>
- Which of the following is True?
- <CHOICES>
- <CHOICE ANS=1>(True and False)
- <CHOICE ANS=2>not (True or False)
- <CHOICE ANS=3>True and then True
- </CHOICES>
- <ANSWER ANS=3>
-
- <SECTION NAME="Creating Types and Subtypes">
- In Ada, a <EM>type</EM> is characterized by a set of values
- and a set of <EM>primitive operations</EM>.
- For example, the type Integer can be characterized by a set of
- values (..., -2, -1, 0, 1, 2, ...) and a set of primitive
- operations (+, -, *, /, etc.).
- We'll learn more about the phrase ``primitive operation'' later.
- <P>
- An <EM>object</EM> of a given type is a run-time entity that
- contains (has) a value of the type.
- For example, a variable named `Number_Of_Widgets' is an object;
- Number_Of_Widgets could be of the type <EM>Integer</EM>.
- <P>
- Ada lets you create your own types, and has a very rich set
- of capabilities for creating types with exactly the operations
- you want.
- <P>
- To create a new type, use a <EM>type declaration</EM>.
- A type declaration begins with the keyword <EM>type</EM>, followed
- by the name of the new type, the keyword <EM>is</EM>, and then
- a definition of the new type.
- Here's an example of a new type named <EM>Column</EM> which can
- only have integer values in the range 1 through 72, and another
- type called <EM>Row</EM> that has values 1 through 24:
- <P>
- <PRE>
- type Column is range 1 .. 72;
- type Row is range 1 .. 24;
- </PRE>
- <P>
- One <EM>very</EM> important difference between Ada and some other
- languages is that Ada considers types different even if
- they happen to be implemented the same way at a particular time.
- For example, an object of type Column can't be added with an object
- of type Row or Integer without some additional expressions, even though they
- may be implemented the same way in the (current) underlying system.
- Why? Because they have different types.
- Now, you could <EM>create</EM> such operations to allow them to be mixed,
- but these operations don't come automatically.
- <P>
- This prohibition of mixing types is often useful for catching errors,
- but sometimes it's not what you want.
- Beginning Ada programmers sometimes create too many different numeric types,
- turning simple programs into complicated ones.
- If two different types are closely related and it should be possible
- to mix the different types together,
- perhaps you have two related types instead of two independent types.
- What you probably need in that case is a <EM>subtype</EM> declaration.
- <P>
- A <EM>subtype</EM> is simply another name for an existing type
- that may have some additional constraints on it.
- For example, let's say you have a program that manipulates counts
- of many different kinds of things.
- You could have a base type called `Count', and subtypes to represent
- counts of different kinds of things.
- If there must be less than 100,000 things, and widgets must have less
- than 100 (while there's no specific limit for eggs), you could define
- these subtypes as follows:
- <PRE>
- type Count is range 0 .. 99_999;
- subtype Widget_Count is Count range 0 .. 99;
- subtype Egg_Count is Count;
- </PRE>
- <P>
- Don't get the idea that new types are always a bad thing, however;
- there are a number of places where creating a new type for numeric
- values is very appropriate.
- Ada provides you with a number of tools; you need to decide which
- tool is appropriate for your task.
-
- <QUESTION Type=Multiple-Choice>
- If you want to permit free mixing of two different kinds of numbers,
- should they be defined as subtypes or different types?
- <CHOICES>
- <CHOICE ANS=1>subtypes
- <CHOICE ANS=2>types
- </CHOICES>
- <ANSWER ANS=1>
-
- <SECTION NAME="Enumeration">
- Often a variable can have only one of a small set of values.
- An <EM>enumeration</EM> type can be created for such variables,
- making it easier to understand and permitting error detection.
- For example, let's say that a variable
- `Today' must be one of seven values, Monday through Sunday.
- Let's call the list of legal values type `Day', and set
- `Today' to Tuesday as an example:
- <P>
- <PRE>
- type Day is (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday);
- subtype Weekday is Day range Monday .. Friday;
- subtype Weekend is Day range Saturday .. Sunday;
- -- ... some time later
- Today : Day;
- -- ... Here's an example of setting Today to a value.
- Today := Tuesday;
- </PRE>
- <P>
- Here's a simplified <A HREF="bnf.htm">BNF</A> for
- declaring enumeration types:
- <P>
- <PRE>
- enumeration_type_declaration ::=
- "(" enumeration_literal_specification
- { "," enumeration_literal_specification } ")"
- </PRE>
- <COMMENT No question >
-
- <SECTION NAME="Arrays">
- An array type in Ada can contain many components with the same subtype.
- An Ada array is quite similar to arrays in many other languages,
- but here are some important things to know about them:
- <P>
- <OL>
- <LI>
- Ada array indices are not required to start at zero or one.
- Array indices can begin (and end) with any discrete value - whatever
- makes the most sense for the data.
- This means that you can start arrays at -5 (if that makes sense),
- and you can use enumerated values as indices as well.
- Ada programs usually use a starting index of 1 if there's
- no particularly natural starting point; this reduces the
- probability of so-called ``one-off'' errors
- (people normally count from one, not zero, and
- can sometimes get confused when starting from zero).
- <LI>
- Like many other things in Ada, array accesses (both read and write)
- are normally checked at run-time.
- Thus, if the array index is out-of-bounds,
- instead of quietly doing the wrong thing (as C and C++ do),
- an <EM>exception</EM> will be raised.
- This catches a surprisingly large number of errors.
- <LI>
- Multi-dimensional arrays are handled in an intuitive way.
- <LI>
- A directive can be used to <EM>pack</EM> arrays, which requests
- the compiler to store the array in a memory-efficient way.
- This is particularly handy for arrays of Boolean and Character values.
- <LI>
- Using a value from an array intentionally looks like a function call.
- That way, if you change an array into a function, code that uses
- the values often needs relatively few changes.
- <LI>
- You can define array types without completely fixing their
- minimum and maximum size.
- These are called `unconstrained' arrays.
- While they are very useful, we will discuss them further later.
- </OL>
- <COMMENT ??? Haven't discussed Character type >
- <P>
- Here are a few examples:
- <P>
- <PRE>
- -- Sample array type definitions:
- type Table is array(1 .. 100) of Integer; -- 100 Integers.
- type Schedule is array(Day) of Boolean; -- Seven Booleans.
- type Grid is array(-100 .. 100, -100 .. 100) of Float; -- 40401 Floats.
- -- Sample variable declarations:
- Products_On_Hand : Table; -- This variable has 100 Integers.
- Work_Schedule : Schedule;
- Temperature : Grid;
- -- And sample uses:
- Products_On_Hand(1) := 20; -- We have 20 of Product number 1
- Work_Schedule(Sunday) := False; -- We don't work on Sunday.
- Temperature(0,0) := 0.0; -- Set temperature to 0.0 at grid point (0,0).
- Put(Products_On_Hand(1)); -- Print out the number 20.
- </PRE>
-
- <COMMENT No question. We haven't shown the BNF. >
-
- <SECTION NAME="Records">
- Types can be a complex collection of other types;
- the primary method for collecting these is through the <EM>record</EM>
- (which is basically identical to the Pascal record and C struct).
- For example, here's an example of a record useful for recording dates:
- <P>
- <PRE>
- type Date is
- record
- Day : Integer range 1 .. 31;
- Month : Integer range 1 .. 12;
- Year : Integer range 1 .. 4000 := 1995;
- end record;
- </PRE>
- <COMMENT ??? Haven't discussed this kind of range stuff >
- <P>
- The record component `Year' has an example of an `initialization clause' -
- any object created with this type automatically has initial values
- given in initialization clauses.
- <P>
- Creating variables of a record type is done the same way as any other
- type.
- A record component is referenced by using the variable name, a period,
- and the name of the record component.
- For example, let's create a variable called Ada_Birthday, and set
- its values to December 10, 1815:
- <P>
- <PRE>
- procedure Demo_Date is
- Ada_Birthday : Date;
- begin
- Ada_Birthday.Month := 12;
- Ada_Birthday.Day := 10;
- Ada_Birthday.Year := 1815;
- end Demo_Date;
- </PRE>
-
- <QUESTION Type=Multiple-Choice>
- If you had the following record type:
- <P>
- <PRE>
- type Complex is
- record
- Real_Part, Imaginary_Part : Float := 0.0;
- end record;
- </PRE>
- <P>
- and you declared the following type:
- <P>
- <PRE>
- X : Complex;
- </PRE>
- <P>
- How would you set X's Real_Part to 1?
-
- <CHOICES>
- <CHOICE ANS=1>Complex.X.Real_Part := 1.0;
- <CHOICE ANS=2>X.Real_Part := 1.0;
- <CHOICE ANS=3>Real_Part.X := 1.0;
- </CHOICES>
- <ANSWER ANS=2>
-
- <SECTION NAME="Private and Limited Types">
- When creating a new type you often want to restrict
- the operations that users can perform on them.
- Two methods are particularly important: declaring
- types as <EM>private</EM>, and declaring them as <EM>limited</EM>.
- <P>
- When declaring a type in a package declaration, you
- can declare the type as <EM>private</EM>, and then complete
- the definition in a section of the package declaration in a section
- called the <EM>private</EM> part.
- If a type is declared as <EM>private</EM>, other packages can only
- use the operations that you provide and the default
- assignment (:=) and equality (=) operations.
- <P>
- Here's an example.
- Let's say that you want to create a type called `Key', which
- uniquely identifies some resource; you only want people to be
- able to Request a key and determine if one key was requested
- before another (let's call that operation "<").
- Here's one way to implement this
- (this example is inspired by the
- <A HREF="http://lglwww.epfl.ch/Ada/LRM/9X/rm9x/rm9x-07-03-01.html">Ada
- LRM section 7.3.1</A>):
- <P>
- <PRE>
- package Key_Manager is
- type Key is private;
- Null_Key : constant Key; -- a deferred constant.
- procedure Get_Key(K : out Key); -- Get a new Key value.
- function "<"(X, Y : Key) return Boolean; -- True if X requested before Y
- private
- Max_Key : constant := 2 ** 16 - 1;
- type Key is range 0 .. Max_Key;
- Null_Key : constant Key := 0;
- end Key_Manager;
- </PRE>
-
- Note that the type declaration in the package declaration is
- declared as `private'.
- This is later followed by the word `private' introducing the
- `private part' of the package specification.
- Here the type can be defined, as well as any constants necessary
- to complete its definition.
- Although Key is actually a numeric type, other
- packages cannot use addition, multiplication, and other numeric
- operations because Key is declared as `private' - the only operations
- are those defined in the package (and := and =).
- <P>
- What if we don't want the default assignment (:=) and equals-to (=)
- operations?
- The answer: we declare the type as <EM>limited</EM>.
- A limited type doesn't have the default assignment and equals-to
- operations defined.
- Usually the term <EM>limited</EM> is combined with private,
- and such a type is called a <EM>limited private</EM> type.
- Here's how Key would be defined using the limited keyword:
- <P>
- <PRE>
- type Key is limited private;
- </PRE>
-
- <QUESTION Type=Multiple-Choice>
- How would you define a type if you wanted <EM>only</EM>
- operations called `up' and `down' associated with it?
- <CHOICES>
- <CHOICE ANS=1>private
- <CHOICE ANS=2>limited private
- <CHOICE ANS=3>non-private
- </CHOICES>
- <ANSWER ANS=2>
- <RESPONSES>
- <WHEN ANS=1>
- No, sorry.
- That would also have assignment and equals-to operations.
- <WHEN ANS=2>
- Right. Here's what that might look like:
- <P>
- <PRE>
- package Up_And_Down is
- type Up_And_Down_Type is limited private;
- procedure Up(U : Up_And_Down_Type);
- procedure Down(U : Up_And_Down_Type);
- end Up_And_Down;
- </PRE>
- <WHEN ANS=3>
- </RESPONSES>
-