Lecture 21
Mutation and Sub-typing
Logistics and Week Ahead
For some - Ethics Module 8 - Sustainability
Reminders:
Calling functions for their effects
reviewing record (named) structures
Aka “structs”
Looking inside record structures
Rectangle
Width: 10
Height: 10
Ellipse
Width: 15
Height: 10
Function
Name: iterated-overlay
Arguments: proc count
Body: [apply group� [up-to count
Color
R: 240
G: 220
B: 0
A new kind of CUSTOM object: the album
Example: Making the album type
(define-struct album (title artist genre))
This defines 5 new functions for us automagically:
Making new data types with imperatives
(define-struct typename (field-names …))
Mutators that set the value of the specified fieldname of the object to a new value
Example: Making the album type
(define-struct album (title artist genre))
set-album-title/artist/genre! : album string -> (void) ��MUTATORS
Example time!
subtypes
Type hierarchies are trees
object
number
integer
float
procedure
posn
color
picture
string
boolean
exception
contract-violation
arity-mismatch
Imagine we want to create an animal struct
animal
cat
dog
mouse
Making new subtypes
(define-struct (typename parenttype) (field-names …))
Special case…type with no special attributes?
(define-struct (typename parenttype) ())
Example time!
Defining and Modifying a Snake (w/o mutation)
; a snake is:
; - (make-snake number symbol)
(define-struct snake (weight food))
Defining and Modifying a Snake (w/o mutation)
; feed-snake : Snake -> Snake
; feeds the snake a 5lb meal
(define (feed-snake s)
(make-snake (+ 5 (snake-weight s)) (snake-food s)))
(check-expect (feed-snake (make-snake 4 "rat"))
(make-snake 9 "rat"))
(check-expect (feed-snake (make-snake 9 "mouse"))
(make-snake 14 "mouse"))
Defining and Modifying a Snake (w/ mutation)
; feed-snake! : snake -> void
; feeds the snake a 5lb meal
; Effect: the input snake weighs 5lb more
(define (feed-snake! s)
(set-snake-weight! s (+ 5 (snake-weight s))))
(define a-snake (make-snake 4 "rat"))
(check-expect (begin (feed-snake! a-snake)
(snake-weight a-snake))
9) ; checking side effect, mutation
(check-expect (feed-snake! a-snake)
(void)) ; checking output
Defining and Modifying an Armadillo
; an armadillo is
; (make-armadillo number boolean)
(define-struct armadillo (weight dead?))
; Constructors
; make-armadillo : number bool -> armadillo
; Predicate
; armadillo? : any -> bool
; Accessors
; armadillo-weight : armadillo -> number
; armadillo-dead? : armadillo -> bool
; Mutators
; set-armadillo-weight! : armadillo number -> void
; set-armadillo-dead?! : armadillo bool -> void
Feeding an Armadillo (w/o Mutation)
; feed-armadillo : armadillo -> armadillo
; feeds a armadillo a 2lb meal if it isn't dead
(define (feed-armadillo d)
(cond [(armadillo-dead? d) (make-armadillo (armadillo-weight d)
true)] ; or just return d
[else (make-armadillo (+ 2 (armadillo-weight d))
false)]))
(check-expect (feed-armadillo (make-armadillo 12 false))
(make-armadillo 14 false))
(check-expect (feed-armadillo (make-armadillo 11 true))
(make-armadillo 11 true))
Feeding an Armadillo (w/ Mutation)
; feed-armadillo! : armadillo -> void
; feeds a armadillo a 2lb meal if it isn't dead
; Effect: an alive armadillo is 2lb larger
(define (feed-armadillo! d)
(unless (armadillo-dead? d)
(set-armadillo-weight! d (+ 2 (armadillo-weight d)))))
(define armadillo-1 (make-armadillo 12 #false))
(define armadillo-2 (make-armadillo 13 #true))
(check-expect (begin (feed-armadillo! armadillo-1)
(armadillo-weight armadillo-1))
14)
(check-expect (begin (feed-armadillo! armadillo-2)
(armadillo-weight armadillo-2))
13)
Defining an Ant
; an ant is
; - (make-ant number posn)
(define-struct ant (weight loc))
; make-ant
; ant?
; ant-weight, ant-loc
; set-ant-weight!, set-ant-loc!
Feeding an ant w/mutation
(define antonio-banderas (make-ant 0.01 (make-posn 0 0)))
(define ulysses-s-grant (make-ant 0.005 (make-posn 2 3)))
(define marc-antony (make-ant 0.01 (make-posn 0 0)))
; feed-ant! : Ant -> void
; feeds ant a 0.01lb meal
; Effect: ant is 0.01 larger
(define (feed-ant! a)
(set-ant-weight! a (+ 0.01 (ant-weight a))))
(check-expect (begin (feed-ant! marc-antony)
(ant-weight marc-antony))
0.02)
What if we want to make a zoo…and find the sum of the weight of all the animals?
(define i-bought-a-zoo (list a-snake
armadillo-1
armadillo-2
marc-antony
antonio-banderas
ulysses-s-grant))
Solution: Type Dispatch!
; weight : animal -> number
; returns the weight of a particular animal
(define (weight a)
(cond [(snake? a) (snake-weight a)]
[(armadillo? a) (armadillo-weight a)]
[(ant? a) (ant-weight a)]))
; zoo-weight : (listof animals) -> Number
; takes a list of animals and returns the sum of their weights
(define (zoo-weight loa)
(cond [(empty? loa) 0]
[else (+ (weight (first loa))
(zoo-weight (rest loa)))]))
(check-expect 41.035
(zoo-weight my-first-zoo))
Problem: This seems silly.
animal
cat
dog
mouse
Subtypes are the Answer!
; an animal is:
; - (make-animal string number number)
(define-struct animal (name weight age))
; a cat is:
; - (make-cat string number number string)
(define-struct (cat animal) (sleeping-spot))
; cat-sleeping-spot
; set-cat-sleeping-spot!
; cat-name,cat-weight,cat-age, ACCESSORS/MUTATORS DON’T EXIST
; instead use animal-name, animal-weight, animal-age
Now ASL will handle Type Dispatch for us!
; zoo-weight-2 : list-of-animals -> Number
; takes a list of animals and returns a sum of their weights
(define (zoo-weight-2 zoo)
(cond [(empty? zoo) 0]
[else (+ (animal-weight (first zoo))
(zoo-weight-2 (rest zoo)))]))
; As long as we give it any animal or subtype of animal,
; it will run just fine!