Pular para o conteúdo

O livro · 12

Módulos e ecossistema

book.md · 103 linhas · 3 min de leitura

Objetivo: organizar código no modelo bin/lib, importar com use, entender os tiers de estabilidade, e conhecer as libs oficiais e o CLI mk.

Dois marcadores, com papéis distintos:

  • mk.mod marca um módulo, e um módulo é uma lib: uma caixa independente e reutilizável, com suas próprias dependências. Funciona como fronteira de namespace e de dependência. Nunca é compilado sozinho, apenas como parte da árvore de um projeto (módulos não-usados convivem sem custo).
  • mk.project marca o bin (o compositor): o módulo de topo e a unidade de compilação. Compõe os módulos numa árvore, declara a versão da linguagem, suas deps, e as tasks/produção de binário.
myapp/ ← mk.project (BIN: compõe módulos, tasks, deps)
├── mk.project
├── mk.sum (lockfile, auto-gerado)
├── main.mko → módulo "myapp"
├── auth/ ← mk.mod (LIB "myapp/auth", deps próprias)
│ └── tokens.mko
└── store/ ← mk.mod (LIB "myapp/store")
└── db.mko

O manifesto declara a versão da linguagem e as deps (estilo go 1.21):

mk.project
package myapp
makoto 1.0
deps {
github.com/acme/http 2.3.1
}
use json // monta o módulo → json.parse(...)
use json.{parse, decode} // levanta nomes → parse(...) direto
use json as j // alias

De onde vem cada use é decidido pelo prefixo: bare é stdlib (use io); nome-do-pacote é local (use myapp/auth); forma URL é externo (use github.com/acme/http). Imports são absolutos a partir do nome do pacote, nunca ../. Ciclos são proibidos.

O ecossistema é organizado por quão livremente se pode mexer no contrato:

  • Tier 0, o core (a linguagem mais a stdlib): padrões que não mudam (IEEE, TCP/IP, UTF-8, lista linkada). É add-only: acrescenta-se, nunca se edita o contrato. collections (List/Map/Set) é tier 0, um conjunto fechado (nunca haverá uma “quarta coleção fundamental”).
  • Tier 1, as libs oficiais: especificações que evoluem (HTTP teve 3 versões; regex troca de algoritmo). Tem cadência própria (semver/changelog), é opt-in e custa peso zero até o use. containers é tier 1, um roster que cresce (cada algoritmo dentro é frozen, mas a coletânea muda).
  • Tier 2, os frameworks (web, a UI): mais opinião, mais giro.
  • Tier 3, os terceiros: a promessa de compatibilidade é de outro.

A regra é que tiers só dependem pra baixo. O corte às vezes parte um conceito ao meio: UTF-8 é tier 0, as tabelas Unicode são tier 1; UTC/offset é tier 0, os nomes de fuso IANA são tier 1.

  • http: cliente e servidor, sobre a camada 2 do net (bytes + TLS). Tem superfície agnóstica de versão (/1.1, /2, /3 negociados por ALPN), processo-por-stream (um panic numa request crasha só ela) e cliente full (pool/redirect/cookies/gzip). O framework (router/middleware) é o web (tier 2).
use http
client := http.Client.new()
resp := client.get("https://api.exemplo/users") catch |e| { return e }
if resp.status.is_success() { process(resp.body.to_string() catch |e| { return e }) }
  • regex: multi-engine por construção. regex.compile usa RE2 (linear, sem ReDoS, o default), regex.pcre.compile usa backtracking (features completas), e regex.hyperscan faz multi-pattern mais streaming. Padrão literal compila em comptime.
const WORD := regex.compile("[a-z_][a-z0-9_]*").or_panic() // comptime: valida + embarca
  • containers: Deque, PriorityQueue, SortedMap/SortedSet (B-tree), Trie (ART), RingBuffer. Segue a convenção new() (ordem natural) / with_order(cmp) (custom):
use containers
pq := containers.PriorityQueue[Task].with_order(by_priority) // Task sem ordem natural → with_order

mk run / mk build / mk test / mk fmt / mk get / mk doc / mk lint / mk bench, e mais (capítulo 15). Binário único, alias de makoto.

Próximo: 13 · FFI e baixo nível