Trait a konstruktor

Re:Trait a konstruktor
« Odpověď #15 kdy: 19. 12. 2020, 01:34:00 »
V první otázce zní: Nezneužívat dědičnost, radši na to vzít traity. Já říkám: Ale já vidím kompozici, k té traity nepotřebuju. Odpověď: V kontextu OOP je to jinak. Tak jak je to? Co je trait?

Abych nebyl za kverulanta, já bych prostě inicializoval v konstruktoru, kde bych volal konstruktor traitu. Nebo je myšlena nějaká automatická inicializace? Asi nerozumím té otázce. Je to otázka po syntaxi, sémantice, runtime? Všechno je možný - můžu inicializovat aspektem, anotací...


BoneFlute

  • *****
  • 1 974
    • Zobrazit profil
Re:Trait a konstruktor
« Odpověď #16 kdy: 19. 12. 2020, 01:44:11 »
V první otázce zní: Nezneužívat dědičnost, radši na to vzít traity. Já říkám: Ale já vidím kompozici, k té traity nepotřebuju. Odpověď: V kontextu OOP je to jinak. Tak jak je to? Co je trait?
To máš buřt.

Abych nebyl za kverulanta, já bych prostě inicializoval v konstruktoru, kde bych volal konstruktor traitu. Nebo je myšlena nějaká automatická inicializace? Asi nerozumím té otázce. Je to otázka po syntaxi, sémantice, runtime? Všechno je možný - můžu inicializovat aspektem, anotací...

Takhle?:
Kód: [Vybrat]
class Foo {
    use A;
    use B;
    public constructor(int id, string name) {
        A.constructor(id);
        B.constructor(name);
    }
}

Asi nerozumím té otázce. Je to otázka po syntaxi, sémantice, runtime? Všechno je možný - můžu inicializovat aspektem, anotací...
Syntaxe.

Jak tyto vlastnosti inicializovat, případně když ta inicializace má nějakou komplexní logiku. Proč by to měl být problém souvisí poněkud s tím, že ty fieldy z traitu jsou privátní, mají nějaký provázaný stav, který by si měl hlídat ten trait.

Re:Trait a konstruktor
« Odpověď #17 kdy: 19. 12. 2020, 08:15:18 »
class C(val f: Integer) extends T {
  def printF(): Unit = {
    println(f)
  }
}
Tohle je docela hezký.

Jde nějak ještě když bych tomu chtěl přidat nějakou logiku? Tedy konstruktor přijme f, přepočítá ho, a teprve výsledek uloží do fieldu f?

Místo konstruktoru použiješ faktory metodu, typicky v associated objectu třídy.


trait T {
  def f: Integer
}

class C(val f: Integer) extends T {
  def printF(): Unit = {
    println(f)
  }
}

object C {
  def apply(s: String): C = {
    new C(s.toInt)
  }
}

object Main {
    def main(args: Array[String]): Unit = {
      C("11").printF()
    }
}

Ale taky mám radši composition over inheritance. Kdybych chtěl skládat tvůj UserAccount podle toho vzoru co ukazuješ, použil bych kompozici. I když by to ve Scale šlo poskládat z traitů s fieldy jak chceš, nelíbilo by se mi, že v definici UserAccount není jasně na jednom místě vidět, jaké fieldy nakonec v té třídě budou, člověk si musí projít všechny traity zvlášť, a přitom fieldy a jejich typy bývají pro porozumění kódu většinou to nejdůležitější.

BoneFlute

  • *****
  • 1 974
    • Zobrazit profil
Re:Trait a konstruktor
« Odpověď #18 kdy: 19. 12. 2020, 17:00:53 »
... nelíbilo by se mi, že v definici UserAccount není jasně na jednom místě vidět, jaké fieldy nakonec v té třídě budou, člověk si musí projít všechny traity zvlášť, a přitom fieldy a jejich typy bývají pro porozumění kódu většinou to nejdůležitější.

On ten dotaz tak trochu vycházel z mého požadavku toho DSLka. Kde se to používá trochu naopak. Většinou si prohlížíš ten výsledný typ, se všema fieldama a behaviours, co to cestou posbíralo. A teprve sekundárně doklikáváš, kde je to nadefinované.

Ale pokud tě napadá jaká další úskalí to může mít, sem s tím.

