Lecture: 5 (4 canceled due to snow) Date: Jan 16, 2008 - Review of self-referential unions - Defining functions (methods) in Java Administrative: There were problems with the hand-in server. We're looking into it and it will be fixed for future homeworks. In general, talk to your TAs when you have this kind of trouble. Assignment 2 is posted. Have a look. Some students have expressed boredom with the current material. The first two weeks of this course are a total rehash of things we learned in 211. There is nothing new, only a new notation for saying the same old things. This is by design. Bear with us. If you're still bored in two weeks, come talk to me. Q: How was lab? Q: Any Q's? ==== Ancestor family trees (page 190 of HtDP): ;; A Child is a (make-child f m na da ec). ;; where f, m are Children; na, ec are strings, da is a number. (define-struct child (father mother name date eyes)) Q: Does this data definition make sense? A: If yes, write an example. Get back to me when you're done. Self-referential data must always consist of a clause that does not make reference to itself. Since we can only know our family tree up to some depth, let's use the following data definition to represent this information: ;; A family-tree-node (FTN) is one of: ;; - (make-unknown) ;; - (make-child f m na da ec) ;; where f, m are FTNs, na and ec are strings, and da is a number. Q: Draw an example family tree. Q: Draw the class diagrams for this data definition on the board. Note the different arrows: hollow triangle arrowhead - inheritance arrow : implements an interface, is-a, a variant in a union. thin "vee" arrow head - containment arrow : contains an instance of, has-a. Q: Can you write the class definitions? A: You better. Q: Which one is the weird one? What does its class definition look like? A: Unknown class Unkown implements IFTN { Unkown() {} } Notice this is just like our representation of the empty list of advertisements from last lecture MTLoAd. In Java (for now), every different kind of list has to have a different class definition, which is identical upto naming. We don't have (yet) parametric data definitions or functions with parametric contracts. [We don't even have functions yet, but we'll remedy that today]. So you'll have, for example in Java: - MTLoInt, empty list of integers - MTLoLoInt, empty list of lists of integers - MTLoAd, empty list of Ads - MTLoShape, empty list of Shapes - ... ad nauseum Compare to Scheme: - empty What does this mean? We have to write the same code for different datatypes. This is not a good engineering principle, but we'll tease out some of the pros/cons of this as the course goes on. === Q: So besides data definitions, what else did we define in Scheme? A: Functions. Learning a new programming language starts with learning: - how to define classes of data - how to define functions that consume and produce data. Returning to our radio show example. Suppose we want to also record when the show starts and ends. (Do we need to record the duration anymore? No, we can /compute/ it). [For now, let's forget about advertisements]. Example information: On Point airs from 10am to noon and Marketplace airs from 6:30 to 7pm on WBUR. (Aside: is noon 12 AM or PM? What do AM/PM mean?) Q: How do we want to represent clock time? +--------------+ | RS | +--------------+ | String title | | ??? starts | | ??? ends | +--------------+ How about ClockTime, as we saw in lab 2 and on page 25 in HtDC. +------------------+ | RS | +------------------+ | String title | +-| ClockTime starts | +-| ClockTime ends | | +------------------+ | | +------------+ +->| ClockTime | 24 hour clock time +------------+ | int hour | [0,23] | int minute | [0,59] +------------+ We'll see how to enforce these constraints later. Q: Write data definitions in Scheme: ;; A Clock-Time is a (make-clock-time Number Number). (define-struct clock-time (hour minute)) ;; A Radio Show (RS) is a (make-rs String Clock-Time Clock-Time) (define-struct rs (title starts ends)) Let's turn our information into examples: (define on-point-start (make-clock-time 10 0)) ;; 10am (define on-point-end (make-clock-time 12 0)) ;; Noon (define on-point (make-rs "On Point" on-point-start on-point-end)) (define fresh-air-start (make-clock-time 18 30)) ;; 6:30pm (define fresh-air-end (make-clock-time 19 0)) ;; 7pm (define fresh-air (make-rs "Fresh Air" fresh-air-start fresh-air-end)) Q: Develop the program show-duration that consumes a radio show and produces the duration of the show. ;; show-duration : RS -> Number ;; Calculate the duration of the given radio show, in minutes. (define (show-duration a-show) ... ??? ...) Q: What's next? A: Examples (show-duration on-point) => 120 (show-duration fresh-air) => 30 Q: What's next? A: Template Q: What's the template? (define (show-duration a-show) ... (rs-title a-show) ... ;; ? String ... (rs-starts a-show) ... ;; ? Clock-Time ... (rs-ends a-show) ...) ;; ? Clock-Time Q: Is there any obvious way to compute a number from this kind of data? A: No. Q: What should we do? A: Wish list. Q: What do you want? - minutes : ClockTime -> Number, converts given clock time to minutes. Q: Really? Let's go ahead and develop it anyway: ;; minutes : ClockTime -> Number ;; Converts given clock time to minutes. (minutes on-point-start) => 600 (minutes on-point-end) => 720 (minutes fresh-air-start) => 1110 (minutes fresh-air-end) => 1140 OK, now let's translate into Java. Here is the /method/, which sits inside the ClockTime class definition: class ClockTime { ... // Convert this clock time to minutes. int minutes() { ... } } This gives the contract & purpose statement. Notice that the result type is written on the left. Q: What is missing? [Play the Highlights game, what is different between these two pictures?] A: - the ClockTime parameter to minutes in the Scheme code went away. - there is a subtle change in the purpose statement We changed it to say THIS clock time. We have to have an instance of ClockTime in hand in order to invoke the method. ClockTime onPointStart = new ClockTime(10,0); onPointStart.minutes(); Q: So what does "this" refer to in the above example? A: The onPointStart ClockTime object (instance). Q: But where do we find "this" when we want the method to compute? A: Methods defined in Java classes must be invoked by instances of data of that class. The instance of data that invokes the method is "this" clock time. Q: So, how does the method invocation looks? A: Instead of (minutes a-time) we had in Scheme we write aTime.minutes() --- the instance that invokes the method is written first, indicating we should look for the method definition in the class to which this instance belongs, then the method name and parameters (if any) follow after a dot. Q: Do we write templates as before? A: Yes and no. The templates are very similar, but we must include the information about "this", its parts, and the methods "this" can invoke that have been defined earlier. Q: Can we see an example? A: Let's work on it together. Q: What data is available to the method 'minutes'? A: Well, there are no parameters, but there is "this" Q: Great. So, what do we know about "this"? A: It has two fields, 'hour' and 'minute'. Both are of the type 'int'. Q: Do we have selectors to get their values from "this"? A: Yes. this.hour produces the value of the 'hour' field of 'this'. this.minute produces the value of the "minute" field of 'this' and the template will be: /* ... this.hour ... -- int ... this.minute ... -- int */ Q: What is the /* and */ doing there? A: That is the beginning and ending of several lines of comments in Java. Let's finish the code, now that we know what we can use in the computation: class ClockTime { ... // Convert this clock time to minutes. int minutes() { return (60 * this.hour) + this.minute; } } Notice: - the infix (as opposed to prefix) notation. - return keyword. To make an example: class CTExample { CTExample() {} ClockTime onPointStart = new ClockTime(10,0); boolean testMin = check this.onPointStart.minutes() expect 600; } Q: What's the problem with this: (define (show-duration a-show) (- (minutes (show-ends a-show)) (minutes (show-starts a-show)))) (define wow-start (make-time 23 30)) ;; 11:30pm (define wow-end (make-time 1 0)) ;; 1:00am (define wow (make-rs "War of the Worlds" wow-start wow-end)) Instead, how about: - elapsed : ClockTime ClockTime -> Number, compute elapsed time in minutes. Develop this program. ;; elapsed : ClockTime ClockTime -> Number ;; Compute elapsed time (in minutes) from given start and end ;; clock times. (elapsed on-point-start on-point-end) => 120 (elapsed fresh-air-start fresh-air-end) => 30 Template: ;; (define (elapsed start end) ... ;; (clock-time-hour start) -- Number ;; (clock-time-minute start) -- Number ;; ;; (clock-time-hour end) -- Number ;; (clock-time-minute end) -- Number ;; ;; (minutes start) -- Number ;; (minutes end)) -- Number (define (elapsed start end) (if (<= (minutes start) (minutes end)) (- (minutes end) (minutes start)) ???)) ;; What do we want here? (elapsed wow-start wow-end) => 90 (define (elapsed start end) (if (<= (minutes start) (minutes end)) (- (minutes end) (minutes start)) (+ (- (* 24 60) (minutes start)) (minutes end)) Develop the program in Java: // ClockTime : represents 24 hour clock time. class ClockTime { int hour; int minute; ClockTime(int hour, int minute) { this.hour = hour; this.minute = minute; } // Template -- common to all methods /* Fields: ... this.hour ... -- int ... this.minute ... -- int Methods: (added when defined) ... this.minutes() ... -- int ... this.elapsed(ClockTime end) ... -- int */ // Convert this clock time into minutes. int minutes() { return (60 * this.hour) + this.minute; } // Compute elapsed time in minutes between this clock time, // and the given clock time. int elapsed(ClockTime end) { /* Template: ... this.hour ... -- int ... this.minute ... -- int ... this.minutes() ... -- int ... this.elapsed(ClockTime end) ... -- int ... end.hour ... -- int ... end.minute ... -- int ... end.minutes() ... -- int ... end.elapsed(ClockTime end) ... -- int */ if (this.minutes() <= end.minutes()) { return end.minutes() - this.minutes(); } else { return ((24 * 60) - this.minutes()) + end.minutes(); } } } class CTExample { CTExample() {} ClockTime onPointStart = new ClockTime(10,0); boolean testMin = check this.onPointStart.minutes() expect 600; ClockTime wowStart = new ClockTime(23,30); ClockTime wowEnd = new ClockTime( 1, 0); boolean testElapse = check this.wowStart.elapsed(this.wowEnd) expect 90; }