Montag, 20. September 2010

Scala: Klassen erweitern mal anders

Datentypen erweitern ist mehr oder weniger etwas das man des öfteren machen muss, und das ist nicht umbedingt immer unproblematisch. Nehmen wir mal an wir hätten folgende Klasse:

class Test(val x: Int)

Ganz klar: hochkomplizierter Code. Test quillt an Features nur so über, aber uns fehlt gerade eine Methode damit
wir Objekte dieser Klasse in unserem Code nahtlos verwenden können. Diese Methode nennen wir bla. Das Problem ist allerdings: Wir haben den Code von Test nicht und können ihn deswegen nicht um bla erweitern.
Jetzt gibt es verschiedene Wege wie wir diese Methode in Test einbinden könnten. Der offensichtlichste ist sicherlich Vererbung. Blöd ist nur: Wir haben bla schon geschrieben und würden ihn ungern duplizieren, vor allem weil wir den Code bereits schön generalisiert haben.

Eine Lösung ist hier ziemlich elegant mit Traits, Selftyping und Structural Types zu machen.

Als erstes definieren wir einen Structural Type der eine genaue Schnittstelle definiert. Wir nennen ihn xAble und er macht nichts weiter als zu definieren das alle Klassen die eine Methode x anbieten vom Typ xAble sind.

type xAble = { def x: Int }

Was wir jetzt brauchen ist unsere generalisierte Implementation von bla. Hier verwenden wir, Selftyping. Das ist ein Feature das es uns erlaubt innerhalb eines Traits so zu tun als wäre es von einem bestimmten Typ ohne davon zu erben.

trait Gimme[A <: xAble] {
self: A =>
def bla(): Unit = println(self.x + 1)
}

Wie man sieht muss der muss der Typparameter A ein Subtyp von xAble sein, also die methode x liefern.

Alles was wir jetzt noch machen müssen ist das Trait Gimme in das Objekt des Typs Test zu mischen und wir haben das ganze um bla erweitert.

object Main {

class Test(val x: Int)

type xAble = { def x: Int }

trait Gimme[A <: xAble] {
self: A =>
def bla(): Unit = println(self.x + 1)
}

def main(args: Array[String]): Unit = {
val t = new Test(666) with Gimme[Test]
t.bla()
}
}

Das ganze Zeit mal wieder wie extrem mächtig das Scala Typsystem ist und was für elegante Features die Sprache zum lösen immer wiederkehrender Probleme bietet. Ich hoffe dieses Beispiel gibt euch eine kleine Idee was man damit machen kann. ;)