Re:Trait a konstruktor
« Odpověď #19 kdy: 20. 12. 2020, 01:34:06 »
V první otázce zní: Nezneužívat dědičnost, radši na to vzít traity. Já říkám: Ale já vidím kompozici, k té traity nepotřebuju. Odpověď: V kontextu OOP je to jinak. Tak jak je to? Co je trait?
To máš buřt.

Abych nebyl za kverulanta, já bych prostě inicializoval v konstruktoru, kde bych volal konstruktor traitu. Nebo je myšlena nějaká automatická inicializace? Asi nerozumím té otázce. Je to otázka po syntaxi, sémantice, runtime? Všechno je možný - můžu inicializovat aspektem, anotací...

Takhle?:
Kód: [Vybrat]
class Foo {
    use A;
    use B;
    public constructor(int id, string name) {
        A.constructor(id);
        B.constructor(name);
    }
}

Asi nerozumím té otázce. Je to otázka po syntaxi, sémantice, runtime? Všechno je možný - můžu inicializovat aspektem, anotací...
Syntaxe.

Jak tyto vlastnosti inicializovat, případně když ta inicializace má nějakou komplexní logiku. Proč by to měl být problém souvisí poněkud s tím, že ty fieldy z traitu jsou privátní, mají nějaký provázaný stav, který by si měl hlídat ten trait.

Jo, jestli jde o syntax, líbí se mi to jak to uvádíš výše. Všechnu logiku bych dal do konstruktorů jako programový kód, IMHO to je nejčitelnější. Co se týče chování, nedělat bych tam žádnou automagii, to se vyplatí až při násobném použité té magie. Co se týče čitelnosti traitu a srozumitelnosti z čeho je výsledný objekt poskládaný, tak podle mě mají traity smysl právě tehdy, když je nemusím moc číst. Já mám traity třeba WithLogger, WithImages, WithRelations apod. kde právě dělám kompozici. Ten trait přidává jednu jednoduchou pochopitelnou vlastnost (logger, obrázky...). Výhoda je samosebou znovupoužitelnost spojená s flexibilitou. Takže pokud mám nějaký objekt a k němu chci obrázky, tak jen připojím trait. Přidám jedno slovo a je hotovo. Razantně lepší než dědičnost, citelně lepší než kompozice. Pokud pak v objektu intenzivně metody traitu používám a chci jeho chování zase odstranit, stačí trait odpojit a opravit chyby kompilátoru. Zase lepší než dědičnost a srovnatelné s kompozicí.


BoneFlute

  • *****
  • 1 974
    • Zobrazit profil
Re:Trait a konstruktor
« Odpověď #20 kdy: 20. 12. 2020, 02:33:33 »

Kit

  • *****
  • 663
    • Zobrazit profil
    • E-mail
Re:Trait a konstruktor
« Odpověď #21 kdy: 20. 12. 2020, 19:45:28 »
V první otázce zní: Nezneužívat dědičnost, radši na to vzít traity. Já říkám: Ale já vidím kompozici, k té traity nepotřebuju. Odpověď: V kontextu OOP je to jinak. Tak jak je to? Co je trait?

Abych nebyl za kverulanta, já bych prostě inicializoval v konstruktoru, kde bych volal konstruktor traitu. Nebo je myšlena nějaká automatická inicializace? Asi nerozumím té otázce. Je to otázka po syntaxi, sémantice, runtime? Všechno je možný - můžu inicializovat aspektem, anotací...

Také nevidím smysl traitů, kompozice se mi jeví jako přehlednější. Když ji injektuji do konstruktoru, mohu bohatě využít polymorfismu, což u traity není možné. Například logger je takto jednodušší než přes traitu - mohu ho z vnějšku vyměnit nebo zaslepit, a to pro každou instanci zvlášť.

Re:Trait a konstruktor
« Odpověď #22 kdy: 20. 12. 2020, 22:07:52 »
Souhlas, že traity a DI jsou částečně zastupitelné přístupy. Vhodnost jednoho či druhého záleží IMHO na okolnostech.

BoneFlute

  • *****
  • 1 974
    • Zobrazit profil
