Pular para o conteúdo

O sistema de tipos

O mapa: tipos internos, anotações, coleções tipadas, tipos nomeados, generics, indexados, opacos e traits — e o que cada camada garante.

O DataForge é de tipagem dinâmica com anotação verificada: você escreve o tipo onde ele importa, e a linguagem cobra em duas horas diferentes — o dataforge check antes de rodar, quando consegue provar, e o interpretador na fronteira, sempre.

As camadas#

CamadaEscreve-seQuem conferePágina
tipos internosInteger, String, Cluster, Vault, Set, Tuple, Frozen, Bytes, Anyexecução, na anotaçãoTipos
anotaçãox: Integer := 3, -> Floatas duasAnotações
conteúdo de coleçãoCluster<Integer>, Vault<String, Pedido>, Set<T>fronteira, inserção e checkAnotações
tuplaTuple<Integer, String>posição e tamanhoTuplas
alias, união, interseçãotype Json := String \| Integeras duasTipos nomeados
refinamentotype Positivo := Integer where valor bigger 0toda fronteira, e check sobre literalTipos nomeados
opacoopaque type Cpf := String where …nominal: só o construtor criaTipos nomeados
generics<T>, <T extends Number>limite nas duas metadesGenerics
indexadoVetor<3>a regra vê o númeroGenerics
traitstrait, extends, type Item, &declaração e execuçãoTraits

Um exemplo com todas elas#

dataforge
type Id := Integer
type Email := String where "@" in valor
type Vetor<N> := Cluster<Float> where len(valor) is N
opaque type Cpf := String where len(valor) is 11

trait Auditavel:
    action resumo() -> String

record Cliente<T extends Number>:
    id: Id
    email: Email
    documento: Cpf
    saldo: T
    coordenada: Tuple<Float, Float>

blueprint Carteira extends Auditavel:
    clientes: Cluster<Cliente> := []

    action guardar(c: Cliente):
        self.clientes.append(c)
        yield self

    action resumo() -> String:
        yield $"{len(self.clientes)} cliente(s)"

action distancia(a: Vetor<2>, b: Vetor<2>) -> Float:
    yield ((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2) ** 0.5

c := Cliente(1, "ana@exemplo.com", Cpf("12345678901"), 250.0, (1.0, 2.0))
carteira := spawn Carteira()
carteira.guardar(c)

assert carteira.resumo() is "1 cliente(s)"
assert c.documento.valor is "12345678901"
assert distancia([0.0, 0.0], [3.0, 4.0]) is 5.0

Quando cada uma acusa#

A regra é uma só: o analisador cala quando não consegue provar. Um falso alarme ensina a desligar a verificação, e aí ela deixa de valer para tudo.

SituaçãocheckExecução
x: Integer := "a"acusa (type-mismatch)acusa
x: Positivo := -1acusa (tipo-refinado)acusa
x: Positivo := ler()calaacusa se o valor não servir
xs: Cluster<Integer> := [1, "a"]acusa (tipo-do-conteudo)acusa
xs.append("a") num Cluster<Integer>acusa quando conhece a coleçãoacusa sempre
f("texto") num <T extends Number>acusa (generic-bound)acusa
cadastrar("123…") num Cpfacusa (tipo-opaco)acusa

O que o sistema de tipos NÃO faz#

Vale dizer, para ninguém contar com o que não está aqui.

Não existePor quê
inferência de tipo para variável sem anotaçãoa linguagem é dinâmica: o analisador infere o que consegue para acusar, e não para exigir
monomorfização e especializaçãonão há compilação para código de máquina
variância declarada (in/out)ainda não — Cluster<T> é conferido item a item
prova formal do refinamentoo where é verificado, não provado: literal no check, valor na fronteira
apagamento de tipo, ABI, layoutassunto de linguagem compilada; aqui a anotação é conferência em execução