Pular para o conteúdo

Tipos

Os tipos primitivos, typeof, cast e as anotações opcionais verificadas.

Os tipos primitivos#

TipoExemplostypeof devolve
Inteiro42, 0xFF, 0b1010, 1_000_000"Integer"
Decimal3.14, 1.5e3"Float"
Texto"a", 'b', """várias linhas""""String"
Booleanoyes, no"Boolean"
Nulovoid"Void"
Lista[1, 2, 3]"Cluster"
Dicionário{"k": 1}"Vault"

Os nomes Cluster e Vault valem uma explicação: são lista e dicionário, com nomes que descrevem o uso — um agrupamento de itens e um cofre de pares chave-valor.

typeof#

typeof x devolve o mesmo nome que você usaria numa anotação. Isso não é detalhe: significa que as duas formas falam a mesma língua.

dataforge
idade: Integer := 30
out typeof(idade)          # Integer

record Ponto:
    x: Integer
    y: Integer

enum Cor:
    Vermelho

out typeof(42), typeof(3.14), typeof("a"), typeof(yes), typeof(void)
out typeof([1]), typeof({"k": 1})
out typeof(Ponto(1, 2))    # Ponto — o próprio nome do record
out typeof(Cor.Vermelho)   # Cor — o nome do enum

Conversão#

cast valor as Tipo converte explicitamente:

dataforge
out cast "42" as Integer      # 42
out cast 3.9 as Integer       # 3   — trunca, não arredonda
out cast 42 as String         # "42"
out cast "3.5" as Float       # 3.5

out str(42), int("7"), float("2.5"), bool(1)

Uma conversão impossível dispara erro em vez de devolver lixo:

dataforge
monitor:
    cast "abc" as Integer
handle e:
    out e.message

Anotações de tipo#

Opcionais, mas verificadas — tanto em tempo de execução quanto pelo analisador estático:

dataforge
idade: Integer := 30
nome: String := "Ana"
notas: Cluster := [8, 9, 10]
config: Vault := {"tema": "escuro"}

# recusado:
# quantidade: Integer := 3.5

Os nomes aceitos, com seus sinônimos:

CanônicoTambém aceita
Integerinteger, int
Floatfloat
Numbernumber — aceita Integer ou Float
Stringstring, str, text
Booleanboolean, bool
Clustercluster, list, array
Vaultvault, dict, map
Voidvoid, none
Actionaction, function
Anyany — desliga a checagem

Qualquer outro nome é tratado como nome de record, enum ou blueprint, e a checagem percorre a cadeia de herança.

A regra de alargamento#

Há uma única flexibilização, e ela existe porque é matematicamente segura:

dataforge
media: Float := 8          # ok: todo inteiro é um decimal válido
# quantidade: Integer := 3.5   # erro: 3.5 não é inteiro

Um Integer entra onde se espera Float. O contrário perderia informação, e por isso é recusado.

Tipagem gradual com Any#

Any diz explicitamente "qualquer tipo serve". É diferente de não anotar:

FormaSignifica
action f(x):não pensei sobre o tipo
action f(x: Any):pensei, e qualquer tipo serve

A segunda comunica intenção. Aceitar Any não significa tratar tudo igual — o padrão é estreitar logo na entrada com pattern matching:

dataforge
action descrever(v: Any) -> String:
    match v:
        point Integer as n:
            yield $"inteiro {n}"
        point String as s:
            yield $"texto de {len(s)} letras"
        point Cluster as c:
            yield $"lista com {len(c)} itens"
        default:
            yield "outro"