Skip to content

spec: 0056 Deterministic Resource Cleanup — defer によるスコープ脱出時のファイナライザ - #21

Merged
Allianaab2m merged 1 commit into
mainfrom
spec/0056-deterministic-resource-cleanup
Jul 30, 2026
Merged

spec: 0056 Deterministic Resource Cleanup — defer によるスコープ脱出時のファイナライザ#21
Allianaab2m merged 1 commit into
mainfrom
spec/0056-deterministic-resource-cleanup

Conversation

@Allianaab2m

Copy link
Copy Markdown
Member

Summary

ホスト資源(fd・ソケット)をスコープ脱出の全経路で確定的に解放する言語機構を定める SPEC 0056 を追加する。ブロック項 defer <expr> を導入し、その action が

  1. 正常完了
  2. エラーチャネルによる脱出(throw / ? / 伝播)
  3. 自己末尾呼び出しによる脱出(0045)

のいずれにおいてもちょうど 1 回実行されることを保証する(D4)。

経路 3 が必須なのは、Emela がループ構文を持たずすべての反復が自己末尾呼び出しだからである。これを欠くと defer はループ本体で一度も実行されない。

Motivation

現在、解放は明示的な close 呼び出しだけが担っており、エラー経路で確実に漏れる。std.fsread_file が実例で、read_all_loop(f)? が throw すると raw_close(f.id) に到達しない。同型の漏れが write_file と 0046 の HttpServer.respond / accept_one にもある。とりわけ accept ループは 0045 により有界メモリで無限に回るため、1 反復 1 fd の漏れは確実に枯渇へ至る。

0011 の try / catch は「必ず実行される節」を持たないためこの問題を解けず、? を使う限り脱出点はソース上に現れない。

主な設計判断

bracket(acquire, release, body) を stdlib 関数として書く案は採らない。 body をクロージャにすると 0045 T4 によりその中の再帰呼び出しが自己末尾呼び出しにならず、サーバの accept ループを bracket の中に書けない。加えて throws 多相が言語に存在せず、クロージャはヒープ確保を伴う。deferuse x = e 形を包含するので、糖衣は後から足せる。

0024 / 0048 A2 の finalizer 禁止とは衝突しない。 禁止対象は RC 回収(refcount が 0 になる瞬間)の観測である。defer はレキシカルで参照カウントを見ず(D12)、値の生存に依存しない。RC 命令を無視するバックエンド(0048 A9)でも意味論が同一であることがその実証になる — デストラクタならそこで意味が変わる。

所有権・借用・線形性は導入しない(D11、0000 の非目標を維持)。安全性は「close は冪等」(0050 P7 / 0055 P2)という既存方針に依拠する。

キャンセルは第 3 のチャネルを作らない。 実際に途中で打ち切られる事象(接続断 SocketError::ConnectionClosedHttpError::Timeout、ホストの失敗)はすべて既に throws チャネルに乗っている。協調キャンセルを採る限り D4 の経路 2 がそのまま覆う。非協調なプリエンプションは trap 相当で、D10 により action は走らない。

その他

  • panic は action を実行しない(D10)。ホスト資源はインスタンス破棄時にホストが回収する。参照実装では両バックエンドが追加実装ゼロでこう振る舞う。
  • action は throws を持てず、型は UnitNever(D8)。Socket.close / Fs.close は既に infallible なので実用上の制約はほぼない。
  • README の Current Drafts に 0056 を追記し、漏れていた 0053・0054 も補った

実装は emela 側で完了済み(3 経路 × wasm/js-node の両方で検証、live_bytes == 0、fd リーク回帰テストつき)。

ホスト資源(fd・ソケット)をスコープ脱出の全経路で確定的に解放する言語機構を
定める。ブロック項 `defer <expr>` を導入し、正常完了・エラーチャネル・自己末尾
呼び出し(0045)のいずれでも action がちょうど 1 回走ることを保証する。

0024/0048 A2 の finalizer 禁止とは衝突しない。禁止対象は RC 回収の観測であり、
`defer` はレキシカルで参照カウントを見ない(D12)。RC を持たないバックエンドで
意味論が変わらないことがその実証になる。

キャンセルは第 3 のチャネルを作らず、協調キャンセルとしてエラーチャネルに載せる
方針を Open Questions に記す。接続断・タイムアウトは既に throws チャネル上にある。

README の Current Drafts に 0056 を追記し、漏れていた 0053・0054 も補う。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant