Lecture 21 Slides - Mutation and Subtypes

1 of 29

Lecture 21

Mutation and Sub-typing

2 of 29

Logistics and Week Ahead

For some - Ethics Module 8 - Sustainability

  • Monday - Mutation and Sub-types
  • Wednesday - Methods (Pre-Recorded + MQ15) + Tutorial 8
  • Friday - Q3 Review (MQ 16) (Ex 7 Due)

Reminders:

  • Ethics module reflections due Sunday at 11:59pm

3 of 29

Calling functions for their effects

  • You can write functions that make a wide range of changes in the computer
    • Changing a variable's value (assignment)
    • Changing a data object (mutation)
    • Creating files
    • Creating windows
    • Performing input or output
  • Commands that change the computer this way are called imperatives
  • As with everything else in this class, complex effects
    • Are ultimately built up from a few kinds of simple effects
    • And methods for combining them

4 of 29

reviewing record (named) structures

Aka “structs”

5 of 29

Looking inside record structures

  • Data objects are like forms
    • They have fields
    • Filled in by values
  • The fields
    • Have names (width, height)
    • The fields are filled with other data objects
  • The object’s type (rectangle, ellipse) determines what fields it has

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

6 of 29

A new kind of CUSTOM object: the album

  • Let’s say we want to catalog our music collection
  • We’ll use a new kind of data object, the album
  • An album will have three fields, each holding a string:
    • Its title
      • "The Wall","The Fame Monster"
    • The artist who recorded it
      • "Frank Ocean","Frank Sinatra"
    • The album’s genre
      • "rock","hip hop","jazz","classical","comedy"

7 of 29

Example: Making the album type

(define-struct album (title artist genre))

This defines 5 new functions for us automagically:

  • (make-album title artist genre)�;; make-album : string string string -> albumMakes a new album with the specified title, artist, and genre. (constructor)
  • (album? object);; album? : any -> BooleanReturns true if object is an album, otherwise false
  • (album-title album), (album-artist album), (album-genre album)�;; album-title/artist/genre : album -> string Returns the title of the specified album object (accessors)

8 of 29

Making new data types with imperatives

(define-struct typename (field-names))

  • define-struct is a special form that makes new data types
  • Defines a set of new functions automagically:
    • (make-typename field-values …)�Makes a new object of the type, given values for its field
    • (typename? object)�Predicate that tests whether object is of the specified type
    • (typename-fieldname object)�Returns the value of the specified field of the object
    • (set-typename-fieldname! object new-value)

Mutators that set the value of the specified fieldname of the object to a new value

9 of 29

Example: Making the album type

(define-struct album (title artist genre))

  • (make-album title artist genre)�;; make-album : string string string -> albumMakes a new album with the specified title, artist, and genre. (constructor)
  • (album? object);; album? : any -> BooleanReturns true if object is an album, otherwise false
  • (album-title album), (album-artist album), (album-genre album)�;; album-title/artist/genre : album -> string Returns the title of the specified album object (accessors)
  • set-album-title!, set-album-artist!, set-album-genre! ;

set-album-title/artist/genre! : album string -> (void) MUTATORS

10 of 29

Example time!

11 of 29

subtypes

12 of 29

Type hierarchies are trees

  • Computers have a taxonomy of types of data objects
  • Types can have subtypes
    • Which can have subsubtypes

object

number

integer

float

procedure

posn

color

picture

string

boolean

exception

contract-violation

arity-mismatch

13 of 29

Imagine we want to create an animal struct

  • We want to be able to say
    • All cats are animals
    • Not all animals are cats
    • All dogs are animals
    • All mice are animals

  • In other words, cats are animals with extra properties
    • They inherit all the properties of animal
    • And then have extra stuff on top of that

animal

cat

dog

mouse

14 of 29

Making new subtypes

(define-struct (typename parenttype) (field-names))

  • This is an upgraded version of define-struct provided by the "define_super_struct.rkt" library we'll give you.
    • It doesn’t work in ASL by default.
  • typename is a subtype of parenttype
  • Defines functions automagically as before:
    • (make-typename paretntype-field-values … field-values …)�Must provide parenttype fields FIRST
    • (typename? object)
    • (typename-fieldname object)
  • But also says that
    • All instances of typename are ALSO instances of parenttype

15 of 29

Special case…type with no special attributes?

(define-struct (typename parenttype) ())

  • The parens are required even if you don’t want to specify any extra special attributes beyond those defined in the parent type

16 of 29

Example time!

17 of 29

Defining and Modifying a Snake (w/o mutation)

; a snake is:

; - (make-snake number symbol)

(define-struct snake (weight food))

18 of 29

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"))

19 of 29

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

20 of 29

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

21 of 29

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))

22 of 29

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)

23 of 29

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!

24 of 29

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)

25 of 29

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))

  • Problem: all of these animals have a weight attribute but they’re all accessed using different functions (i.e. ant-weight, armadillo-weight, snake-weight)

26 of 29

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))

  • Type dispatch means customizing a function’s behavior based on the types of data it receives as input.

27 of 29

Problem: This seems silly.

  • All of these animals have weight in common. We need to say “this thing is a new type, but also maintains all the attributes of being an animal”
  • We want to be able to say
    • All cats are animals
    • Not all animals are cats
    • All dogs are animals
    • All mice are animals

  • In other words, cats are animals with extra properties
    • They inherit all the properties of animal
    • And then have extra stuff on top of that

animal

cat

dog

mouse

28 of 29

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

29 of 29

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!