Re:Trait a konstruktor
« Odpověď #23 kdy: 20. 12. 2020, 23:09:07 »
Souhlas, že traity a DI jsou částečně zastupitelné přístupy. Vhodnost jednoho či druhého záleží IMHO na okolnostech.
Nemohu souhlasit. Tyto dva koncepty spolu nijak nesouvisí. Traity jsou o lepení kódu. DI je o přiznání závislostí. Nebe a dudy.

Idris

  • *****
  • 2 285
    • Zobrazit profil
    • E-mail
Re:Trait a konstruktor
« Odpověď #24 kdy: 20. 12. 2020, 23:53:01 »
Souhlas, že traity a DI jsou částečně zastupitelné přístupy. Vhodnost jednoho či druhého záleží IMHO na okolnostech.
Nebe a dudy.
Tak.

Re:Trait a konstruktor
« Odpověď #25 kdy: 21. 12. 2020, 08:20:40 »
Souhlas, že traity a DI jsou částečně zastupitelné přístupy. Vhodnost jednoho či druhého záleží IMHO na okolnostech.
Nemohu souhlasit. Tyto dva koncepty spolu nijak nesouvisí. Traity jsou o lepení kódu. DI je o přiznání závislostí. Nebe a dudy.

Souhlasim, ze je tam rozdil, ale nevidim ze by u toho traitu ta zavislost byla mene priznana.

Kit

  • *****
  • 663
    • Zobrazit profil
    • E-mail
Re:Trait a konstruktor
« Odpověď #26 kdy: 21. 12. 2020, 09:48:48 »
Souhlas, že traity a DI jsou částečně zastupitelné přístupy. Vhodnost jednoho či druhého záleží IMHO na okolnostech.
Nemohu souhlasit. Tyto dva koncepty spolu nijak nesouvisí. Traity jsou o lepení kódu. DI je o přiznání závislostí. Nebe a dudy.

Souhlasim, ze je tam rozdil, ale nevidim ze by u toho traitu ta zavislost byla mene priznana.

U traitu je ta závislost vnitřní, u DI vnější.

Ink

  • *****
  • 600
    • Zobrazit profil
    • E-mail
Re:Trait a konstruktor
« Odpověď #27 kdy: 21. 12. 2020, 09:52:04 »
im, ze je tam rozdil, ale nevidim ze by u toho traitu ta zavislost byla mene priznana.

Podle mě ses zaměřil na obecný význam slova "závislost", ale ne na skutečnou funkci DI třeba v tom konstruktoru. Trait řeší chování celé třídy (typu), DI rozhoduje o situaci či chování konkrétní instance.

Re:Trait a konstruktor
« Odpověď #28 kdy: 21. 12. 2020, 10:33:09 »
class C(val f: Integer) extends T {
  def printF(): Unit = {
    println(f)
  }
}
Tohle je docela hezký.

Jde nějak ještě když bych tomu chtěl přidat nějakou logiku? Tedy konstruktor přijme f, přepočítá ho, a teprve výsledek uloží do fieldu f?

Dotty (Scala 3) podporuje parametrizované traity. (A také "intersection types", které mohou při práci s traity přijít vhod.)

Kód: [Vybrat]
trait Polite(text: String) {
  val greeting = init(text)
  def greet(name: String) = s"$greeting $name!"
  private def init(s: String) = s"${text.toUpperCase},"
}

trait Curious(val question: String)

class MessageStyle(g: String) extends Polite(g) with Curious("How are you?")

def composeMessage(data: Polite & Curious, name: String): String = {
  s"${data.greet(name)}\n${data.question}"
}

object Main extends App {
  val messageStyle = MessageStyle("hello")
  println(composeMessage(messageStyle, "World"))
}
(https://scastie.scala-lang.org/VCcgilMpRMWpnZ773wMJIw)

Re:Trait a konstruktor
« Odpověď #29 kdy: 21. 12. 2020, 15:10:59 »
im, ze je tam rozdil, ale nevidim ze by u toho traitu ta zavislost byla mene priznana.

Podle mě ses zaměřil na obecný význam slova "závislost", ale ne na skutečnou funkci DI třeba v tom konstruktoru. Trait řeší chování celé třídy (typu), DI rozhoduje o situaci či chování konkrétní instance.

Přesně. Navíc DI je zpravidla runtime kdežto traity compile time. Někdy potřebujeme to a jindy ono.