Programming in D – Solutions

Member Functions

  1. Potentially negative intermediate values make decrement() slightly more complicated than increment():
    struct TimeOfDay {
        // ...
    
        void decrement(Duration duration) {
            auto minutesToSubtract = duration.minute % 60;
            auto hoursToSubtract = duration.minute / 60;
    
            minute -= minutesToSubtract;
    
            if (minute < 0) {
                minute += 60;
                ++hoursToSubtract;
            }
    
            hour -= hoursToSubtract;
    
            if (hour < 0) {
                hour = 24 - (-hour % 24);
            }
        }
    
        // ...
    }
    
  2. To see how much easier it gets with toString() member functions, let's look at the Meeting overload of info() one more time:
    void info(Meeting meeting) {
        info(meeting.start);
        write('-');
        info(meeting.end);
    
        writef(" \"%s\" meeting with %s attendees",
               meeting.topic,
               meeting.attendanceCount);
    }
    

    Taking advantage of the already-defined TimeOfDay.toString, the implementation of Meeting.toString becomes trivial:

        string toString() {
            return format("%s-%s \"%s\" meeting with %s attendees",
                          start, end, topic, attendanceCount);
        }
    

    Here is the entire program:

    import std.stdio;
    import std.string;
    
    struct Duration {
        int minute;
    }
    
    struct TimeOfDay {
        int hour;
        int minute;
    
        string toString() {
            return format("%02s:%02s", hour, minute);
        }
    
        void increment(Duration duration) {
            minute += duration.minute;
    
            hour += minute / 60;
            minute %= 60;
            hour %= 24;
        }
    }
    
    struct Meeting {
        string    topic;
        int       attendanceCount;
        TimeOfDay start;
        TimeOfDay end;
    
        string toString() {
            return format("%s-%s \"%s\" meeting with %s attendees",
                          start, end, topic, attendanceCount);
        }
    }
    
    struct Meal {
        TimeOfDay time;
        string    address;
    
        string toString() {
            TimeOfDay end = time;
            end.increment(Duration(90));
    
            return format("%s-%s Meal, Address: %s",
                          time, end, address);
        }
    }
    
    struct DailyPlan {
        Meeting amMeeting;
        Meal    lunch;
        Meeting pmMeeting;
    
        string toString() {
            return format("%s\n%s\n%s",
                          amMeeting,
                          lunch,
                          pmMeeting);
        }
    }
    
    void main() {
        auto bikeRideMeeting = Meeting("Bike Ride", 4,
                                       TimeOfDay(10, 30),
                                       TimeOfDay(11, 45));
    
        auto lunch = Meal(TimeOfDay(12, 30), "İstanbul");
    
        auto budgetMeeting = Meeting("Budget", 8,
                                     TimeOfDay(15, 30),
                                     TimeOfDay(17, 30));
    
        auto todaysPlan = DailyPlan(bikeRideMeeting,
                                    lunch,
                                    budgetMeeting);
    
        writeln(todaysPlan);
        writeln();
    }
    

    The output of the program is the same as the earlier one that has been using info() function overloads:

    10:30-11:45 "Bike Ride" meeting with 4 attendees
    12:30-14:00 Meal, Address: İstanbul
    15:30-17:30 "Budget" meeting with 8 attendees