5.8 The time library (so far)
In the course of introducing methods, classes, and generic functions, we have created elements of a library dealing with two kinds of time. Now, we construct a simple library containing those elements (we will continue to develop the time library throughout this book). We represent the time library in four files: a LID file, a library file, a library implementation file, and a test file. We could have expressed this library in three files, by combining into a single file the library implementation file and the test file, but we decided that it would be clearer to separate the underlying implementation (the definitions of classes, methods, and generic functions) from the test (where we create instances and call say on them).
The LID file: |
|---|
library: time
files: library
library-implementation
test
|
The library file defines the time library and the time module.
The library file: |
|---|
module: dylan-user define library time use dylan; use format-out; end library time; define module time use dylan; use format-out; end module time; |
The library implementation file defines the classes, methods, and generic functions.
The implementation file: |
|---|
module: time// Class definitions define class <time> (<object>) slot total-seconds :: <integer>, init-keyword: total-seconds:; end class <time>;// A specific time of day from 00:00 (midnight) to before 24:00 (tomorrow) define class <time-of-day> (<time>) end class <time-of-day>; |
// A relative time between -24:00 and +24:00
define class <time-offset> (<time>) end class <time-offset>; |
// Method for determining whether a time offset is in the past
define method past? (time :: <time-offset>) => (past? :: <boolean>) time.total-seconds < 0; end method past?; |
// Methods for encoding and decoding total seconds
define method encode-total-seconds
(hours :: <integer>, minutes :: <integer>, seconds :: <integer>)
=> (total-seconds :: <integer>)
((hours * 60) + minutes) * 60 + seconds;
end method encode-total-seconds;
define method decode-total-seconds
(time :: <time>)
=> (hours :: <integer>, minutes :: <integer>, seconds :: <integer>)
decode-total-seconds(abs(time.total-seconds));
end method decode-total-seconds;
define method decode-total-seconds
(total-seconds :: <integer>)
=> (hours :: <integer>, minutes :: <integer>, seconds :: <integer>) let(total-minutes, seconds) = truncate/(total-seconds, 60);
let(hours, minutes) = truncate/(total-minutes, 60);
values(hours, minutes, seconds);
end method decode-total-seconds;
|
// The say generic function and its methods
// Given an object, print a description of the object
define generic say (any-object :: <object>) => ();
define method say (time :: <time>) => ()
let (hours, minutes) = decode-total-seconds(time);
format-out
("%d:%s%d", hours, if (minutes < 10) "0" else "" end, minutes);
end method say;
define method say (time :: <time-offset>)
format-out("%s ", if (past?(time)) "minus" else "plus" end);
next-method();
end method say;
|
The test file creates instances and calls say on the instances. The test file can access variables defined in the implementation file, because both files are in the time module.
The test file: |
|---|
module: time define variable *my-time-offset* :: <time-offset> = make(<time-offset>, total-seconds: encode-total-seconds(15, 20, 10)); define variable *your-time-offset* :: <time-offset> = make(<time-offset>, total-seconds: - encode-total-seconds(6, 45, 30)); define variable *my-time-of-day* = make(<time-of-day>, total-seconds: encode-total-seconds(0, 2, 0)); define variable *your-time-of-day* = make(<time-of-day>, total-seconds: encode-total-seconds(8, 30, 59)); say(*my-time-offset*); say(*your-time-offset*); say(*my-time-of-day*); say(*your-time-of-day*); |
When we run the test.dylan file, Dylan creates two instances of <time-offset> and two instances of <time-of-day>. It calls say on all four instances. The output of the test is
plus 15:20 minus 6:45 0:02 8:30




