Pular para o conteúdo

A superfície é o contrato

O que um módulo exporta, com que aridade e com que tipos — e por que mudá-la é o mesmo problema que quebrar uma ABI.

Numa linguagem compilada, quebrar a ABI é trocar o layout de uma struct ou a convenção de chamada. O sintoma é cruel: o programa carrega e corrompe memória, longe da causa e sem nada denunciar.

Aqui não há layout binário a quebrar. E existe exatamente o mesmo problema, com outro nome.

Na linguagem compiladaAqui
símbolo removido do .sosímbolo tirado do relay
assinatura trocadaaridade, nome ou tipo de parâmetro trocado
layout de struct mudadocampo acrescentado a um record
tipo de retorno trocadoo mesmo — e ele atravessa o adopt
soname bumpversão maior no forge.toml

O que é contrato, e o que não é#

A superfície respeita o relay. Um módulo que declara o que exporta está dizendo que o resto é interno — e o que é interno não é contrato, então mexer nele não quebra ninguém.

lib.df — o relay decide
action somar(a: Integer, b: Integer) -> Integer:
    yield a + b

action interna():          // nao esta no relay: nao e contrato
    yield 1

record Ponto:
    x: Integer
    y: Integer

relay somar, Ponto

Sem relay, tudo o que é de topo é contrato — o que é a escolha certa para um arquivo que não declarou nada, e um bom motivo para declarar.

A superfície, como dado#

dataforge
adopt Arcane.Abi as Abi

// Abi.superficie("lib.df") devolve, por simbolo:
//   especie      acao, record, blueprint, enum, trait, valor
//   minimo       quantos argumentos ele EXIGE
//   maximo       quantos ele ACEITA (void = variadico)
//   parametros   os nomes, na ordem — e eles sao contrato
//   tipos        o tipo declarado de cada um
//   retorno      o tipo de retorno, que atravessa o adopt
//   campos       de um record ou blueprint
//   linha        onde ele foi declarado

assert len(keys(Abi.regras())) bigger_eq 7