Pular para o conteúdo principal

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.

chat_room.hew
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.

service_cluster.hew
// 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.

batch.hew
// 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.

patterns.hew
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.

connection.hew
// 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.hew
// 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.

user.hew
// 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.

.hew → Frontend → Verificação de tipos → MIR → LLVM IR → Binário nativo