Chapter 10 SCALARS, SUBRANGES, & SETS PREREQUISITES FOR THIS MATERIAL ______________________________________________________________ In order to understand the material in this chapter, you should have a fairly good understanding of most of the material in Part I of this tutorial. A scalar, also called an enumerated type, =============== is a list of values which a variable of ENTYPES.MOD that type may assume. Examine the file =============== named ENTYPES.MOD for an example of some scalars. The first TYPE declaration defines Days as being a type which, if used to define a variable, the variable can be assigned any one of the seven values listed. Since, within the VAR declaration, Day is assigned the type of Days, then Day is a variable which can assume any one of seven different values. Moreover, Day can be assigned the value mon, or tue, etc., which makes the program easier to follow and understand. Internally, the Modula-2 system does not actually assign the value mon to the variable Day, but it uses an integer representation for each of the names. This is important to understand because you must realize that you cannot print out mon, tue, etc., but can only use them for indexing control statements. Note that there is an upper limit of 16 values for an enumerated type placed on you by most implementations of Modula-2. This is actually a very low limit and it is most unfortunate that such a small limit exists. You should check your documentation because your particular compiler may allow more. ANOTHER ENUMERATED TYPE ______________________________________________________________ The second line of the type definition defines TimeOfDay as another enumerated type. The variable Time can only be assigned one of four values since it is defined as the type TimeOfDay. It should be clear that even though it can be assigned morning, it cannot be assigned morningtime or any other variant spelling of morning, since each enumerated value is simply another identifier which must have an exact spelling to be understood by the compiler. Several real variables are defined to allow us to demonstrate the use of the enumerated variables. After writing a header for neat formatting of the output, the real variables are initialized to some values that are probably not real life values, but will serve as a platform to illustrate use of the enumerated variable. 10-1 Chapter 10 - Scalars, Subranges and Sets A BIG SCALAR VARIABLE LOOP ______________________________________________________________ The remainder of the program is one large loop being controlled by the variable Day as it goes through all of its values, one at a time. Note that the loop could have gone from tue to sat or any portion of the range desired. It does not have to go through all of the values of Day. Using Day as the case variable, the name of one of the days of the week is written out each time we go through the loop. Another loop controlled by Time is executed four times, once for each value of Time. The two CASE statements within the inner loop are used to calculate the total pay rate for each time period and each day. The data is formatted carefully to make a nice looking table of pay rates as a function of Time and Day. Take careful notice of the fact that the scalar variables never entered into the calculations, and they were not printed out. They were only used to control the flow of the logic. It was much neater than trying to remember that mon is represented by a 0, tue is represented by a 1, etc. In fact, those numbers are used for the internal representation of the scalars, but we can relax and let the Modula-2 system worry about the internal representation of our scalars. THE OUTPUT MAY NOT BE VERY NEAT ______________________________________________________________ Compile and run this program and observe the form of the output data. The only format available with some compilers is the E (exponential) notation which does not make for a very well formatted or easily read output. Don't let this worry you, when we get to Part III of this tutorial we will see how we can write our own output routines to display or print floating point numbers in any format we can think up. One other thing should be pointed out in this module. If you observe the case statements you will notice that the one that starts in line 33 does not have an else clause. It is really not needed because every possible value of the variable Day is covered in the various branches. In the case statement starting in line 51, there is an else clause, because only two of the possible 7 values are acted on in the case body itself. Without the else, the program would not know what to do with a value of mon through fri, so the else is required here, but not in the earlier one. 10-2 Chapter 10 - Scalars, Subranges, and Sets A COMMENT ON PROGRAM STYLE ______________________________________________________________ The enumerations in this program used a named type, but an anonymous type can also be used. Good programming practice would be to use a named type however. The case statement in lines 51 through 55 could easily be replaced by an if statement. The case statement was selected here simply because the other constructs use the case statement and it was felt that using the same construct would lead to a clearer program. LETS LOOK AT SOME SUBRANGES ______________________________________________________________ Examine the program SUBRANGE.MOD for an ================ example of subranges. It may be SUBRANGE.MOD expedient, for a particular programming ================ problem, to define some variables that only cover a part of the full range as defined in a scalar type. Notice that Days is declared a scalar type as in the last program, and Work is declared a type with an even more restricted range, a subrange of Days. The variable named Rest is declared as a different subrange of Days. In the var declaration, Day is once again defined as the days of the week and can be assigned any of the days by the program. The variable Workday, however, is assigned the type Work, and can only be assigned the days mon through fri because of the more limited range of the type. If an attempt is made to assign Workday the value sat, a runtime error will be generated because sat is not a legal value to be assigned to Workday. A carefully written program will never attempt to do so, and it would therefore be an indication that something is wrong with either the program or the data. This is one of the advantages of Modula-2 over older less structured languages. Further examination will reveal that Index is declared as being capable of storing only the range of values from 1 to 12, another subrange. During execution of the program, if an attempt is made to assign Index any value outside of that range, a runtime error will be generated. Suppose the variable named Index was intended to refer to your employees, and you have only 12. If an attempt was made to refer to employee number 27, or employee number -8, there is clearly an error somewhere in the data and you would want to stop running the payroll to fix the problem. Modula-2 would have saved you a lot of grief. The way Index is defined, it will be of type cardinal because the entire range is composed of positive numbers. It is therefore not possible to use the variable Index in calculations involving integer type numbers. If the range 10-3 Chapter 10 - Scalars, Subranges, and Sets were defined with at least one end negative, it would be of type integer. Index2 will be of type integer because we force the compiler to use the integer type through use of the type written prior to the range. Modula-2 gives you complete control over the types used. SOME STATEMENTS WITH ERRORS IN THEM ______________________________________________________________ In order to have a program that would compile without errors, and yet include some examples of errors, the first part of the program is not really a part of the program since it is within a comment area. This is a trick to remember when you are debugging a program, a troublesome part can be commented out until you are ready to include it with the rest. The errors should be self explanatory. Going beyond the area commented out, there are seven assignment statements in lines 31 through 37 given as examples of subrange variable use. Notice that the variable Day can always be assigned the value of either Workday or Weekend, but the reverse is not true because Day can store values that would be illegal for the other variables. THREE VERY USEFUL FUNCTIONS ______________________________________________________________ Lines 39 through 45 of the example program demonstrate the use of three very important functions when using scalars. The first is the INC function which returns the value of the scalar following the value of the scalar used as the actual parameter. If the parameter is the last value in the list, a runtime error is generated. The next function is the DEC that returns the value of the scalar prior to the one used in the actual parameter. All scalars have an internal representation starting at 0 and increasing by one until the end is reached. The third function is the ORD which simply returns the numerical value of the scalar variable. In our example program, ORD(Day) is 5 if Day has been assigned sat, but ORD(Weekend) is 0 if Weekend has been assigned sat. As you gain experience in programming with scalars and subranges, you will realize the value of these three functions. A few more thoughts about subranges are in order before we go on to another topic. A subrange is always defined by two predefined constants, and is always defined in an ascending order. A variable defined as a subrange type is actually a variable defined with a restricted range, and should be used as often as possible in order to prevent garbage data. There are actually very few variables ever used in any computer 10-4 Chapter 10 - Scalars, Subranges, and Sets program that cannot be restricted by some amount. The limits may give a hint at what the program is doing and can therefore help in understanding the program operation. Subrange types can only be constructed using the simple data types, not including the real type, and any operation that can be performed on a particular type can be performed on a subrange of that type. SETS ______________________________________________________________ Now for a new topic, sets. Examining the ================ example program SETS.MOD will reveal the SETS.MOD use of some sets. A scalar type is ================ defined first, in this case the scalar type named Goodies. A set type is then defined with the reserved words SET OF followed by a predefined scalar type. Most microcomputers have an upper limit of 16 elements that can be used in a set. Your compiler documentation will tell you if yours allows a larger range. Several variables are defined as sets of Treat, after which they can individually be assigned portions of the entire set. Consider the variable IceCreamCone which has been defined as a set of type Treat. This variable is composed of as many elements of Goodies as we care to assign to it. In the program, we define it as being composed of IceCream, and Cone. The set IceCreamCone is therefore composed of two elements, and it has no numerical or alphabetic value as most other variables have. Continuing in the program, you will see 4 more delicious deserts defined as sets of their components. Notice that the banana split is first defined as a range of terms, then another term is added to the group. All five of the defined sweets are combined in the set named Mixed, then Mixed is subtracted from the entire set of values to form the set of ingredients that are not used in any of the deserts. Each ingredient is then checked to see if it is IN the set of unused ingredients, and printed out if it is. Running the program will reveal a list of the unused elements. In this example, better programming practice would have dictated defining a new variable, possibly called Remaining for the ingredients that were unused. It was desirable to illustrate that Mixed could be assigned a value based on subtracting itself from the entire set, so the poor variable name was used. This example resulted in some nonsense results but hopefully it led your thinking toward the fact that sets can be used for inventory control, possibly a parts allocation scheme, or some other useful system. 10-5 Chapter 10 - Scalars, Subranges, and Sets THE BITSET TYPE ______________________________________________________________ The only predefined set type is the BITSET. This is a set of bits contained in one word of the host computer, and is typically composed of 16 bits or elements. The type BITSET acts as if it were defined as; TYPE BITSET = SET OF [0..15]; Its use will be left to the students study. There is an example of use in chapter 16 of this tutorial. It will be found in the program named BITOPS.MOD and it would be a profitable study to examine this program. SET OPERATIONS ______________________________________________________________ A complete list of all operations available with sets is as follows; + Union - Difference * Intersection / Symmetric difference = Test for equality # Test for inequality (Modern method) <> Test for inequality (Becoming obsolete) <= Inclusion >= Inclusion A complete discussion of set theory is beyond the scope of this tutorial. The interested student will be referred to academia and popular press. 10-6