Pular para o conteúdo

Traits

Contratos de interface compostos com with.

Declarar#

dataforge
trait Serializavel:
    action serializar()

trait Comparavel:
    action comparar(outro)

Um trait lista assinaturas — ações sem corpo. Ele descreve o que um tipo deve saber fazer.

Compor#

dataforge
blueprint Produto(nome, preco) with Serializavel, Comparavel:
    action serializar():
        yield {"nome": self.nome, "preco": self.preco}

    action comparar(outro):
        yield self.preco - outro.preco

a := spawn Produto("Mouse", 80)
b := spawn Produto("Teclado", 200)

out a.serializar()
out a.comparar(b)          # -120

Um blueprint pode compor vários traits: with A, B, C.

Métodos com corpo#

Um trait pode trazer implementação padrão. Ela só é usada se o blueprint não definir a própria:

dataforge
trait Descritivel:
    action descrever():
        yield $"<{typeof(self)}>"      # padrão

blueprint Simples with Descritivel:
    # herda descrever()
    action nada():
        yield void

blueprint Detalhado(nome) with Descritivel:
    action descrever():                # sobrescreve
        yield $"Detalhado: {self.nome}"

A limitação atual#

Enquanto isso, quando a garantia importa, verifique em tempo de execução:

dataforge
action processar(item):
    guard has_method(item, "serializar"), $"{typeof(item)} nao implementa Serializavel"
    yield item.serializar()

Trait ou herança?#

Use traitUse extends
definir uma capacidadeespecializar um tipo
vários tipos não relacionadosrelação "é um tipo de"
compor várias capacidadesuma cadeia de especialização
sem estado compartilhadoreaproveitar campos e lógica

Na dúvida: se você diria "um Produto é um Serializável", talvez seja herança. Se diria "um Produto sabe serializar", é trait.

Introspecção#

dataforge
out has_method(a, "serializar")     # yes
out get_methods(a)                  # todos os métodos disponíveis
out get_mro(a)                      # ordem de resolução