初识者的若干反馈

大家好,拜个晚晚年了!

我为了审阅[某个PR](https://github.com/typst-community/wasm-minimal-protocol/pull/65),初步尝试了下MoonBit,不过遇到了很多困难。大部分困难我不确定是否算MoonBit的缺陷,算的话也不确定应该报到哪个 GitHub 仓库,所以就直接在这里反馈了。

注:“新用户在一个帖子中仅能发布 2 个链接”,我就变通处理了。

$MOONBIT_INSTALL_VERSION及其格式不明

[安装 MoonBit CLI Tools](https://www.moonbitlang.com/download/#moonbit-cli-tools) 界面没有介绍如何安装特定版本(而不是最新版)。然而对于时刻在变化的新语言,固定版本通常很必要,特别是在CI上。

我查看[install/unix.sh](https://cli.moonbitlang.cn/install/unix.sh),发现支持环境变量$MOONBIT_INSTALL_VERSION,但没找到是变量应该是什么格式。经过一番调查试验,最终确定它指定的是moonc的版本(而非moon),而且格式需要加hash。例如以下这个版本,应该要指定MOONBIT_INSTALL_VERSION=0.8.2+8cca5f22a

$ moon version --all
moon 0.1.20260209 (b129ae2 2026-02-09) ~/.moon/bin/moon
moonc v0.8.2+8cca5f22a (2026-02-25) ~/.moon/bin/moonc
moonrun 0.1.20260209 (b129ae2 2026-02-09) ~/.moon/bin/moonrun
moon-pilot 0.0.1-df92511 (2026-02-25) ~/.moon/bin/moon-pilot

文档版本号可能过时

[MoonBit Documentation](https://docs.moonbitlang.com/en/latest/index.html)选择 latest 时,<title>是 MoonBit v0.7.1 documentation,但根据上一节我操作的结果,目前 latest 好像是 0.8.2。这是文档落后呢,还是仅仅<title>标错了?

moon fmt添加的///|缺少解释

对于没有注释的函数,运行moon fmt后会添加///|,如下。

+ ///|
  pub fn hi() -> Int {
    0
  }

我不清楚它和///有什么区别。我在 [MoonBit Language — MoonBit v0.7.1 documentation](https://docs.moonbitlang.com/en/latest/language/index.html) 没有找到任何关于///|的解释。它第一次出现是在介绍 async 时,难道///|和 async 有关?

我询问通用LLM,回复说这是避免 markdown 列表被错误合并成一行,但我也没在文档中找到 line wrap 相关信息,而且多行都用///|的话,会被moon fmt修改:

  ///| - a
- ///| - b
+ ///|
+ /// - b
  pub fn hi() -> Int {
    0
  }

至今我仍不清楚///|的意义。

moon fmt转换出的moon.pkg不稳定

如果用moon.pkg.json,运行moon fmt会转换为moon.pkg(这让我比较惊讶,但可能设计如此,也还好)。

问题在于,第一次运行时moon.pkg最后没有空行,第二次运行会给加上,正常应该一步到位。

BytesFixedArray[Byte]等的关系不明

我在 [Bitstring Pattern — Fundamentals — MoonBit documentation](https://docs.moonbitlang.com/en/latest/language/fundamentals.html#bitstring-pattern) 看到 MoonBit 有多种方式表示字节序列:

BytesView, Bytes, Array[Byte], FixedArray[Byte], ReadOnlyArray[Byte], and ArrayView[Byte]

其它几个还相对好理解,但BytesFixedArray[Byte]是什么关系呢?通用LLM说前者是后者的别名,但我实测好像二者不能互换,而且内存结构也不同(前者开头有八个字节的零,后者开头有四个字节0xFF和另外四个我不清楚意义的字节)。

此外,如果我定义一个函数,需要读取一串长度任意的字节而无需修改,那么函数的参数应该用哪种?这在文档里似乎没有解释。

我在论坛上看到下面这段解释,但还是很模糊……

[DeepWiki 的分析](https://deepwiki.com/search/bytesfixedarraybyte_90421b28-fe57-4814-a7c4-27b160960db2?mode=fast)也有一定帮助,但仍未解决问题。

blit 函数系列不全

处理字节时,经常需要整块memcpy。根据我的调查,MoonBit把这类函数叫blit_to/blit_from_*

然而MoonBit有多种方式表示字节序列,并不是每两种方式之间都能blit。我在 [core – mooncakes](https://mooncakes.io/docs/moonbitlang/core/) 只查到了下面几种:

Array::blit_to(..., dst : Array[A], ...)
ArrayView::blit_to(..., dst : Array[A], ...)
FixedArray::blit_from_bytes(..., src : Bytes, ...)
FixedArray::blit_from_bytesview(..., src : BytesView)
FixedArray::blit_from_string(..., str : String, ...)

FFI缺少字节

在 [Foreign Function Interface (FFI)](https://docs.moonbitlang.com/en/latest/language/ffi.html#types) 中,Wasm后端并无任何字节、数组相关的类型,那应该怎样向host传递字节呢?

我们现在的做法是在moon.pkg设置"export-memory-name": "memory",然后通过以下函数把 Bytes 的地址转成Int传出去。

#borrow(bs)
extern "wasm" fn data_ptr(bs : Bytes) -> Int =
  #|(func (param i32) (result i32)
  #|  local.get 0
  #|  i32.const 8
  #|  i32.add)
// 以上加八是试验出来的,我没在文档中找到能确认的信息。

Types not mentioned above do not have a stable ABI, so your code should not depend on their representations.

以上 FFI 文档说Bytes的 API 不稳定,那这种做法恐怕过几个版本就可能失效了?有没有更可靠的办法呢?

E4042 解释不实

错误代码 [E4042 — MoonBit documentation](https://docs.moonbitlang.com/en/latest/language/error_codes/E4042.html) 说:

For example, you cannot use FixedArray[T] and String in FFI definition on WASM linear backend.

但我实测FixedArray[Byte]可以,而FixedArray[Int]确实不行。

discuss 和 taolun 论坛的关系不明

我查到有 https://discuss.moonbitlang.com/https://taolun.moonbitlang.com/ 两个论坛。前者主要英文,后者主要中文,而且两论坛似乎相互均未提及。这两个论坛有取代继承关系吗?若是共同运行,建议置顶帖子介绍一下。

感觉反馈。关于你的问题:


其它几个还相对好理解,但BytesFixedArray[Byte] 是什么关系呢?

BytesFixedArray[Byte] 在内存结构上是一样的。你看到的不一致行为实际上是 BytesFixedArray[Byte] 的对象头(Object header)。对象头的存在也能够解释为什么你在后面将 Bytes 传出 WASM 的时候需要在地址上 + 8,因为这是对象头的大小。


以上 FFI 文档说Bytes 的 API 不稳定,那这种做法恐怕过几个版本就可能失效了?有没有更可靠的办法呢?

你可以通过 heap-start-address 来指定 MoonBit 堆的最低地址,然后在低于该地址的地方把 Bytes 写入进去。比如说你可以定义一个这样的 FFI :

extern "wasm" fn write_byte(address : Int, byte : Byte) = ...

然后通过逐个遍历 Bytes 中的字节的方式将内容写入到固定的地址。

1 个赞

感谢你这么详细的反馈!

  1. 关于版本的问题

    我们还未达到1.0版本,目前暂时只提供 lastest stable / nightly channel 的下载渠道。

  2. moon fmt转换出的moon.pkg不稳定

    这是 moon fmt 的缺陷,我们正在改进

  3. 关于文档

    标题、缺少///|和 E4042 都是文档更新滞后和遗漏了,我们已经记录了issue并逐个改进。

  4. taolun 和 discuss 的关系

    taolun是中文论坛,discuss是英文论坛。没有取代和继承关系。

1 个赞