Objetivos do projeto Rust: tipos imóveis e destrutores garantidos

Os mantenedores do Rust estão explorando novos traits no nível de tipo como `!Move` e `!Forget` para dar suporte a tipos imóveis e destrutores garantidos, visando resolver problemas antigos de async, estruturas autorreferenciais e vazamentos de memória. Comentadores destacam como isso poderia permitir concorrência estruturada mais segura (por exemplo, tarefas async com escopo e limpeza garantida) e APIs mais expressivas, como recursos lineares “must-use”, ao mesmo tempo em que apontam desafios sérios de compatibilidade retroativa com traits existentes, coleções e o modelo `Pin`. Há um entusiasmo amplo pelas capacidades que esses recursos poderiam desbloquear, temperado pelo reconhecimento de que o design é complexo, ainda não está finalizado e pode exigir trocas com propostas alternativas como a “ergonomia de pin”.

Ideia de alto nível

  • A proposta introduz traits como !Move, !Forget e, eventualmente, !Destruct para:
    • Tornar a imobilidade uma propriedade do tipo em vez da localização (substituindo grande parte de Pin).
    • Garantir que os destrutores sejam executados (ou que seja impossível vazar) para certos tipos.
    • Lançar as bases para tipos lineares / must-move.

Rust assíncrono e concorrência estruturada

  • A motivação principal é melhorar o async/concorrência estruturada:
    • Hoje, tarefas async podem ser canceladas arbitrariamente, então os destrutores talvez nunca sejam executados.
    • Isso bloqueia “tarefas com escopo” totalmente seguras, análogas a threads com escopo.
    • Com !Forget, os handles de tarefas poderiam ter a garantia de serem descartados, tornando o async com escopo seguro e ergonômico.
  • Também ajuda em:
    • Funções async recursivas (sem truques com Box::pin).
    • Funções async que fazem borrowing de escopos externos em vez de clonar.

Tipos imóveis vs Pin

  • Pin é amplamente visto como confuso e como uma “gambiarra”:
    • Ele fixa localizações e tem semântica de Unpin e regras de projeção complicadas.
    • Código async de baixo nível que usa Pin é pouco ergonômico e depende de unsafe.
  • !Move tornaria a imobilidade intrínseca ao tipo:
    • Permite auto-referências seguras e padrões complexos que Pin não consegue suportar totalmente.
  • Existe um caminho alternativo de “locais fixados”/ergonomia de pin; esta proposta é explicitamente uma alternativa e pretende descontinuar Pin no longo prazo.

Controle de vazamentos e !Forget

  • !Forget visa garantir que um destrutor seja executado antes que o armazenamento seja reutilizado.
  • Vazamentos via mem::forget ou ciclos de referências:
    • A proposta é restringi-los exigindo T: Forget para Rc/Arc e tipos semelhantes.
    • Loops infinitos ou enviar valores para outras threads não são considerados “esquecer”, já que o escopo nunca termina.

Tipos lineares / must-move (!Destruct)

  • Forçariam caminhos explícitos de destruição:
    • APIs como transações poderiam exigir estaticamente exatamente um de commit/rollback.
    • Padrões de “rollback silencioso” ou de panic em Drop poderiam ser evitados.
  • A destruição normalmente exigiria desestruturação ou funções consumidoras dedicadas no módulo definidor.

Compatibilidade retroativa e impactos em std

  • A compatibilidade retroativa é um grande risco:
    • Genéricos existentes assumem implicitamente que tudo é móvel e descartável.
    • Traits como Iterator::Item e Deref::Target tornam-se problemáticos quando alguns tipos são !Move.
    • Coleções como Vec<T> movem elementos por natureza; provavelmente não podem suportar tipos !Move, ou apenas via APIs restritas.
  • Edições ajudam, mas não resolvem tudo; um design cuidadoso de padrões e limites (T: Move vs T: ?Move) é crucial e nada trivial.

Relação com efeitos algébricos e C++

  • Alguns veem esses traits como semelhantes a efeitos: drop<T>, move<T>, forget<T> se comportam como efeitos implícitos associados às funções.
  • Outros argumentam que isso é principalmente sobre propriedades de tipos e futuros sistemas de efeitos.
  • Comparações com C++:
    • Rust não está adicionando construtores implícitos de move/copy.
    • Imobilidade e destrutores garantidos facilitam a interoperabilidade com C++ e certos padrões (auto-referências, grafos de objetos complexos), mas com semânticas explícitas e mais estritas.

Status e incerteza

  • Isso é um objetivo de projeto, não uma mudança de linguagem aceita.
  • Compete com o objetivo de ergonomia de pin; muitos esperam que tipos imóveis vençam se apenas um sobreviver, mas:
    • A mudança é abrangente e complexa.
    • Semântica, compatibilidade retroativa e integração com std continuam em aberto e ainda podem inviabilizar ou remodelar significativamente o design.