Angespornt durch die lange und informative Unterhaltung neben an (Sichtbarkeit Klassenvariablen) poste ich hier mal eine Frage, die ich schon länger hatte 
Angenommen ich möchte Abstract Syntax Trees (ASTs) in meinem Programm verwalten. Genauer gesagt ASTs von mathematischen Ausdrücken/Termen im Lambdakalkül, aber das ist nicht wirklich relevant für die Frage, erreicht aber, dass das Problem im trivialen Fall sich nicht in Luft auflöst. Dazu habe ich folgende Klassen in Scala:
Übersetzung für Nicht-Scala-Kenner: Case Classen als normale immutable Klassen vorstellen, Parameter in den runden Klammern sind nur Syntactic Sugar für Konstruktoten mit eben jenen Konstruktorargumenten.
Induktiver Algorithmus: Jetzt möchte ich z. B. alle Identifiers eines Terms sammeln. Das geht ganz einfach wie folgt in Scala:
Wie würde das in anderen (nicht-funktionalen) OOP-Sprachen aussehen?
Ich habe gerade nur zwei Optionen im Kopf:
Insbesondere gibt es ja unzählige Algorithmen, die man auf ASTs ausführen möchte! Mitunter auch konkurrierende, sodass man auch auf Namensgebung Acht geben müsste.
Fällt einem von euch eine dritte bessere Möglichkeit ein?
Ich habe in letzter Zeit viel mit Scala gearbeitet und mich sehr mit funktionalen Sprachen i. Allg. angefreundet
Wobei ich 'purity' zwar theoretisch interessant finde, aber für großere Projekte wohl eine 'impure' Sprache wie Scala auch ihre Vorzüge hat.

Angenommen ich möchte Abstract Syntax Trees (ASTs) in meinem Programm verwalten. Genauer gesagt ASTs von mathematischen Ausdrücken/Termen im Lambdakalkül, aber das ist nicht wirklich relevant für die Frage, erreicht aber, dass das Problem im trivialen Fall sich nicht in Luft auflöst. Dazu habe ich folgende Klassen in Scala:
Java:
// Example: λx. x + x
// Would be represented as: Binding(Context with 'x', Application(Identifier('+', List(Variable('x'), Variable('x')))))
abstract case class Term
// Example: λx. x + x
// Definition of Context irrelevant
case class Binding(context: Context, body: Term) extends Term
// Example: x + x (application of identifier + to arguments x and x)
case class Application(function: Term, arguments: List[Term]) extends Term
// Example: x
case class Variable(name: String) extends Term
// Example: +
case class Identifier(name: String) extends Term
Induktiver Algorithmus: Jetzt möchte ich z. B. alle Identifiers eines Terms sammeln. Das geht ganz einfach wie folgt in Scala:
Java:
def collectIdentifiers(term: Term): List[String] = term match {
case Binding(_, body) => collectIdentifiers(body)
case Application(fun, args) => (fun :: args).flatMap(collectIdentifiers) // prepend fun to arg list and then flatMap!
case Variable(_) => Nil
case Identifier(name) => List(name)
}
Wie würde das in anderen (nicht-funktionalen) OOP-Sprachen aussehen?
Ich habe gerade nur zwei Optionen im Kopf:
- Der Term-Klasse eine abstrakte Methode collectIdentifiers spendieren und diese in allen Kindklassen überladen.
- Analog zur Scala-Lösung, aber mit sehr unschönem instanceof-Checking.
Insbesondere gibt es ja unzählige Algorithmen, die man auf ASTs ausführen möchte! Mitunter auch konkurrierende, sodass man auch auf Namensgebung Acht geben müsste.
Fällt einem von euch eine dritte bessere Möglichkeit ein?
Ich habe in letzter Zeit viel mit Scala gearbeitet und mich sehr mit funktionalen Sprachen i. Allg. angefreundet
