Vererbungstechniken in Scala

Unter Berücksichtigung von Mix-Ins

Stefan Winter

Ludwig-Maximilians-Universität München

Folien online

https://www.stefan-winter.net/presentations/vererbung_scala.html

Überblick und Lernziele

  • Wiederholung: Ziele der Vererbung in OO-Sprachen
  • Welche Vererbungsmechanismen stellt Scala zur Verfügung?
  • Wie unterscheiden sich Traits von Java Interfaces?

Wiederholung: Vererbung in Java

Vererbung:

  • Modellierung von
    Typ-Beziehungen
  • Vermeidung von
    Code-Duplikaten

Java:

  • Klassenvererbung via extends
class A {
    public void sayTruth() {
        System.out.println("42");
    }
}

Wiederholung: Vererbung in Java

Vererbung:

  • Modellierung von
    Typ-Beziehungen
  • Vermeidung von
    Code-Duplikaten

Java:

  • Klassenvererbung via extends
class A {
    public void sayTruth() {
        System.out.println("42");
    }
}

class B extends A {
    public void sayLie() {
        System.out.println("cake");
    }
}

Wiederholung: Vererbung in Java

Vererbung:

  • Modellierung von
    Typ-Beziehungen
  • Vermeidung von
    Code-Duplikaten

Java:

  • Klassenvererbung via extends
class A {
    public void sayTruth() {
        System.out.println("42");
    }
}

class B extends A {
    public void sayLie() {
        System.out.println("cake");
    }
}

public class Main {
    public static void main(String[] args) {
        B b = new B();
        b.sayLie();
        b.sayTruth();
    }
}

Vererbung in Scala

Klassenvererbung via extends

class A {
    def sayTruth(): Unit = println("42")
}

class B extends A {
    def sayLie(): Unit = println("cake")
}
class A {
    public void sayTruth() {
        System.out.println("42");
    }
}

class B extends A {
    public void sayLie() {
        System.out.println("cake");
    }
}

public class Main {
    public static void main(String[] args) {
        B b = new B();
        b.sayLie();
        b.sayTruth();
    }
}

Beispiel: Fuhrparkmanagement

classDiagram
    class Automobil {
        String räder
        String standort
    }

class Automobil(var räder: String, var standort: String) 

Klassenvererbung

Spezialisierung zur Berücksichtigung von Eigenheiten

classDiagram
    class Automobil {
        String räder
        String standort
    }

    class ElektroAuto {
        Int batterieLadung
        laden(sekunden, ladegerät) Unit
    }

    Automobil <|-- ElektroAuto

class Automobil(var räder: String, var standort: String) 

class ElektroAuto(var batterieLadung: Int, 
                  räder: String, 
                  standort: String) 
    extends Automobil(räder, standort) {
    def laden(sekunden: Int, ladegerät: Ladegerät) = {
        batterieLadung += ladegerät.laden(sekunden)
    }
}

Transitive Klassenvererbung

Generalisierung auf Fahrzeuge

classDiagram
    class Fahrzeug {
        String standort
    }

    class Automobil {
        String räder
    }

    class ElektroAuto {
        Int batterieLadung
        laden(sekunden, ladegerät) Int
    }

    Fahrzeug <|-- Automobil
    Automobil <|-- ElektroAuto

class Fahrzeug(var standort: String)

class Automobil(var räder: String, standort: String) 
    extends Fahrzeug(standort)

class ElektroAuto(var batterieLadung: Int, 
                  räder: String, 
                  standort: String) 
    extends Automobil(räder, standort) {
    def laden(sekunden: Int, ladegerät: Ladegerät) = {
        batterieLadung += ladegerät.laden(sekunden)
    }
}

Multiple Klassenvererbung

Mehrere Unterklassen

classDiagram
    class Fahrzeug {
        String standort
    }

    class Automobil {
        String räder
    }

    class Raumfahrzeug {
        Int missionen
    }

    Fahrzeug <|-- Automobil
    Fahrzeug <|-- Raumfahrzeug

class Fahrzeug(var standort: String)

trait Raumfahrzeug extends Fahrzeug {
    var missionen = 0
    def entsende() = {
        missionen += 1
    }
}

class Automobil(var räder: String, standort: String) 
    extends Fahrzeug(standort)

Multiple Klassenvererbung

Mehrere Oberklassen

classDiagram
    class Fahrzeug {
        String standort
    }

    class Automobil {
        String räder
    }

    class Raumfahrzeug {
        Int missionen
    }

    class MarsRover {
        String name
    }

    Fahrzeug <|-- Automobil
    Fahrzeug <|-- Raumfahrzeug
    Automobil <|-- MarsRover
    Raumfahrzeug <|-- MarsRover

class Fahrzeug(var standort: String)

trait Raumfahrzeug extends Fahrzeug {
    var missionen = 0
    def entsende() = {
        missionen += 1
    }
}

class Automobil(var räder: String, standort: String) 
    extends Fahrzeug(standort)

class MarsRover(var name: String, standort: String) 
    extends Automobil("space wheels", standort) 
    with Raumfahrzeug

Unterschiede zu Java Interfaces

  1. Traits können zustandsbehaftete Logik vererben
trait Raumfahrzeug extends Fahrzeug {
    var missionen = 0
    def entsende() = {
        missionen += 1
    }
}

Unterschiede zu Java Interfaces

  1. Traits können zustandsbehaftete Logik vererben
  2. Trait Mix-ins führen Initialisierungscode aus
trait Raumfahrzeug extends Fahrzeug {
    println("Ich bin ein Raumfahrzeug!") // Ausführung beim Mix-in
    var missionen = 0
    def entsende() = {
        missionen += 1
    }
}

Unterschiede zu Java Interfaces

  1. Traits können zustandsbehaftete Logik vererben
  2. Trait Mix-ins führen Initialisierungscode aus
  3. Lösung von “Diamonds” durch Trait-Linearization

classDiagram
    class Fahrzeug {
        String standort
        *fahre(ort) Unit
    }

    class Automobil {
        String räder
        fahre(ort) Unit
    }

    class Raumfahrzeug {
        Int missionen
        fahre(ort) Unit
    }

    class MarsRover {
        String name
    }

    Fahrzeug <|-- Automobil
    Fahrzeug <|-- Raumfahrzeug
    Automobil <|-- MarsRover
    Raumfahrzeug <|-- MarsRover

  • Vererbung unterschiedlicher fahre-Methoden
    → welche gilt für MarsRover?
  • Trait-Linearization: Das “rechteste” Mix-in gewinnt
class MarsRover(var name: String, standort: String) 
    extends Automobil("space wheels", standort) 
    with Raumfahrzeug

Zusammenfassung

  • Ziele der Vererbung in OO-Sprachen
  • Welche Vererbungsmechanismen stellt Scala zur Verfügung?
  • Wie unterscheiden sich Traits von Java Interfaces?

Ausblick

Ergänzungen und Anknüpfungspunkte:

  • Abstrakte Methoden/Attribute und override
  • Sichtbarkeit und Implikationen für Vererbung
  • Self-types zur Modellierung von Trait-Abhängigkeiten
  • Einschränkung der Vererbung bei Case-classes

Literatur:

  • Odersky, Spoon, Venners, Sommers: “Programming in Scala”,   Fifth edition, Artima press, 2021