Pular para o conteúdo

Herança e traits

Estender sem reimplementar, e o que final impede.

`root` chama o pai#

dataforge
blueprint Documento:
    titulo: String := ""
    action setup(titulo):
        self.titulo := titulo

    action cabecalho():
        yield $"# {self.titulo}"

    action render():
        yield self.cabecalho()

blueprint Artigo extends Documento:
    autor: String := ""

    action setup(titulo, autor):
        self.titulo := titulo
        self.autor := autor

    // acrescenta ao do pai, em vez de refazer
    action cabecalho():
        yield root.cabecalho() + $"\npor {self.autor}"

É o que distingue estender de reimplementar: o filho acrescenta, e continua acompanhando as mudanças do pai.

Polimorfismo sem marcação#

Um método herdado que chama self.x() resolve para a versão do filho. No exemplo acima, render foi herdado sem mudança e usa o cabecalho sobrescrito.

`final`#

dataforge
blueprint Base:
    final action identidade():
        yield self._id

Impede a sobrescrita, e a tentativa falha na declaração do herdeiro:

text
erro[DF0301]: 'Filho.identidade' cannot override 'Base.identidade', which is declared final

Use no que o resto da hierarquia depende para funcionar — um método que outros métodos do pai chamam esperando um comportamento específico.

Traits#

dataforge
trait Serializavel:
    action serializar()              // exigência

    action salvar_em(caminho):       // padrão, herdado
        adopt Arcane.IO as IO
        IO.write(caminho, self.serializar())

blueprint Config with Serializavel:
    action serializar():
        yield "…"

Trait não guarda estado — por isso with aceita vários sem o problema clássico de herança múltipla.

Quando não herdar#

Herança amarra o filho ao pai para sempre. Antes de estender, pergunte se não é composição:

  • Herança quando A é um B — um Artigo é um Documento
  • Composição quando A tem um B — um Carro tem um Motor

Uma cadeia com mais de dois ou três níveis costuma ser sinal de que a modelagem foi longe demais. Veja modelagem.