Lange Rede, kurzer Unsinn: Ich will Multimethods in Scala! Auf den ersten Blick klingt das als würde man sich eine Sprache zu etwas hinbiegen wollen was sie gar nicht ist, aber in Scala geht das ganze erschreckend schmerzlos.
Zum dispatchen verwende ich einfach ein paar partielle Funktionen die man mit
orElse
beliebig aneinanderketten kann. Der Vorteil davon ist das ich keinen Code aufmachen muss wenn ich einen weiteren Fall hinzufügen will sondern durch Komposition zum Ziel komme.
trait Dynamic
class A extends Dynamic
class B extends Dynamic
object Dynamic {
// 2 dynamische argumente
type Dyn2 = (Dynamic, Dynamic)
// infix notation fuer PartialFunction
type ~>[A, B] = PartialFunction[A, B]
val f: Dyn2 ~> String = {
case (a: A, b: A) => "A A"
}
val g: Dyn2 ~> String = {
case (a: A, b: B) => "A B"
}
// d ist die dispatchfunktion
def dispatch[A, B](d: A ~> B, a: A): Option[B] =
if (d.isDefinedAt(a)) Some(d(a))
else None
}
In Aktion sieht das Ganze so aus:
scala> :l ./dynamic.scala
Loading ./dynamic.scala...
defined trait Dynamic
defined class A
defined class B
defined module Dynamic
scala> import Dynamic._
import Dynamic._
scala> dispatch(f, (new A, new A))
res0: Option[String] = Some(A A)
scala> dispatch(f, (new A, new B))
res1: Option[String] = None
scala> dispatch(f orElse g, (new A, new B))
res2: Option[String] = Some(A B)
Wie man schön sehen kann werden auch die nicht abgedeckten Fälle behandelt indem wir einfach eine
Option
verwenden, dadurch könnten wir unseren Dispatch auch in einer for
-Comprehension verwenden (Monaden für den Gewinn!)Viel Spass beim ausprobieren ;)
Hier ein kleiner Nachtrag wozu Multimethods gut sind. Für alle die Das Visitorpattern schon immer gehasst haben ;)