Exercise in RecordsYour 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 date, Tomorrow should return the following date. Your function will 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 needn't understand the test driver. If your function fails any test, you'll see the test case, the answer from your function, and the right answer. Otherwise, you'll see "Congratulations, you completed the assignment!"
The definitions of Month_Type, Day_Subtype, and Date are in the test driver; you shouldn't define them inside your function. A dummy solution is in TOMORROW.DUM; it looks like this:
-- Dummy solution to Outside Assignment 3separate (Nextdate) function Tomorrow(Today : in Date) return Date is beginreturn Today;end Tomorrow;
Again, you'll probably want to remove or change the comment line, and you shouldn't change the lines highlighted above. You may, but don't have to, include Answer : Date; in the declarative region and make return Answer; the last statement before end Tomorrow;.
Normally, years divisible by 4 are leap years. But if a year is divisible by 100, it must also be divisible by 400 to be a leap year. Thus, 2000 is a leap year, but 1900 and 2100 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.
The steps to follow for Outside Assignment 3 are very similar to those of Outside Assignment 2. They're in your printed course notes on page 14:
- Copy TOMORROW.DUM to TOMORROW.ADA to make a copy of the dummy solution. Also, compile the test driver NEXTDATE.ADA. You need do this step only once.
- Edit TOMORROW.ADA to become your real solution. You may skip this step the first time through, to see error messages from the test driver.
- Compile TOMORROW.ADA. If the compiler finds errors, go back to step 2.
- Link with the name of the main program Nextdate. Then execute. If the test driver displays error messages, go back to step 2.
- When the message "Congratulations, you completed the assignment!" is displayed, you'll have a chance to compare your solution with ours.
There are many ways to solve this problem. In our solution we declared an array of Day_Subtype with subscripts of type Month_Type. Some students use a case construct on Today.Month; some use an if block with elsifs.
This assignment should be a simple exercise in records. Our solution fits on one screen. If your solution starts to get long and difficult, you should think the problem through again. Don't try to save the computer a few microseconds; computers are supposed to save people time. Instead, minimize the complexity of the program to save yourself programming effort!
Remember that an entire record can be assigned in one statement. Also, try to calculate the number of days in the month and then test for end of month and end of year in only one place. This is better than having several blocks of code testing for end of month and end of year in three or four different places in your program. One last hint: remember that Month_Type'Succ(Today.Month) will raise a Constraint_Error if Today.Month is Dec.
Please exit AdaTutor temporarily, and try Outside Assignment 3. Work at your own pace; there's no deadline. Good luck!
Congratulations on Completing Outside Assignment 3!Our solution to Outside Assignment 3 (in TOMORROW.ANS):
separate (Nextdate) function 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 (Today.Year mod 100 /= 0 or Today.Year mod 400 = 0) then Length(Feb) := 29; end if; if Today.Day /= Length(Today.Month) then -- Not end of month. Answer := (Today.Day + 1, Today.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 -- End of year. Answer := (1, Jan, Today.Year + 1); end if; return Answer; end Tomorrow;
In our solution, the first if statement checks for leap year. No else is needed because the locally declared array Length is re-initialized every time the function is called. After this if statement, the number of days in the month is in Length(Today.Month), and it's easy to test for end of month and end of year - in only one place in the program.
We could have written Month_Type'Last instead of Dec, and Month_Type'First instead of Jan. We could even have used Day_Subtype'First. But the program seems a little easier to read when we use the names Dec and Jan and the number 1 directly.
Your solution might be entirely different from ours. If the test driver said "Congratulations, you completed the assignment!" you may consider your solution correct. Let's go on to discuss recursion.