Recursos da linguagem
Hew foi feita para serviços resilientes e de alta performance. Esta página separa os recursos atuais da v0.9.3 da direção mais ampla da linguagem.
Modelo de actors
O exemplo da sala de conversa mantém as contagens de membros e mensagens em um actor. Apenas seus métodos receive alteram esse estado, e cada chamada retorna um resultado tipado.
actor ChatRoom {
var members: i64 = 0;
var message_count: i64 = 0;
receive fn join(user_id: i64) -> i64 {
members = members + 1;
members
}
receive fn post_message(content: string) -> i64 {
message_count = message_count + 1;
message_count
}
}Modelo de memória
Valores owned comuns são liberados recursivamente. Recursos afins mantêm uma única responsabilidade de limpeza: #[resource] fornece limpeza segura ao fim do escopo, enquanto #[linear] exige uma ação de consumo explícita em cada caminho.
Árvores de supervisão
O exemplo declara três filhos sob um supervisor one_for_one, com um orçamento de cinco reinícios por minuto e políticas permanentes ou transitórias para cada filho.
// A supervisor declares its restart strategy, its restart budget
// (`intensity: N within <window>`), and its children. Each child names the
// actor type and its init args; a per-child `restart:` policy decides whether
// a crash is restarted (permanent), restarted only on failure (transient),
// or never (temporary).
actor DatabasePool {
let pool_size: i64;
receive fn query() -> i64 {
pool_size
}
}
actor CacheLayer {
let capacity: i64;
receive fn get() -> i64 {
capacity
}
}
actor ApiHandler {
let port: i64;
receive fn handle() {}
}
supervisor ServiceCluster {
strategy: one_for_one;
intensity: 5 within 60s;
child db: DatabasePool { pool_size: 16 } restart: permanent;
child cache: CacheLayer { capacity: 1024 } restart: permanent;
child api: ApiHandler { port: 8080 } restart: transient;
}Concorrência estruturada
O lote inicia três tarefas independentes com fork e reúne seus resultados com await. O scope espera o trabalho filho antes de o lote retornar.
// Structured concurrency: a `scope` block opens a region that joins all
// child work before it returns. Start independent jobs with `fork`, then
// collect each result with `await`.
fn process_batch(a: i64, b: i64, c: i64) -> i64 {
var total = 0;
scope {
let ra = fork run_job(a);
let rb = fork run_job(b);
let rc = fork run_job(c);
let first = await ra;
let second = await rb;
let third = await rc;
total = first + second + third;
};
total
}
fn run_job(job: i64) -> i64 {
job * 2
}Padrões de concorrência
O exemplo põe duas chamadas de actor em disputa com select e um timeout after; depois usa await fork (...) para iniciar duas chamadas independentes e coletar ambas as respostas.
actor Fetcher {
receive fn fetch(key: i64) -> i64 {
key
}
}
actor Store {
receive fn get_users() -> i64 {
0
}
receive fn get_posts() -> i64 {
0
}
}
// Wait for the first responder, with a timeout fallback. Each arm races an
// actor ask; the first to reply wins and the rest are cancelled.
fn race_fetch(primary: Fetcher, fallback: Fetcher, key: i64) -> i64 {
select {
resp from primary.fetch(key) => resp handle e { -1 },
resp from fallback.fetch(key) => resp handle e { -1 },
after 500ms => -1,
}
}
// Run independent calls concurrently and collect every result.
fn parallel_fetch(db: Store) -> (i64, i64) {
let (users, posts) = await fork (db.get_users(), db.get_posts());
(users.expect("store stopped"), posts.expect("store stopped"))
}
fn main() {
let primary = spawn Fetcher;
let fallback = spawn Fetcher;
println(race_fetch(primary, fallback, 42));
let db = spawn Store;
let (users, posts) = parallel_fetch(db);
println(f"{users} {posts}");
}Máquinas de estado
A máquina de conexão declara eventos, estados, transições com guards e comportamento padrão em uma tabela. step aplica apenas uma transição declarada para o estado e o evento atuais.
// A connection lifecycle as a compiler-checked state machine.
// Events are declared up front; transitions route with `=>` and a body
// that constructs the target state. Every (state, event) pair must be
// covered — `default { state }` makes the rest a no-op stay.
machine Connection {
events {
Connect { host: string; }
Disconnect;
HeartbeatTimeout;
}
state Idle;
state Connecting { host: string; }
state Connected { host: string; }
state Disconnected { retries: i64; }
on Connect { host }: Idle => Connecting { host: host }
on Connect { host }: Disconnected => Connecting when state.retries < 5 { host: host }
on Disconnect: Connected => Disconnected { retries: 0 }
on HeartbeatTimeout: Connected => Disconnected { retries: 0 }
default { state }
}
fn main() {
var conn = Connection.Idle;
_ = conn.step(Connection.Event.Connect { host: "10.0.0.1" });
println(conn.state_name()); // Connecting
}Chamadas de actor com falhas tipadas
Este exemplo com um actor local mostra a fronteira de chamada com falhas tipadas: cada solicitação retorna um resultado que o chamador trata ou propaga.
// Actor calls make failure part of the method surface. Every call yields a
// Result, so callers handle a stopped actor or expired request deadline alongside
// the successful value. The error branch below has the typed
// ActorError<Never, Never> carried by this method.
actor Worker {
let id: i64;
receive fn process(task: i64) -> i64 {
task + id
}
}
fn dispatch(task: i64) -> i64 fails ActorError<Never, Never> {
let w = spawn Worker { id: 1 };
// `?` on the binding unwraps Ok and propagates a typed ActorError<Never, Never>
// on the failure branch.
let answer = (w.process(task))?;
answer
}
fn main() {
match dispatch(7) {
.Ok(v) => println(f"result = {v}"),
.Err(_) => println("dispatch failed"),
}
}Contratos Wire
O schema de perfil atribui uma tag numérica estável a cada campo. O campo opcional verified pode ser omitido por pares antigos ou novos, enquanto o verificador de compatibilidade acompanha mudanças nas tags.
// Wire types carry explicit field tags (@1, @2, ...) for forward- and
// backward-compatible binary encoding. Optional fields may be omitted by
// older or newer peers without breaking the schema.
#[wire]
type UserProfile {
name: string @1;
email: string @2;
age: i32 @3;
verified: Option<bool> @4 optional;
}Sistema de tipos
O sistema de tipos de Hew é construído em torno de isolamento por actors e limites verificados por capacidades. O compilador aplica verificações Send/Frozen, exaustividade e isolamento de actors em tempo de compilação.
Generics com monomorfização
O compilador especializa tipos e funções genéricos para cada tipo concreto usado pelo programa.
Traits de capacidade Send + Frozen
Send marca valores que podem atravessar o limite de um actor. Frozen marca valores profundamente imutáveis que podem ser compartilhados com segurança.
Inferência de tipos bidirecional
Tipos esperados fluem para lambdas e chamadas genéricas, reduzindo anotações e mantendo o tipo inferido visível ao verificador.
Pattern matching com exaustividade
Expressões match são verificadas quanto à completude em tempo de compilação. O compilador garante que todos os casos possíveis sejam tratados.
C FFI com blocos extern
Blocos extern descrevem símbolos C e suas assinaturas Hew. FFI é unsafe por padrão; ABI, ponteiros e vidas úteis continuam sob responsabilidade de quem chama.
Option<T> e Result<T, E>
Ausência e falhas recuperáveis são valores explícitos, tratados com pattern matching ou propagados com ?.
Trait Iterator com adapters
Adapters como map, filter e fold compõem transformações lazy sobre sequências.
Compilação
Hew já compila para código de máquina nativo. O comando hew build aciona um frontend em Rust e um backend Rust LLVM, com cada etapa preservando mais garantias do verificador.