5. Advanced Object-Oriented Programming Language-Oriented Programming Prof. Dr. Bernhard Humm Faculty of Computer Science Hochschule Darmstadt University of Applied Sciences 1
Retrospective Functional Programming What is a higher-order function? What is a lambda function / closure? Are closures just syntactic sugar or are they more powerful than named functions? Is there behaviour that you can express with closures that you cannot express with named functions? Explain sort, detect, select, collect, and inject What additional documentation features are implemented in the language functional.1? Do they form a language extension? What are pre- and post-conditions / design by contract? Which design-by-contract features are implemented in the language functional.1? Do they form a language extension? 2
This lecture in the context of the entire course 1. Introduction 2. Lisp Crash Course 3. Functional programming 4. Advanced object-oriented programming 5. Business information systems 6. Database queries 7. Logic programming 8. Workflows 9. Implementing a DSL: Macros 3
Agenda Classes Instances Methods Advanced concepts 4
Defining classes Schema for defining classes: Extension of cl:defclass with convenience features (define-class name (direct-superclass-name*) (slot-specifier*)) Example: Class name (define-class bank-account () (customer-name balance)) Slots a.k.a. instance variables / attributes bank-account +customer-name +balance 5
bank-account +customer-name +balance Inheritance Lisp provides multiple inheritance Examples: checking-account savings-account +credit-limit +interest-rate money-market-account (define-class checking-account (bank-account) (credit-limit)) Slots additional to inherited ones from superclass (define-class savings-account (bank-account) (interest-rate)) (define-class money-market-account (checking-account savings-account) ()) Multiple inheritance: slots from all superclasses (bank-account, savings-account, and checking-account) are inherited 6
Slot and class options Lisp provides useful slot and class options via keyword parameters Examples: (define-class bank-account () ((customer-name :type 'string :documentation "Surname of the customer") (balance :initform 0) (all-accounts :allocation :class)) (:documentation "General bank account )) Specifies the slot data type (quoted!) (validation platform-specific) Documents the slot Initializes the slot with a value Specifies slot as class slot (static variable in Java). Default: instance slot Documents the class 7
Agenda Classes Instances Methods Advanced concepts 8
Instantiation Instantiation of classes via make-instance Class name (quoted!) (make-instance 'bank-account) #<bank-account @ #x21135952> (make-instance 'checking-account :customer-name "Seibel") #<checking-account @ #x211382ca> Keyword parameters according to slot names (convenience feature of define-class) (make-instance 'savings-account :customer-name "Steele" :interest-rate 0.03) #<savings-account @ #x2113b352> 9
Slot access Convenience feature of create-class: automatic generation of getters and setters The examples make use of imperative programming in Lisp: - Local variables - Assignments - Sequential execution (let (account) Definition of local variables that can be used within the scope of let; sequential execution of following forms Assignment of a value to a variable (setf account(make-instance 'bank-account)) (set-balance 42 account) Write access of slot balance (print (get-balance account))) 42 Read access of slot balance 10
Agenda Classes Instances Methods Advanced concepts 11
Methods = functions Methods are defined as functions outside the class definition (unlike Java, C++, Smalltalk) Allows for multi-methods introduced later Class specified via :type keyword; parameter name and type declaration enclosed in list (define-function withdraw ((account :type bank-account) amount) (set-balance (- (get-balance account) amount) account)) Method body: implementation of functionality 12
Method invocation Methods are invoked like funtions (unlike message passing in Java, C++, Smalltalk) (let (account) (setf account(make-instance 'bank-account :balance 40)) (withdraw account 15) (print (get-balance account))) Method invocation 25 13
Polymorphism Methods are inherited and can be overwritten by subclasses The implementation is selected according to the type of the actual parameter passed Method definition for savings-account (define-function withdraw ((account :type savings-account) amount) (if (> amount (get-balance account)) (error "Account overdrawn") (call-next-method))) Invocation of withdraw of class bank-account (similar to super in Java) 14 (let (account) (setf account(make-instance 'savings-account :balance 40)) (withdraw account 50)) Error "Account overdrawn" Invocation of withdraw for savings-account according to type of object account
Agenda Classes Instances Methods Advanced concepts 15
Multimethods: Polymorphism over several parameters Powerful concept: Lisp methods may behave polymorphic over several parameters Avoids if/else cascades or stragegy pattern Example: Classic polymorphism: method applies to all subclasses of bank-account (define-function transfer ((from :type bank-account) (to :type bank-account) amount) ;;; general behaviour (withdraw from amount) (deposit to amount)) (define-function transfer ((from :type checking-account) (to :type savings-account) amount) ;;; specific behaviour... ) Advanced polymorphism: method applies to the combination checking-account / savings-account and its respective subclasses 16
Method definitions specific to literal values Methods may be defined for concrete numbers or (quoted) symbols if their treatment is special Example: Is invoked if and only if amount = 42 (define-function withdraw ((account :type bank-account) 42) (print "The answer to all questions, universe, and everything") (call-next-method)) Invokes standard withdraw method Avoids if-cascades for special cases 17
:before :after and :around Methods Concept to elegantly factor out tests and functionality to be evaluated before and after method invocation Declares a method to be invoked Example: before primary withdraw methods (define-function withdraw :before ((account :type savings-account) amount) (if (> amount (get-balance account)) (error "Account overdrawn"))) to be invoked after primary withdraw methods (define-function withdraw :after ((account :type bank-account) 42) (print "The answer to all questions, universe, everything")) Result: as in previous examples but better separated from default business logic 18
:before :after and :around Methods (cont d) Invocation order: 1. All :before methods (here withdraw for savings-account) 2. All primary methods, i.e., without :before, :after, or :around specifier (here: withdraw for bank-account) 3. All :after methods :around-methods are wrapped around all invocations 19