生态:为什么"没有 Rust crates"没抓住要点
对 SuperJ 的第三个标准反对 — 在"没有线程"和"没有内存安全"之后 — 是"没有生态:Rust 有 crates,C++ 有库,SuperJ 只有一个 SDK"。这个框定假设生态是一个源码级的东西,而在那一层它是对的:你无法把一个 Rust crate 用 cargo add 加进 SuperJ 项目并拿到它的 derive 宏、它的 async 脱糖、它的基于 trait 的分派。
但 SuperJ 是一门 LLVM 语言,而这改变了算法。
可链接的生态就是编译后的生态
SuperJ 的 native 关键字链接 C ABI 符号 — 这就是 runtime/*.c 今天的工作方式。其他每一门 LLVM 语言(Rust、C、C++、Zig、Swift)都能导出 extern "C" 函数,它们不过就是带 C 调用约定的 LLVM IR 函数。SuperJ 链接它们的方式与链接 arena.c 相同。你免费得到每个 LLVM 语言生态中编译后的、ABI 稳定的部分:
- 加密 —
ring、BoringSSL、libsodium、libsecp256k1(已被 SuperJ 自己的runtime/secp256k1.c链接)。 - 压缩 — zstd、lz4、zlib、brotli。
- 数值内核 — BLAS/LAPACK、simde、OpenMP 运行时。
- 解析器 — 任何解析器库的编译核心(宏与 derive 跨不过语言边界 — 它们跨不过任何语言边界,连到 C 也不行)。
- 系统绑定 — 任何带 C 头文件的东西都已是可链接的。
这是生态中真正对链接有意义的部分。你拿不到的部分 — serde 的 derive 宏、tokio 的 async 脱糖、axum 的基于 trait 的路由 — 是人体工学层,它生活在源码语言层面,任何方向都跨不过语言边界(你从 C 也用不了 serde)。那一层是便利,不是能力:一个 Rust #[derive(Serialize)] 产出一个函数,它调用的是同一个 serde 核心,而那个核心你可以从 SuperJ 链接并通过一个薄 native 包装器调用。
关键的不对称
Rust 能链接 C,但 Rust 不能从非 Rust 宿主链接 Rust crate — 宏/derive 层是一个需要 Rust 编译器的编译期展开。所以 Rust 生态在人体工学层是单语言的。SuperJ 在链接层是多语言的:任何编译到带 C ABI 的 LLVM IR 的东西,只差一个 native 声明。"生态优势"一旦你停止把源码人体工学层与可链接能力层混为一谈,就反转了。
SuperJ 自己的 SDK 已经覆盖了什么
SuperJ SDK 不是一个象征性的姿态 — 它覆盖了人体工学层本会显得重要的那些场景:
- 集合 — 原始类型特化(
IntArrayList、Int2IntMap、Obj2ObjMap<K,V>、IntSet、…),避免了泛型 Java 集合会施加的装箱。 - JSON — 一个手写的增量式解析器,无需 derive 宏。
- HTTP/1.1 — 一个带 TLS 1.3 的增量式服务器。
- SEDA — 本手册围绕其构建的事件驱动框架。
- 加密 — SHA256(ARM NEON)、用于区块链的 Secp256k1。
- Math、Integer、Long、Short — 完整的
java.lang.Math等价物。
你会伸手去拿 Rust crate 的场景,大多是编译核心本就可链接的场景:你要 zstd,就链接 zstd。你要 BLAS,就链接 BLAS。你要某个解析器,就链接它的编译核心。SuperJ SDK 覆盖 Java 人体工学的空缺(集合、JSON、HTTP);LLVM 链接层覆盖系统的空缺(其余一切)。
诚实的剩余
你真正拿不到的是:一个需要其源码语言的编译期特性才能运作的库 — 一个整个 API 面由过程宏生成、没有 extern "C" 回退的 Rust crate。这些存在但很罕见;大多数真实能力 — 加密、压缩、数值内核、解析器 — 在人体工学糖衣之下都有一个 C-ABI 核心。那层糖衣是你在 SuperJ 中自己写的,而因为 SuperJ 是 Java 形状的,那层糖衣很廉价:一个 native 声明加一个薄包装方法。这就是作为一个小生态的代价,而 LLVM 链接层让它保持小而非残废。