Lecture 23
FP vs. OOP Decomposition;
Double Dispatch
Programming Languages
UW CSE 341 - Winter 2023
Breaking Things Down
Summary
“The Expression Problem”
FP Approach = “By Column”
See code!
OOP Approach = “By Row”
See code!
A Big Course Punchline
Extensibility
???
???
FP Extensibility
See code!
???
😃
???
😭
😭
😭
OOP Extensibility
???
???
😭
😃
😭
😭
See code!
Extensibility is Difficult
Thoughts on extensibility
Binary Operations and OOP’s “Double Dispatch”
add
Example
add
Binary Operations Easy in FP
See code!
add
Now try OOP...
add
(define add% …
(define/public (eval)
(send (send _e1 eval) add-value (send _e2 eval)))
(define int% …
(define/public (add-value other) …)
(define string% …
(define/public (add-value other) …)
(define rational% …
(define/public (add-value other) …)
Uh-oh
(define int% …
(define/public (add-value other)
(cond [(is-a? other int%) … ] ; get other’s i and +
[(is-a? other string%) …] ; get other’s s and concat
[(is-a? other rational%) …] ; get other’s n,d and math
[#t (error …)])))
add
Another way
Double-dispatch
See code!!
Why am I teaching you this?
Works in Java too
In a statically typed OOP language, double-dispatch works without problem:
abstract class Value extends Exp {
abstract Value addValue(Value other);
abstract Value addInt(Int other);
abstract Value addString(MyString other);
abstract Value addRational(Rational other);
}
class Int extends Value { … }
class Strng extends Value { … }
class Rational extends Value { … }
See code!
[optional material ahead]
[We won’t test you on what remains in this lecture and it’s not on the homework]
But this will improve your understanding of:
So don’t be surprised if you find yourself looking for this material some day :-)
Java, in more common practice
Because Java has static overloading, no need to give different names to methods that take different types of arguments
Can make double dispatch seem even more magical/confusing, but same thing:
abstract class Value extends Exp {
abstract Value add(Value other);
abstract Value add(Int other);
abstract Value add(MyString other);
abstract Value add(Rational other);
}
See code!
What if instead...
What if we could implement 9 add-value methods and have:
Pick the right 1 of the 9 with one dispatch?
This would require dynamic dispatch on the receiver and the argument
(define add%
…
(define/public (eval)
(send (send _e1 eval) add-value (send _e2 eval)))
add