CSC151 2009F, Class 49: Objects in Scheme Admin: * Welcome back! * No reading for tomorrow. * Exam 3 is now ready. * It is due next Tuesday. * Corrections for credit not accepted until tomorrow. * Sorry for the switch in order of topics. * Upon reflection, it seemed like a better idea to talk about the implementation of images after we looked at the images themselves. * I'm not sure whether or not we'll have time for lab today. Overview: * Motivating problems: Circles, turtles, and counters. * Building and using compound values. * Objects: A new approach to compound values. * Creating objects in Scheme. Three motivating problems: * How might we represent circles to make it easy to build a picture composed only of circles? * How might we implement turtles? * Build a counter For each thing, we want to store a bunch of information and we want to be able to do some things with that information * How do we store that information? * Vector * List * Which do we choose and why? * Vectors are cool because they are easy to change * Lists are cool because you can't change them Problem: If you use vectors, sometimes you want some parts unchangable or you may want to limit the kinds of changes * For turtles: You should not be able to change the image associated with a turtle * For circles: The color needs to be valid, the radius needs to be positive, etc. * For counters: You can increment them, but that's all you should be able to do If we use vectors (or lists or almost anything), our clients can determine the implementation and intentionally or accidentallly mess it up. Mid-1960's: Clever idea: Build a way to structure information and operations on that information so that clients have limited access to the information * Objects: Encapsulate data and operations * Lots of languages have built-in objects * Here are my data * Here are the operations * Here's what clients get access to * Basic Scheme lacks objects * But we can implement them [Question: What is object-oriented programming? Typically: Three things: (1) Encapsulation (these kinds of objects). (2) Inheritance: Once you've defined one kind of object, you can easily build similar kinds of objects. (3) Polymorphism: One procedure can work with multiple kinds of objects.] How do we hide information in Scheme? * Local bindings! (define degrees->radians (let ((conversion-factor (/ pi 180))) (lambda (degrees) (* conversion-factor degrees)))) This gives us a way to protect our information, including the information we want to change. But how do we make all the operations work with this protected set of information? Change our world view slightly. * Rather than calling a function, we tell an object to do something * In Scheme, we're going to make objects functions, and tell them to do something by passing them a symbol (define professor (lambda (message) (cond ((eq? message 'wake-up!) "What? No, I wasn't sleeping. Really.") ((eq? message 'joke!) "Timing") (else (error "This professor is unable to do what you requested."))))) We combine the idea of responding to messages with the idea of local bindings to build objects. (define counter (let ((count (vector 0))) (lambda (message) (cond ((eq? message ':increment!) (vector-set! count 0 (+ 1 (vector-ref count 0)))) ((eq? message ':get-value) (vector-ref count 0)) (else (error ": unknown message" message)))))) What if we want more than one counter? We write a procedure that returns one of these things. (define make-counter (lambda () (let ((count (vector 0))) (lambda (message) (cond ((eq? message ':increment!) (vector-set! count 0 (+ 1 (vector-ref count 0)))) ((eq? message ':get-value) (vector-ref count 0)) (else (error ": unknown message" message))))))) > (define c1 (make-counter)) > (define c2 (make-counter)) > (c1 ':get-value) 0 > (c2 ':get-value) 0 > (c1 ':increment!) > (c1 ':increment!) > (c1 ':increment!) > (c1 ':get-value) 3 > (c2 ':get-value) 0 Let's think about turtles * What values might we store for a turtle? * x and y position * direction * color * brush * up-or-down pen * image * We'll start with simpler turtles * x and y position * direction (define canvas (image-show (image-new 200 200))) (define sam-the-turtle (let ((x (vector 100)) (y (vector 100)) (angle (vector 0))) (lambda (message) (cond ; Move the turtle forward ten spaces ((eq? message 'forward!) ; Figure the destination (let ((newx (+ (vector-ref x 0) (* 10 (cos (vector-ref angle 0))))) (newy (+ (vector-ref y 0) (* 10 (sin (vector-ref angle 0)))))) ; Draw a line (image-draw-line! canvas (vector-ref x 0) (vector-ref y 0) newx newy) ; Change its position (vector-set! x 0 newx) (vector-set! y 0 newy))) ((eq? message ':turn!) (vector-set! angle 0 (+ (/ pi 16) (vector-ref angle 0)))) (else (error ": Does not understand your message" message))))))