Skip to content

Instantly share code, notes, and snippets.

@fiddlerwoaroof
Last active June 13, 2019 17:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save fiddlerwoaroof/74ce5e9a39100573a2801c78d620cb71 to your computer and use it in GitHub Desktop.
Save fiddlerwoaroof/74ce5e9a39100573a2801c78d620cb71 to your computer and use it in GitHub Desktop.
Static typable EP solution
//
// Two kinds of animals: dogs and cats
//
// I want greet and leave to be defined such that there are four
// different behaviors corresponding to each combination of dog and
// cat
//
class Animal {
receive_operation(operation) {
console.log("the animal is unresponsive");
}
}
class Operation {
operate() {
console.log("the animal is unresponsive");
}
}
class Turtle extends Animal {}
class Dog extends Animal {
receive_operation(operation) {
// This if statement is hard to add in an extensible fashion
if (operation instanceof Greet) {
console.log("the dog wags its tail joyfully");
} else if (operation instanceof Leave) {
console.log("the dog looks very sad");
}
}
}
class Cat extends Animal {
receive_operation(operation) {
if (operation instanceof Greet) {
console.log("the cat stands aloof");
} else if (operation instanceof Leave) {
console.log("the cat purs happily");
}
}
}
class Greet extends Operation {}
class Leave extends Operation {}
function operate(animal, operation) {
animal.receive_operation(operation);
}
function main() {
for (const animal of [new Cat(), new Dog(), new Turtle()]) {
for (const operation of [new Greet(), new Leave()]) {
operate(animal, operation);
}
}
}
main();
(defpackage :fwoar.extend
(:use :cl )
(:export ))
(in-package :fwoar.extend)
#| ------------- Begin Library ------------- |#
(defclass animal ()
())
(defclass operation ()
())
(defgeneric operate (animal operation)
#| This method ensures type safety: as long as we're given something in the domain of the function
(animal, operation) => effect}, we'll get a result. |#
(:method ((animal animal) (operation operation))
(format *standard-output* "the animal is unresponsive~%")))
(defclass turtle (animal)
())
#| -------------- End Library -------------- |#
(defclass cat (animal)
(#| cat-specific members here |#))
(defclass dog (animal)
(#| dog-specific members here |#))
(defclass greet (operation)
())
(defclass leave (operation)
())
(defmethod operate ((animal cat) (operation greet))
(format *standard-output* "the cat stands aloof~%"))
(defmethod operate ((animal cat) (operation leave))
(format *standard-output* "the cat purs happily~%"))
(defmethod operate ((animal dog) (operation greet))
(format *standard-output* "the dog wags its tail joyfully~%"))
(defmethod operate ((animal dog) (operation leave))
(format *standard-output* "the dog looks very sad~%"))
(defun main ()
(dolist (animal (list (make-instance 'cat)
(make-instance 'dog)
(make-instance 'turtle)))
(dolist (action (list (make-instance 'greet)
(make-instance 'leave)))
(visit animal action)))) #| ===>
FWOAR.EXTEND> (main)
the cat stands aloof
the cat purs happily
the dog wags its tail joyfully
the dog looks very sad
the animal is unresponsive
the animal is unresponsive
|#
@friedbrice
Copy link

@fiddlerwoaroof
Copy link
Author

Kotlin does control-flow-sensitive type specialization which sort of fixes the issue I have with Java, at the cost of a bit of boilerplate:

https://gist.github.com/fiddlerwoaroof/b24b321ddcfb11470241326e4dd7552d#file-world-kt-L14-L21

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment