Goose 語言:無 heap、比 C++ 快?翻譯、HN 反應、懶人包一次看

Goose 是無 heap 的 memory-safe 系統語言,自稱比 C++ 快、記憶體更少。全文翻譯、HN 214 則留言整理、互動懶人包一次收。

原文:The Goose Programming Language,作者 Wouter van Oortmerssen(Lobster、Amiga E 作者)。

效能數字為專案自報 benchmark,未經第三方驗證。以下為正體中文翻譯整理,程式碼保持原文。

一句話說完

Goose 是 memory-safe 的系統語言,沒有 heap allocator、GC、lifetime 標註。所有動態值住在編譯器管理的 data stack 上,增長只推 pointer,scope 結束即釋放。專案自稱 16 項 benchmark 跑贏慣用寫法的 C++ 3.3 倍、手動優化 C++ 1.16 倍、最佳 safe Rust 1.12 倍,記憶體更少。

為什麼用 Goose

  • 比 C++ 和 safe Rust 快,同時 memory safe:增益來自資料排列與記憶體模型。
  • 沒有 allocator、GC、reference counting、destructor:記憶體是編譯器靜態配置的幾個 data stack,釋放百萬元素結構只需一次 store。
  • 增長不讓 reference 失效:指向 growing array 內部的 reference 一直有效。C++ 得靠 reserve,safe Rust 得用 u32 索引,Goose 直接保留 typed reference。
  • 零標註的 memory safe:沒有 lifetime 語法、沒有 aliasing 規則、沒有 unsafe,編譯器推導每個 reference 的 root。
  • 巢狀資料保持 inline:字串、字串陣列、變長欄位 record 都是連續區塊。C++ 要 160 bytes 加一次配置的 record,Goose 只要 29 bytes、零配置。
  • Enum 只花該 variant 的成本:variable-mode ADT 讓每個值只佔自己 variant 的大小。
  • 比指標更窄的連結:relative reference 存成 1、2、4-byte offset,結構 position independent,資料結構本身就是檔案格式。
  • 保證在原地建構:值直接在最終目的地建好,items.push(parse(line)) 把結果直寫進陣列。
  • 跨多層呼叫回傳:return err from load 可從任意上層 frame 回傳,靜態檢查,不需 unwinder。
  • 互不共享的執行緒:worker 各有記憶體,flat 值經 typed queue 以 memcpy 傳遞,沒有 data race、lock、atomic。
  • 零開銷泛型與高階函式:untyped 參數即泛型,xs.filter() { it > 0 } 編出來就是迴圈。
  • Plain C in,plain C out:編成單一 C 檔,經 extern fn 直接呼叫 C,內附 TinyCC 可即時執行。

記憶體模型:stack,離開 scope 即 free

程式有 native call stack、靜態資料和 N 個 data stack,N 由編譯器決定。data stack 是帶 bump pointer 的大段位址空間保留,沒有其他記憶體。每個 stack 同時最多一個可變大小的值存活且永遠在頂端,所以增長永不搬移、永不檢查容量。


for round in 3 {
    var scratch: u8[>..] = [];
    for i in 100000 { scratch.push((i % 256) as! u8); }
    print("round ", round, ": ", scratch.len, " bytes");
}

什麼都不搬,reference 在增長後仍有效


struct Item { id: i32, weight: f32 }

var items: Item[>..] = [];
let first .= items.push(Item { 1, 0.5 });
for i: i32 in 2..1000001 { items.push(Item { i, 0.0 }); }
first.weight = 99.5;

push 回傳指向新元素的 reference。vector 或 Vec 可能重配置,給不出這種保證。

陣列一族

寫法 意義
T[k] 固定大小,編譯期已知
T[]、T[varint] 建構時定大小,之後凍結
T[..k]、T[..] 容量 inline,在容量內增減
T[>..] grow-only 主力,內部 reference 保持有效
T[>..<] grow-shrink:stack、queue、heap 用

字串就是 u8 陣列:u8[>..] 是 builder,u8[] 是完成品,u8[..16] 是 struct 內的小字串,u8[:] 是 view。

代價

  • 得想資料住哪:擁有者與 scope 長度對不上就沒效。
  • 遞迴函式不可在遞迴呼叫兩側保留可增長資料。
  • 變長元素陣列可走訪、不可索引。
  • 沒有逃逸閉包、沒有 function pointer、只做 whole-program 編譯。
  • 歸還給 pool 卻仍被具名的 slot,讀到下一個主人的資料:邏輯 bug,不是記憶體損毀。

現狀與授權

約三萬行 C++ 的 whole-program 編譯器、規格書、標準函式庫、31 支範例,CI 跑 Windows、macOS、Linux。Apache 2.0 授權。刻意暫不做:resizable 值的 move、單 struct 多 resizable、labeled break、namespace 隱私。

作者與 AI

專案幾乎全由 AI 產出,源自人類的語言設計。作者多年前設計好 Goose 並動手實作,因經營遊戲新創(基於他的另一個語言 Lobster)沒時間收尾。Fable 出現後,他讓 AI 照 Lobster 編譯器的風格結構接手,來回討論定版。編譯器用 C++ 寫:輸出本來就是 C,同生態系簡化部署,也方便整合 libtcc 等 C 函式庫。

HN 網友反應(320 分,214 則留言)

主題 風向 重點
記憶體模型設計 叫好 讚 stable reference、relative link、位元組即檔案格式
文件像 AI 寫 開罵 要求作者自己重寫,只講做法不講動機
Benchmark 對照組 存疑 Rust 對照組用 Vec::new() 而非 with_capacity()
Carmack 是否背書 爭議 被指標題誤導,作者稱對方有讀 repo
缺點只放教學 §18 觀感不佳 像把缺點藏起來

作者全程 AMA:執行緒學 Dart Isolate,各自獨立、以 memcpy 傳 flat 值;AoS 轉 SoA 目前不做;Lobster 走好用路線,Goose 走極速路線。

懶人包

互動版整理在一頁內:

手機版可直接開:Goose 語言懶人包

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *