TDDC74 Programmering: Abstraktion och modellering VT 2015 Johannes Schmidt Institutionen för datavetenskap Linköpings universitet Lecture 9 Mutable structres, ADTs, OOP • • • • Abstract data types: queue, stack Mutable pairs, lists: singly / doubly linked list Object Oriented Programming (OOP) in Racket SICP-Book chapter: 3 An abstract data type: Stack Think of a stack as a pile of books (items): TOS: Top Of Stack. Insertion (push) and extraction (pop) only at the TOS. LIFO = last in, first out An abstract data type: Stack ADT Stack Methods: •push: put a given item on the stack. This item is then the new TOS. •pop: remove the TOS-item and return it. Optional methods: •size: determine the number of elements currently in the stack. •empty?: check whether the stack is empty. •peek: return the TOS-item without removing it. An abstract data type: Queue Think of a queue as a queue of people (items): Insertion (enqueue) at the rear, extraction (dequeue) at the front. FIFO = first in, first out An abstract data type: Queue ADT Queue Methods: •enqueue: put a given item into the queue, at the rear. •dequeue: remove an item from the queue, at the front. Optional methods: •size: determine the number of elements currently in the queue. •empty?: check whether the queue is empty. •peek: return the front-item without removing it. How to implement a stack, a queue? Singly linked list Doubly linked list? Doubly linked list A doubly linked list with insertion and extraction at both ends can be used to implement both, stack and queue push pop enqueue dequeue - insert at front - extract at front - insert at rear - extract at front How to implement singly / doubly linked lists? Singly linked list Easy: take on ordinary list Doubly linked list Easy: create a triple-object with selectors left, middle, right E.g. (define (make-triple left middle right) (mcons left (mcons middle right))) Object Oriented Programming Is a programming paradigm. Idea: every problem can be described by objects and their interactions / relations. This helps creating abstractions and achieving encapsulation. Therefore: in order to solve a problem, break it down into subproblems, by identifying objects and how they interact with and relate to each other. OOP Example Game Pac-Man Scenario: Pac-Man goes through a labyrinth, eats pellets and has to avoid being eaten/attacked by enemies. Identify Objects: • • • • • Pac-Man Pellet Enemy Power pellet … Source: http://en.wikipedia.org/wiki/Pac-Man OOP Example Relations between Objects: • • • • Pac-Man eats Pellets Enemy eats/attacks Pac-Man Pac-Man eats Power pellet Pac-Man eats Enemy if eaten recently Power pellet • … Source: http://en.wikipedia.org/wiki/Pac-Man Object Oriented Programming Is a programming paradigm. Idea: every problem can be described by objects and their interactions / relations. Relations between objects indicate what different properties the different objects should have. These properties are realized via fields (variables/data) and methods (procedures): Every object has its own fields and methods! OOP Example Some fields of some Objects: Pac-Man: • Lifes (0-3) • Score (0-1000000) • State: recently Power pellet eaten? • … Enemy: • Color • State: currently eatable or not? • Direction • Speed • … Source: http://en.wikipedia.org/wiki/Pac-Man OOP Example Some methods of some Objects: Pac-Man: • (eat-enemy enemy) • (reduce-life amount) • (eat-pellet pellet) • (die) • … Enemy: • (eat-Pac-Man) • (change-eatable-state value) • (speed-up) • (die) • … Source: http://en.wikipedia.org/wiki/Pac-Man OOP Example Game Pac-Man Observation: some objects will occur just once, others several times Occurrences of Objects: • • • • 1x Pac-Man Nx Pellet 4x Enemy 4x Power pellet Source: http://en.wikipedia.org/wiki/Pac-Man OOP Example Game Pac-Man Observation: some objects will occur just once, others several times Occurrences of Objects: • • • • 1x Pac-Man Nx Pellet 4x Enemy 4x Power pellet Solution: Classes! Source: http://en.wikipedia.org/wiki/Pac-Man OOP - Classes A Class can be considered as a model for objects that share the same properties, but are still different individuals. If we have a class definition, we can then create an object from that class. This process is called instantiating. For this purpose every class provides a constructor. OOP Example Game Pac-Man Classes for Pac-Man: • • • • Pac-Man Pellet Enemy Power-pellet Then instantiate • • • • One object of Pac-Man Many objects of Pellet Four objects of Enemy Four objects of Power-pellet Source: http://en.wikipedia.org/wiki/Pac-Man OOP - Inheritance A Class can be considered as a model for objects that share the same properties, but are still different individuals. What if we have similar classes that share a lot of common properties but are not exactly the same? Solution: We can derive or inherit a class from another. Via Inheritance we obtain a derived class, or a subclass. Think of this as taking a copy of a class, and then modifying this copy according to our needs. OOP Example Game Pac-Man Similar classes for Pac-Man: • • Pellet Power-pellet For instance make Power-pellet a subclass of Pellet, i.e. treat a Power-pellet as a special case of a Pellet. Alternatively: Have a common superclass, call it General-pellet. Then derive once an Ordinarypellet and once a Power-pellet. Source: http://en.wikipedia.org/wiki/Pac-Man OOP in Racket - simple (define (make-pac-man lifes score pp-eaten) ; three fields (define (dispatch message . args) ; define different methods (cond ((eq? message 'eat-enemy) (if pp-eaten (void) 'not-possible)) ; details to be implemented ((eq? message 'reduce-life) (set! lifes (- lifes (car args)))) ((eq? message 'eat-pellet) (set! score (+ score 1))) ((eq? message 'die) (void)) ; details to be implemented ((eq? message 'say-hello) (printf "Hi I am a happy pac-man with ~a lifes\n" lifes)) (else '(unkown message)))) dispatch) OOP in Racket - simple (define (make-pac-man lifes score pp-eaten) ; three fields (define (dispatch message . args) ; define different methods (cond ((eq? message 'eat-enemy) (if pp-eaten ; create a Pac-Man: instantiate (void) ; details to be implemented (define my-pac-man (make-pac-man 3 0 #f)) 'not-possible)) ((eq? message 'reduce-life) ; call some (set! lifes (- lifes (car(my-pac-man args)))) (my-pac-man ((eq? message 'eat-pellet) (my-pac-man (set! score (+ score 1))) ((eq? message 'die) (void)) methods 'say-hello) 'reduce-life 1) 'say-hello) Output: ; happy details to be with implemented Hi I am a pac-man 3 lifes Hi I am a happy pac-man with 2 lifes ((eq? message 'say-hello) (printf "Hi I am a happy pac-man with ~a lifes\n" lifes)) (else '(unkown message)))) dispatch) OOP in Racket (define Pac-Man% (class object% ; fields (variables/data) (init-field lifes score pp-eaten) (super-new) ; superclass initialization (define/public (eat-enemy enemy) ; method (if pp-eaten (void) ; details to be implemented 'not-possible)) (define/public (reduce-life amount) (set! lifes (- lifes amount))) ; method (define/public (eat-pellet pellet) (set! score (+ score 1))) ; method (define/public (die) ; method (void)) ; details to be implemented (define/public (say-hello) (printf "Hi I am a happy pac-man with ~a lifes\n" lifes)))) OOP in Racket (define Pac-Man% (class object% ; fields (variables/data) (init-field lifes score pp-eaten) ; create a Pac-Man: instantiate (super-new) ; superclass initialization (define my-pac-man (make-object Pac-Man% 3 0 #f)) (define/public (eat-enemy enemy) ; method (if pp-eaten ; call some methods (void) ; details tomy-pac-man be implemented (send say-hello) 'not-possible)) (send my-pac-man reduce-life 1) my-pac-man say-hello) (define/public (reduce-life(send amount) ; method (set! lifes (- lifes amount))) Output: (define/public (eat-pellet pellet) ; method Hi I am a happy pac-man with 3 lifes (set! score (+ score 1)))Hi I am a happy pac-man with 2 lifes (define/public (die) ; method (void)) ; details to be implemented (define/public (say-hello) (printf "Hi I am a happy pac-man with ~a lifes\n" lifes)))) OOP in Racket - Inheritance (define General-pellet% (class object% ; fields (variables/data) (init-field color position) (super-new) ; superclass initialization (define/public (get-type) ; method 'general))) (define Ordinary-pellet% (class General-pellet% (super-new) ; superclass initialization (define/override (get-type) ; method 'ordinary))) (define Power-pellet% (class General-pellet% (super-new) ; superclass initialization (define/override (get-type) ; method 'power))) OOP in Racket - Inheritance (define General-pellet% (class object% We inherit from object% This is a special inbuilt base class ; fields (variables/data) (init-field color position) (super-new) ; superclass initialization (define/public (get-type) ; method 'general))) (define Ordinary-pellet% (class General-pellet% We inherit from General-pellet% (super-new) ; superclass initialization (define/override (get-type) ; method 'ordinary))) (define Power-pellet% (class General-pellet% And here too (super-new) ; superclass initialization (define/override (get-type) ; method 'power))) OOP in Racket - Overriding (define General-pellet% (class object% ; fields (variables/data) (init-field color position) (super-new) ; superclass initialization (define/public (get-type) ; method 'general))) (define Ordinary-pellet% (class General-pellet% We inherit ALL fields and methods. That is: (super-new) ; superclass initialization - no need to redefine ;fields (define/override (get-type) methodor methods - if we want to change a method, we need 'ordinary))) to explicitly override (redefine) it (define Power-pellet% (class General-pellet% (super-new) ; superclass initialization (define/override (get-type) ; method 'power))) OOP in Racket - Instantiation (make-object <Class> <list of init-values>) (define my-pac-man (make-object Pac-Man% 3 0 #f)) ; Alternatively: (new <Class> [varname1 value1] [varname2 value2] ...) (define my-pac-man (new Pac-Man% [lifes 3] [score 0] [pp-eaten #f])) OOP in Racket – calling methods From inside the class definition you call methods as usual. From outside special syntax is provided: (send <object> <method-name> <list of parameters>) ; e.g.: (send my-pac-man say-hello) (send my-pac-man reduce-life 1) (send my-pac-man say-hello) OOP in Racket – field vs init-field (define Pac-Man% (class object% ; init-fields, i.e. values MUST ; be provided during instantiation (init-field lifes score pp-eaten) ; ordinary fields, i.e. values must be provided ; right here (field [color 'red] [more-stuff 'hmblhmbl]) ... OOP in Racket – accessing fields From inside the class definition you access fields as usual variables. From outside special syntax is provided: (get-field <field-name> <object-name>) (set-field! <field-name> <object-name> value) E.g. (define my-pac-man (make-object Pac-Man% 3 0 #f)) (get-field color my-pac-man) (set-field! color my-pac-man 'green) But: avoid setting fields this way. Better provide your own methods to change the values of fields. OOP in Racket – Visibility public vs private (define Pac-Man% (class object% ; public fields (visible/accessible from outside) (init-field lifes score pp-eaten) (field [color 'red] [more-stuff 'hmblhmbl]) ; private fields (not visible from outside) (define internal-value 11439) ; public method (visible/accessible from outside) (define/public (eat-enemy enemy) ; method (if pp-eaten (void) ; details to be implemented 'not-possible)) ; private method (not visible from outside) (define (do-some-stuff parameter1) ...) OOP notions object, class field, method inherit, derive, extend subclass, superclass override OOP purpose Remember: use OOP in order to create abstractions and to achieve encapsulation (hide implementation details). Therefore: keep as much as possible private, so it is not visible to the outside. Expose to the outside only what is absolutely necessary. Provide public methods to manipulate variables/fields, do not set them directly.