Whirlwind Tour of Ada - Part 2b - More on Types
A Rich Type Model
A Rich Type Model
- Ada has a richer type model than Java
- We will see several ways to define and use new types and
subtypes
- Look first at subtypes
Subtypes
Subtypes
- Type Natural is known as a subtype
- Subtypes are an important part of modern languages
- We will look at subtypes
- of Integers and Classes
- in Ada and Java
Types and Subtypes
- We look at subtypes in the context of a type
- A type consists of two sets:
- Set of values
- Set of operations (that operate on those values)
- Examples:
- Type Integer:
- Values: All 32 bit integers
- Operations: Integer operations such as +, -, *, /, mod, rem, 'first, 'last, IO, :=
- Type Character: values and operations
- Values: All 8 bit characters
- Operations: &, 'pos, 'val, IO, :=
What is a Subtype
- Defintion: A subtype of a type is a subset of the values of a type, with same operations (normally)
- Example: Natural is a subtype of type Integer
- Values: 0 .. largest 32-bit Integer
- Operations: All integer operations (eg :=, +, -, )
Declaring Subtypes in Ada
- Ada Declaration:
-
subtype Natural is Integer range 1 .. Integer'last
- Remember,
Integer'Last
is the largest value in type Integer
- Other examples:
-
subtype Positive is ...
-
subtype Test_Scores is ...
- Subtypes Natural and Positive are defined in package Standard
- Package Standard is automatically available
- Types Character and Boolean are also defined in package Standard
Why Do We Use Subtype Natural?
- In general, use the type that best reflects the values to be stored
- Person reading code will have better understanding of purpose of variable
- Better error checking possible
- Easier to prove properties of programs with more restricted types
- Easier to improve performance if you can prove that a value will only
have certain values
- Example: Counting something
- Use type Natural: value will be 0 or greater
- Attempt to use negative count will result in a Constraint Error
- Assuming that negative counts are not allowed
Mixing Types and Subtypes
- In general, subtypes can be used anywhere the parent type is expected
- Example:
procedure sum_abs(x, y: Integer) return Natural is
begin
return abs x + abs y;
end sum_abs;
n: Natural;
i, j: Integer;
...
i := sum_abs(i, n)
Some run time type checking occurs
Subtypes Example: Type Checking, Constraint Error
- Compiler generates code for runtime checks of subtype values:
- Constraint error raised at runtime if invalid value assigned
- Example:
with ada.integer_text_io; use ada.integer_text_io;
procedure foo is
i: Integer;
n1, n2: Natural
begin
get(i);
n1 := i; -- fails if ...
get(n2); -- fails if ...
n1 := n1 - n2; -- fails if ...
i := n2; -- fails if ...
end foo;
Subtypes: Implicit Conversion
- Notice that the compiler does implicit conversion between subtypes
- Examples: What are the types on each side of the assignment
with ada.integer_text_io; use ada.integer_text_io;
procedure foo is
i: Integer;
n1: Natural;
p1: Positive;
begin
get(p1); -- fails if ...
n1 := p1; -- fails if ...
get(n1); -- fails if ...
p1 := n1; -- fails if ...
i := p1;
n1 := i;
end foo;
Ada does implicit type conversion in these cases:
- from parent type to child type
- from child type to parent type
- from child type to child type
Which require runtime checks for valid values?
- What code is generated by the implicit conversion
Notice: Integer get works for subtypes
Numeric Subtypes and Java
- Consider byte, short, int, long
- These define a subtype hierarchy
- Java allows a widening conversion without a cast (ie implicit
conversion)
- Java requires a cast for a narrowing conversion (ie explicit
conversion needed)
- Example
i = b; -- Cast not required (but is allowed)
b = (byte) i; -- Cast required. What happens?
What do the widening and narrowing conversions do?
- Narrowing conversion will not lose information.
- Narrowing conversion can lose information. No exception is thrown
if info is lost.
Class Subtypes and Java
- Where else do we see subtypes in Java?
- Assume we have classes: P, C1 extends P, C2 extends P
P myP, C1 myC1, C2 myC2;
myC1 = new C1();
myC2 = new C2();
// Do the assignments below compile?
// If not, can they be cast to compile correctly?
// Can any of these cause runtime errors?
myP = myC1;
myC1 = myP;
myC2 = myP;
myC1 = myC2;
Which assignment is a widening conversion? Which is a widening?
What are Java's rules for compiling subtypes?
- parent = child?
- child = parent?
- child1 = child2?
What does the typecast specify?
Which require runtime checks for valid values?
Subtypes and Strong Typing
- Bottom Line: Catching all possible type errors requires the compiler to
- Do strong type checking at compile time
- Generate code to checks types at runtime
- Strong type checking at compile time: Compiler verifies that operations operate on valid variables
myFloat: float := 3; -- invalid
myVar := 2 + 3.0; -- invalid
- Compiler generates runtime checks to verify variables are assigned only valid values
get(myNat); -- needs runtime check
myPos := myNat; -- needs runtime check
Other Ways of Creating Types
Other Ways of Creating New Types
- New Numeric Types
- Enumerated Types
- Modular Types
- Floating Point Types
- Fixed Point Types
- Decimal Fixed Point Types
- Objects and Class-Wide Types are not considered here
New Numeric Types
Defining New Numeric Types
- New numeric types can be defined
- Example: types ( not subtypes) for temperature and pressure
type Temperature is new Integer Range 32 .. 212;
type Pressure is Range 0 .. 500; -- Alternate syntax -- New Integer implied
t: Temperature;
p: Pressure;
t := 100; -- valid
p := t; -- compile error
Reduce errors:
- Only valid values can be assigned to t and p
- Types cannot be mixed
Automatically get all operations on Integers
Need to define I/O operations
Sometimes mixed type expressions are needed and conversions can be
used.
Result: Integer := Integer(t) * Integer(Pressure)
We mostly ignore new numeric types in ITEC 320
Modular Types
- Values of modular types are never negative
- Modular types use modular arithmetic
- Example 1 - values range from 0 .. 11 (for hours):
type ClockHourType is mod 12;
startTime: ClockHourType := 8;
breakTime: ClockHourType := startTime + 4; -- 0
endTime: ClockHourType := startTime + 6; -- 2
notifyTime: ClockHourType := startTime - 11; -- 9
Example 2 - 32 bit unsigned value (for addresses):
type AddressType is mod 2**32;
Similar to C unsigned types and Java char type
Floating Point Types
- To know Fixed Point Types (below) you must know floating point types
- Type Float: decimal point floats (ie it can move)
x: Float;
x := 12_345_678.9 -- 12_345_678.9
x := x / 10.0; -- 12_345_67.89
x := x / 100.0; -- 12_345.678_9
Floating point can give inexact results:
cent: Float := 0.01;
dollar: Float := 0.0;
for i in 1 .. 100 loop
dollar := dollar + cent;
end loop;
put(dollar); -- 0.9999993443
Decimal Fixed Point Types
- Decimal fixed point types have a constant, fixed number of decimal places
type Money is delta 0.01 digits 15;
cent: Money := 0.01;
dollar: Money := 0.0;
annualSal := 1234567.89;
put_line(annualSal'img); -- 1234567.89
annualSal := annualSal / 10;
put_line(annualSal'img); -- 123456.78 -- Truncates toward 0
annualSal := annualSal / 10;
put_line(annualSal'img); -- 12345.67
for i in 1 .. 100 loop
dollar := dollar + cent;
end loop;
put(dollar); -- 1.00
Another example - calculate missing salary:
subtype Salary is Money digits 10;
annualSal: Salary := 100_000.00;
monthlySal: Salary := monthlySal / 12; -- 8333.33
missingSal := annualSal - (12 * monthlySal); -- 0.04
- Shows number of cents that must be added to paycheck over the year
Fixed Point and Decimal Fixed Point Types
- Decimal Fixed point types are decimal based
- Ordinary Fixed point types are binary based
- Example:
subtype Volt is delta 0.125 range 0.0 .. 255.0;
- 0.125 = 2#0.001# = (0.5)**3
Enumerated Types
Enumerated Types
- Many times we want to represent a set of values with names
- Examples: colors, day names
- Solution: Enumerated Type - allow definition of new literals
- Example:
procedure enum_demo is
type Color is (red, blue, green);
c: color := green;
begin
if c = blue then
-- do something
end if;
end enum_demo;
Enumerated Types
- Many times we want to represent a set of values with names
- Examples: colors, day names
- Solution: Enumerated Type - allow definition of new literals
- Example:
procedure enum_demo is
type Color is (red, blue, green);
c: color := green;
begin
if c = blue then
-- do something
end if;
c := 0; -- compilation error
end enum_demo;
Operations: :=, 'first, 'last, i/o, ...
More information is here