Scala - jópofa dolgok a trait-ek

Előjött egy olyan feladat, hogy egy "kibővíthető" metódusra van szükségem egy osztályon belül.
Van egy alapfunkcionalitás: nem csinál semmit. Ezt szeretném kibővíteni különböző dolgokkal: loggoljon, üzenetet küldjön valaki másnak, ábrázoljon grafikonon, whatever. Lényeg: ezek tetszőleges kombinációját kellene tudnia csinálni. És erre gyönyörűen működik a következő kód:


trait Base { 
  private def _name() = "Base"
  def func = _name
} 
trait A extends Base { 
  private def _name() = "A"
  override def func = _name + " extends " + super.func
}
trait B extends Base { 
  private def _name() = "B"
  override def func = _name + " extends " + super.func
}
val x = new Base with A with B
val y = new Base with B with A

println(x.func)
println(y.func)

Hogy mi készül éppen? Demonstrációs célokból szükségem van egy egyszerű Network-on-a-Chip szimulátorra, és úgy gondolom, az Actor model ennek leírására kiválóan használható (esetünkben Akka).

Scala rulez, teljesen rajongója lettem.

Hozzászólások

Örülök, hogy neked is tetszik!

Annyi kiegészítést tennék a kódhoz, hogy nem szokás aláhúzással kezdeni az azonosítókat, illetve ami nem függvény, hanem konstans, azt lehet val-lal definiálni akkor is, ha a szülőben def-volt, mint itt a name, illetve nem szükséges a végére a zárójel, ahogy a func végére se tettél. (A func végére inkább lehetne rakni, mert az tényleg függvény, szemben a name-mel).

Én inkább ilyenre írnám:


trait Base { 
  private def name = "Base"
  def func = name
} 
trait A extends Base { 
  private val name = "A"
  override def func = name + " extends " + super.func
}
trait B extends Base { 
  private val name = "B"
  override def func = name + " extends " + super.func
}
val x = new Base with A with B
val y = new Base with B with A

println(x.func)
println(y.func)

Egyébként ezekben a témakörökben (Scala, Akka, FP) mindig szívesen segítek, ha bármi kérdésed lenne!

Így már értem, hogy pontosan mire gondoltál. Azt hittem az extrémet szélsőséges értelemben érted, vagyis, hogy meg lehet csinálni úgy is, de nem igazán jó megoldás. Holott a példádból is látszik, hogy egyszerűbb és sokkal általánosabban, rugalmasabban használható az FP megoldás, mint az OO.

Amire folyamatosan rádöbbenek: eszméletlenül kifejező nyelv, nagyon jóleg tudom vele fogalmazni a dolgokat.

Egy valami hiányzik most: generikus osztályban az adott típusból példány létrehozása. No jó, meg a parametrizálható trait-ek, de azt tagváltozókkal meg lehet oldani.

"generikus osztályban az adott típusból példány létrehozása."

Ez alatt mit értesz? Esetleg egy példa is jó volna, hogy mire használnád!

Szerk.: Közben rájöttem, hogy valószínűleg a generikus típusból szeretnél létrehozni egy példányt az osztályon belül. Erre az a megoldás, hogy megadsz az osztályodnak egy factory függvényt, ami létrehozza, lásd itt.

A fordítási időben még ismert típushoz tartozó Manifest-et a fordító képes fordítási időben implicit elérhetővé tenni, így futás időben olyan információt ad a típusról, ami egyébként a type erasure miatt elveszne. Ennek csak egy aspektusa az, hogy elérhetővé válik a típushoz tartozó Class objektum.

Ahogy írtam, a Manifest-et implicit adja oda a fordító, a lenti két metódus (majdnem) ekvivalens:


def foo[T : Manifest] = manifest[T].toString

def bar[T](implicit mf: Manifest[T]) = mf.toString

A fenti kódban a manifest[T] visszaadja az implicit elérhető Manifest[T]-t, így lehetne implementálni (ez egy gyakori trükk Scalaban implicitek környékén, pl. az Ordering is tud ilyesmit):


def manifest[T](implicit mf: Manifest[T]) = mf

A Manifestben az a jó, hogy a fordító mindjárt tudja is használni, pl: http://ideone.com/VUcCfB

ez menő. viszonylag sokat gondolkoztam mostanság azon, miért nem csináltak valami hasonlót Java-ban - ha már a generikusok csak így kókányolva kerültek be a nyelvbe. s hogy van-e, lenne-e bármilyen akadálya, akár nyelvi szinten, akár JVM szinten. De ezek szerint JVM szinten nincs.

az ideone-os példában azt kéne látnom, hogy a fordító a generikus típus alapján tudja, hogy a két függvényhívás közül (

safePrint2[Int](iToS) orElse safePrint2[Boolean](bToS)

) melyiket is kell majd meghívnia?

Ez bájtkódban hogy jelenik meg? A safePrint2 függvényből kettő lesz bátjkód szinten?

Mindenesetre ez bookmark, köszi szépen - ha lesz egy kis időm, a vizsgaidőszak után, alaposabban belemélyedek ebbe, elég érdekesnek tűnik.
--
blogom