Day 9
This is the Day 9 page for computer programming course 101, an introduction to computer programming. Day 9 teaches the concept of user defined types.Below are the topics and course materials we are learning today.
Strict Typing
Free Pascal is considering as a strictly typed languages. In computer programming, programming languages are often colloquially classified as to whether the language's type system makes it strictly typed or loosely typed. Generally, a strictly typed language has stricter typing rules at compile time, which implies that errors and exceptions are more likely to happen during compilation. Most of these rules affect variable assignment, return values and function calling. On the other hand, a weakly typed language has looser typing rules and may produce unpredictable results or may perform implicit type conversion at runtime.When you declare a variable or in a Pascal program you must specify its type. When you declare a constant or in a often compiler will infer the type.
The types of routine parameters and return values are specified in the routine signature. The following signature shows a method that requires an Integer as an input argument and returns a string:
function IntToStr(Value: Integer): string;After a variable is declared, it cannot be re-declared with a new type, and it cannot be assigned a value that is not compatible with its declared type. For example, you cannot declare an Integer and then assign it a Boolean value of True. However, values can be converted to other types, for example when they are assigned to new variables or passed as method arguments. A type conversion that does not cause data loss is performed automatically by the compiler. A conversion that might cause data loss typically produces a hint by the compiler.
Below are examples of valid type conversions:
var B: Byte; C: Char; D: Double; I: Integer; S: string; begin B := 12; // Okay the value 12 is whole number I := B; // Okay Byte and Integer are whole numbers C := 'A'; // Okay you provided one Char S := C; // Okay string can hold one or more Chars D := I; // Okay a floating point number can hold a whole number end;Below are examples of invalid type conversions:
var B: Byte; C: Char; D: Double; I: Integer; S: string; begin B := 12.5; // Error the value 12.5 is not a whole number I := D; // Error a double is not a whole number C := 'ABC'; // Error you provided multiple Chars C := S; // Error a string has multiple Chars D := '3.1'; // Error '3.1' is not a number end;Below are examples of valid type conversions which may result in data loss:
var B: Byte; D: Double; I: Integer; F: Single; begin I := 500; // Okay 500 is a valid whole number B := I; // Hint Byte is going to lose some information D := Pi; // Okay Pi is a floating point number F := D; // Hint Single is going to lose some information end;
Type Aliases
In Free Pascal You can declare your own type using the type keyword. The most fundamental type is known as a type alias. The standard convention in Pascal is to preface all declared types (that is types which are not build in) with the letter T. Consider these type aliases:type TDateTime = Double; TColor = Integer; TMusicalNote = Integer;In each of the above lines we are declare aliases to existing types. These aliases help in understanding the use of a type and its associated data.
Consider the following code:
function FindFiles(Modified: Double): string; procedure FloodFill(Foreground: Integer); procedure PlaySound(Value: Integer); function FindFiles(Modified: TDateTime): string; procedure FloodFill(Foreground: TColor); procedure PlaySound(Value: TMusicalNote);With a type alias it makes reading code much easier to understand what is required to make each routine operate correctly.
S := FindFiles(Now - 1); // Find files modified today FloodFill($00FF00); // Fill with green PlaySound(MiddleC); // Play the musical note middle C
Your Own Types
In addition to declaring type aliases you can also declare entirely new types. A few of the new types you can declare include enumerations, sets, subranges, arrays, and record. Below we explore each of these types in more detail.Enumerated Types
An enumerated type defines an ordered set of values by simply listing identifiers. The values have no inherent meaning. To declare an enumerated type, use the syntax:type TYourEnum = (Val1, ..., Valn);Where TYourEnum and each Vale are valid identifiers. For example, the declaration:
type TSuit = (Club, Diamond, Heart, Spade);Declares an enumerated type called TSuit, whose possible values are Club, Diamond, Heart, and Spade. As a special note the function Ord(Club) returns 0, Ord(Diamond) returns 1, and so on.
When you declare an enumerated type, you are declaring each Val to be a constant of type TYourEnum. If the Val identifiers are used for another purpose within the same scope, naming conflicts occur. For example, suppose you declare the type:
type TSound = (Click, Clack, Clock);Unfortunately, Click is also the name of a method defined for TControl and all of the objects in that descend from it. So if you are writing an application and you create an event handler like:
procedure TForm1.EditBoxEnter(Sender: TObject); var Thing: TSound; begin ... Thing := Click; end;You will get a compilation error; the compiler interprets Click within the scope of the procedure as a reference to a Click method of a TForm. You can work around this by qualifying the identifier; thus, if TSound is declared in MyUnit, you would use:
Thing := MyUnit.Click;A better solution, however, is to choose constant names that are not likely to conflict with other identifiers. Examples:
type TSound = (snClick, snClack, snClock); TAnswer = (ansYes, ansNo, ansMaybe) TSuit = (stClub, stDiamond, stHeart, stSpade);
Subrange Types
A subrange type represents a subset of the values in another ordinal type (called the base type). Any construction of the form Low..High, where Low and High are constant expressions of the same ordinal type and Low is less than High, identifies a subrange type that includes all values between Low and High. For example, if you declare the enumerated type:type TDrawState = (dsDisabled, dsHot, dsPushed, dsFocused, dsSelected, dsChecked);You can then define a subrange type like:
type TAciveState = csHot..csSelected;Here TAciveState includes the values csHot, csPushed, csFocused, and csSelected.
You can use numeric constants and characters (string constants of length 1) to define subrange types:
type TSomeNumbers = -128..127; TCaps = 'A'..'Z';When you use numeric or character constants to define a subrange, the base type is the smallest integer or character type that contains the specified range.
Values do not wrap around the beginning or end of a subrange, even if the base is an integer or character type; incrementing or decrementing past the boundary of a subrange simply converts the value to the base type. Hence, the following code produces an error.
type TPercentile = 0..99; var P: Percentile; begin P := 100; WriteLn(P); end;
Set Types
A set is a collection of values of the same ordinal type. The values have no inherent order, nor is it meaningful for a value to be included twice in a set.The range of a set type is the power set of a specific ordinal type, called the base type; that is, the possible values of the set type are all the subsets of the base type, including the empty set. The base type can have no more than 256 possible values, and their ordinalities must fall between 0 and 255. Any construction of the form:
type TYourSet = set of BaseType;Where BaseType is an appropriate ordinal type, identifies a set type.
Because of the size limitations for base types, set types are usually defined with subranges. For example, the declarations:
type TSomeInts = 1..250; TIntSet = set of TSomeInts; TDrawStates = set of TDrawState;Creates a set type called TIntSet whose values are collections of integers in the range from 1 to 250. You could accomplish the same thing with:
type TIntSet = set of 1..250;Given this declaration, you can create a set like this:
var Set1, Set2: TIntSet; begin Set1 := [1, 3, 5, 7, 9]; Set2 := [2, 4, 6, 8, 10];You can also use the set of ... construction directly in variable declarations:
var MySet: set of 'a'..'z'; begin MySet := ['a','b','c'];Other examples of set types include:
type TBytes = set of Byte TSuits = set of TSuit; TChars = set of Char;The in operator tests set membership:
if S[I] in ['A'..'Z'] then if dsSelect in DrawStates thenEvery set type can hold the empty set, denoted by [].