Pular para o conteúdo

Blueprints

Classes: construtores, herança, traits, polimorfismo, estáticos e sobrecarga de operadores.

Declarar#

Um blueprint é a classe do DataForge. Os parâmetros do cabeçalho viram campos automaticamente:

dataforge
blueprint Ponto(x, y):
    action distancia():
        yield sqrt(self.x ** 2 + self.y ** 2)

    action toString():
        yield $"({self.x}, {self.y})"

p := spawn Ponto(3, 4)
out p, p.x, p.distancia()
saída
(3, 4) 3 5.0

spawn instancia. forge é sinônimo, e chamar o blueprint diretamente (Ponto(3, 4)) também funciona.

Construtor com setup#

Para inicializar campos derivados, use o método setup:

dataforge
blueprint Pedido:
    action setup(cliente):
        self.cliente := cliente
        self.itens := []

    action adicionar(item):
        self.itens.append(item)
        yield len(self.itens)

p := spawn Pedido("Ana")
p.adicionar("mouse")

As duas formas convivem: se um blueprint tem parâmetros e um setup, os parâmetros são atribuídos primeiro e depois o setup roda.

Herança#

dataforge
blueprint Animal(nome):
    action falar():
        yield "..."
    action apresentar():
        yield $"{self.nome} diz {self.falar()}"

blueprint Cachorro(nome) extends Animal:
    action falar():
        yield "Au au"

blueprint Gato(nome) extends Animal:
    action falar():
        yield "Miau"

cycle bicho in [spawn Cachorro("Rex"), spawn Gato("Mia")]:
    out bicho.apresentar()
saída
Rex diz Au au
Mia diz Miau

apresentar está definido só no pai, mas chama self.falar() — que resolve para a versão do filho. Isso é polimorfismo.

root — chamar o pai#

dataforge
blueprint Base(nome):
    action descrever():
        yield $"Base:{self.nome}"

blueprint Derivada(nome) extends Base:
    action descrever():
        yield $"Derivada[{root.descrever()}]"

out (spawn Derivada("teste")).descrever()

Traits#

Um trait declara um contrato. Um blueprint o compõe com with:

dataforge
trait Serializavel:
    action serializar()

trait Comparavel:
    action comparar(outro)

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

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

Membros estáticos#

dataforge
blueprint Contador:
    static total := 0

    action inc():
        Contador.total := Contador.total + 1

c := spawn Contador()
c.inc()
out Contador.total     # 1 — compartilhado por todas as instâncias

Sobrecarga de operadores#

Defina os métodos com estes nomes e os operadores passam a funcionar:

MétodoOperador
add+
sub-
mul*
div/
mod%
pow**
floordiv~/
toStringout e str()
setup / initiateo construtor, chamado por spawn
dataforge
blueprint Vetor(x, y):
    action add(o):
        yield spawn Vetor(self.x + o.x, self.y + o.y)
    action mul(k):
        yield spawn Vetor(self.x * k, self.y * k)
    action toString():
        yield $"<{self.x}, {self.y}>"

out spawn Vetor(1, 2) + spawn Vetor(3, 4)     # <4, 6>
out spawn Vetor(1, 2) * 3                     # <3, 6>

Introspecção#

dataforge
p := spawn Ponto(3, 4)

out typeof(p)              # Ponto
out class_name(p)          # Ponto
out get_fields(p)          # os campos da instância
out get_methods(p)         # os métodos disponíveis
out has_method(p, "distancia")
out has_field(p, "x")
out get_mro(p)             # ordem de resolução de métodos

Blueprint ou record?#

Use recordUse blueprint
dados sem comportamento próprioobjetos com estado que muda
igualdade por valoridentidade importa
imutávelprecisa mutar campos
sem herançaherança, traits, polimorfismo

Detalhes em Records.