跳到主要内容

weekly 2024-08-05

· 阅读需 6 分钟

MoonBit更新

  • JSON字面量支持array spread。
let xs: Array[@json.JsonValue] = [1, 2, 3, 4]
let _: @json.JsonValue = [1, ..xs]
  • 增加了类型别名的支持,主要是为了渐进式代码重构和迁移,而不是某种给类型简短名字的机制。例如,假设需要把 @stack.Stack 重命名为 @stack.T,一次性完成迁移需要修改大量使用 @stack.Stack 的地方,对于大项目很容易产生 conflict,如果有第三方包使用了 @stack.Stack,则会直接造成 breaking change。使用 type alias,则可以在重命名后留下一个 @stack.Stack 的 alias,使现有代码不会失效:
/// @alert deprecated "Use `T` instead"
pub typealias Stack[X] = T[X]

接下来,可以渐进式地逐步迁移对 @stack.Stack 的使用、给第三方用户时间去适配新的名字。直到迁移全部完成,再移除 type alias 即可。除了类型重命名,typealias 还可用于在包之间迁移类型定义等等

  • 增加了给 trait object 定义新的方法的支持:
trait Logger {
write_string(Self, String) -> Unit
}

trait CanLog {
output(Self, Logger) -> Unit
}

// 给 trait object 类型 `Logger` 定义新的方法 `write_object`
fn write_object[Obj : CanLog](self : Logger, obj : Obj) -> Unit {
obj.output(self)
}

impl[K : CanLog, V : CanLog] CanLog for Map[K, V] with output(self, logger) {
logger.write_string("Map::of([")
self.each(fn (k, v) {
// 使用 `Logger::write_object` 方法来简化
logger
..write_string("(")
..write_object(k)
..write_string(", ")
..write_object(v)
.write_string(")")
})
logger.write_string("])")
}
  • 【breaking change】在可能返回错误的返回值类型 T!E 中,错误类型 E 只能是使用 type! 关键字声明具体的错误类型,目前支持以下两种声明方式:
type! E1 Int   // error type E1 has one constructor E1 with an Integer payload
type! E2 // error type E2 has one constructor E2 with no payload

函数声明中可以使用上述具体的错误类型来进行标注,并通过使用 raise 来返回具体的错误,比如

fn f1() -> Unit!E1 { raise E1(-1) }
fn f2() -> Unit!E2 { raise E2 }
  • 添加了内置的 Error 类型作为默认的错误类型,可以在函数声明中使用以下几种等价的声明方式来表明函数会返回 Error 类型的错误,比如:
fn f1!() -> Unit { .. }
fn f2() -> Unit! { .. }
fn f3() -> Unit!Error { .. }

对于匿名函数和矩阵函数,可以通过使用 fn! 来标注该函数可能返回 Error 类型的错误,比如

fn apply(f: (Int) -> Int!, x: Int) -> Int! { f!(x) }

fn main {
try apply!(fn! { x => .. }) { _ => println("err") } // matrix function
try apply!(fn! (x) => { .. }) { _ => println("err") } // anonymous function
}

通过 raisef!(x) 这种形式返回的具体的错误类型可以向上 cast 到 Error 类型,比如

type! E1 Int
type! E2
fn g1(f1: () -> Unit!E1) -> Unit!Error {
f1!() // error of type E1 is casted to Error
raise E2 // error of type E2 is casted to Error
}

错误类型可以被模式匹配,当被匹配的类型是 Error 的时候,模式匹配的完备性检查会要求添加使用 pattern _ 进行匹配的分支,而当其是某个具体的错误类型的时候则不需要,比如

type! E1 Int
fn f1() -> Unit!E1 { .. }
fn f2() -> Unit!Error { .. }
fn main {
try f1!() { E1(errno) => println(errno) } // this error handling is complete
try f2!() {
E1(errno) => println(errno)
_ => println("unknown error")
}
}

此外,在 try 表达式中,如果使用了不同种类的错误类型,那么整个 try 表达式可以返回的错误类型会按照 Error 类型进行处理,比如

type! E1 Int
type! E2
fn f1() -> Unit!E1 { .. }
fn f2() -> Unit!E2 { .. }
fn main {
try {
f1!()
f2!()
} catch {
E1(errno) => println(errno)
E2 => println("E2")
_ => println("unknown error") // currently this is needed to ensure the completeness
}
}

我们会在后续的版本中对此进行改进,以使得完备性检查可能更加精确

  • 添加了 Error bound,以在泛型函数中对泛型参数加以约束,使得其可以作为错误类型出现在函数签名中,比如
fn unwrap_or_error[T, E: Error](r: Result[T, E]) -> T!E {
match r {
Ok(v) => v
Err(e) => raise e
}
}

标准库更新

  • Bigint 变为builtin类型

构建系统更新

  • 支持 debug 单个.mbt文件

  • moon test支持包级别的并行测试

  • moon.mod.json增加root-dir字段,用于指定模块的源码目录,只支持指定单层文件夹,不支持指定多层文件夹。moon new会默认指定root-dirsrc,exec 和 lib 模式的默认目录结构变为:

exec 
├── LICENSE
├── README.md
├── moon.mod.json
└── src
├── lib
│ ├── hello.mbt
│ ├── hello_test.mbt
│ └── moon.pkg.json
└── main
├── main.mbt
└── moon.pkg.json

lib
├── LICENSE
├── README.md
├── moon.mod.json
└── src
├── lib
│ ├── hello.mbt
│ ├── hello_test.mbt
│ └── moon.pkg.json
├── moon.pkg.json
└── top.mbt

工具链更新

  • MoonBit AI 支持生成文档

ai file

weekly 2024-07-29

· 阅读需 4 分钟

MoonBit 更新

  • f(x)!! 修改为 f?(x),用于捕获函数调用中可能出现的错误,并返回 Result 类型
fn div(x: Int, y: Int) -> Int!String {
if y == 0 {
raise "division by zero"
}
x / y
}

fn main {
let a = div?(10, 2)
println(a) // Ok(5)
}
  • 新增 json 字面量支持。数字、字符串、数组和字典字面量为 json 类型提供了重载,可以在知道需要一个 json 类型时用于构建/匹配 json:
fn json_process(x : @json.JsonValue) -> Double {
match x {
{
"outer": {
"middle": {
"inner": [
{ "x": Number(x) },
{ "y": Number(y) }
]
}
}
} => x + y
_ => 0
}
}

fn main {
let x : @json.JsonValue = {
"outer": { "middle": { "inner": [{ "x": 42 }, { "y": 24 }] } },
"another_field": "string value",
}
json_process(x) |> println
}
  • 新增 derive(Hash) 支持,可以自动为类型定义生成 Hash trait 的实现:
enum MyType {
C1
C2(Int)
} derive(Eq, Hash)

fn main {
let m = {}..set(C1, 1)..set(C2(1), 2)..set(C2(2), 3)
println(m[C1]) // Some(1)
println(m[C2(1)]) // Some(2)
println(m[C2(3)]) // None
}
  • Js 后端生成代码移除对 TextDecoder 的依赖

标准库更新

  • 多个函数签名更改

    • Array::new_with_index-> Array::makei

    • FixedArray::new/FixedArray::new_with_index-> FixedArray::makei

    • FixedArray::empty -> FixedArray::new

  • 移除了 Debug trait

构建系统更新

  • 支持运行单个 .mbt 文件(不在某个包中),用法:moon run xx.mbt(默认链接标准库,便于运行一些代码片段,xx.mbt 中需要有 main 函数)

  • moon 支持 shell-completion

    • 使用示例:Zsh

Zsh 在启动时会自动读取 $FPATH 下的所有脚本,可以把补全脚本放在 $FPATH 下的任何一个路径中。

为了方便管理,我们新建一个专门放置补全的路径 $ZSH/completions 并加到 $FPATH

mkdir $ZSH/completions
echo "FPATH+=$ZSH/completions" >> ~/.zshrc
# Zsh 的 shell completion 文件名通常以下划线开头
moon shell-completion > $ZSH/completions/_moon # 一般不需要显式指明 shell 类型,自动读取 $SHELL

. ~/.zshrc # 重载即可使用,或 omz reload

如果希望保持 portability,可以直接把下面这行写进 .zshrc

eval "$(moon shell-completion --shell=zsh)"

shell-completion.gif

达到上图的效果还需要安装 zsh-autocomplete zsh-autosuggestions 两个插件。

工具链更新

  • moonfmt 修复 array spread 格式化后被加上花括号的问题;调整了括号推断的模式匹配,避免使用 wildcard

  • VS Code 现在支持自动对函数生成测试,包括黑盒测试(以 _test.mbt 结尾) 和白盒测试(单元测试)

  • 支持单个 .mbt 文件的 Run | Debug 按钮

weekly 2024-07-22

· 阅读需 8 分钟

MoonBit 更新

  • 【breaking change】错误处理的语法从f(x)! 改为了 f!(x),这样做以便于后续 IDE 在补全的过程中将函数名称和 ! 一起进行补全,并且对 f! 进行特殊的渲染

  • 【breaking change】local 函数如果可能返回错误类型,则必须对其进行标注,比如:

fn toplevel() -> Unit!String {
fn local1() -> Unit!String { raise "err" } // local function
fn local2() -> _!_ { raise "err" } // local function
apply!(fn (_x) -> Int!String { raise "err" }, 42) |> ignore // anonymous function
}

fn apply(f: (Int) -> Int!String, x: Int) -> Int!String {
f!(x)
}

同时,提供了 fn!fn local!() 语法用于标注该函数可能返回错误,并让编译器对返回的错误类型进行推导,其中前者用于矩阵函数和匿名函数,后者用于普通的 local 函数,比如:

fn toplevel() -> Unit!String {
fn local!() { raise "err" } // local function
apply!(fn! (_x) { raise "err" }, 42) |> ignore // anonymous function
apply!(fn! { _ => raise "err" }, 42) |> ignore // matrix function
}
  • 完善了 try 表达式的功能,目前完整的 try 表达式的使用方式如下:
fn test_try() -> Unit {
fn f() -> Int!String {
raise "err"
}
try {
println("this is try body")
f!()
} except {
err => println(err)
} else {
val => println(val)
}
}

其中 except 关键字用于处理 try body 返回错误的情况,else 关键字用于处理 try body 正常返回的情况,同时改语法有如下几种简化情况:

  • 如果 else 分支中不需要对返回值进行任何处理,则 else 分支可以缺省

  • try body 可以是一个简单的表达式

  • except 关键字可以缺省

比如下述程序所示:

fn test_try() -> Result[Int, String] {
fn f() -> Int!String {
raise "err"
}
try Ok(f!()) { err => Err(err) }
}
  • 对模式匹配也添加了整数字面量的重载支持:
fn is_42(x : Double) -> Bool {
match x {
42 => true
_ => false
}
}
  • 【即将到来的 breaking change】Map pattern 将会在本周更改{ "key" : value }中的语义匹配。

原本的 map pattern 中,{ "key" : value } 里,value 的类型为 Option[_],无论 "key" 是否存在都会匹配。接下来,pattern 中 { "key": value } 的语义会修改为匹配 "key" 存在的情况,value 也会直接匹配 "key" 的实际内容。如果想要同时匹配 "key" 存在/不存在的情况,需要使用一个 { "key"? : value_or_none } 的新写法,其中 value_or_none 的类型为 Option[_]

  • 【即将到来的 breaking change】显式实现 trait 的旧语法 fn Trait::method(...) 将会在本周被移除,现有代码应当改用语法 impl Trait for SelfType with method(...)。未来 fn Trait::method(...) 这一语法会被用于直接给 trait object 类型定义方法

MoonBit IDE 更新

  • 现在 main 函数上将提供 Run | Debug 的 Codelens,便于快捷运行和调试程序。目前快捷调试仅支持 JavaScript 后端。

ide

  • 现在顶层函数支持通过 Codelens 调用 AI 生成测试。不过目前这个功能尚在开发,并不稳定。

    1. 点击 “Gen test” 按钮。

    step1

    1. 右边会出现一个新的窗口显示生成好的测试。

    step2

    1. 点击 “Reject” 来去掉不希望的测试,点击 “insert” 将测试插入到源文件中。

标准库(moonbitlang/core)更新

  • 修改了 Show trait 的定义,使其有更正确的行为。新的 Show trait 的定义如下:
pub trait Show {
// `output` 函数用于实现复合类型的 `Show`。
// 它把 `Self` 的一个字符串表示写入到一个 `Logger` 中
output(Self, Logger) -> Unit
// `to_string` 是给 `Show` 的用户使用的,
// 它可以用于字符串插值和 `println` 等。
// `to_string` 有一个使用 `output` 的默认实现。
// 有些类型,如 `String`,会自行重载 `to_string` 以修改其行为
to_string(Self) -> String
}

新的 Show 解决了 String 的实现行为不正确的问题。过去,如果一个复合类型中有 String,那么它的 Show 的实现不会对这个 String 进行 escape,这会导致错误的结果。另一方面,我们希望当 String 直接被用于字符串插值和 println 时,不需要 escape。新的 Show 定义及 core 中的实现能够同时满足上述需求。

对于 Show 的实现者,需要注意以下几点:

  • 应当实现 output 方法,而不是 to_string 方法

  • 在递归调用子结构(如结构体的字段)的 Show 实现时,应当使用 Show::output(..., logger),而不是 to_string

  • Show::to_string 的默认实现不是指一个方法 ,因此无法使用 . 调用。如果想支持 .to_string() 这样的写法,可以添加一个如下的辅助定义:

pub fn to_string(self : ...) -> String {
Show::to_string(self)
}
  • 【即将到来的 breaking change】Show trait 的定义修改后,Debug trait 的功能已经完全被 Show trait 覆盖了。因此,Debug trait 已经被弃用,并且会在近期被删除。

  • 数据结构类型名称被改为了 T, 修改样例如下

// old
// let m : @hashmap.HashMap[Int, Int] = @hashmap.new()

// new
let m : @hashmap.T[Int, Int] = @hashmap.new()

以下数据结构类型均被修改为 T

  • deque
  • hashmap
  • hashset
  • immut/array
  • immut/hashmap
  • immut/hashset
  • immut/list
  • immut/priority_queue
  • immut/sorted_map
  • immut/sorted_set
  • queue
  • priorityqueue
  • rational
  • sorted_map
  • sorted_set

构建系统更新

  • 调整了构建过程中的输出,现在只会在某条命令执行失败的情况下会打印出该命令

  • moon check|build|test|bundle--target 之前只支持三种选项 wasm|wasm-gc|js,修改后支持同时指定多个后端并行执行。支持选项变更为 wasm|wasm-gc|js|all,并且可以用逗号任意组合。添加 --serial 选项将不同后端之间的并行执行变为串行执行,但是同一后端内部仍为并发执行。使用样例:

    • moon test --target all执行全部后端的测试

    • moon test --target js,wasm 执行 js,wasm 后端的测试

    • moon test --target js,wasm --serial等价于按顺序执行 moon test --target js; moon test --target wasm

  • moon.pkg.json["link"]["wasm"|"wasm-gc"] 中添加与内存相关的 heap-start-addressimport-memory 配置

{ 
"link": {
"wasm": {
"heap-start-address": 65536,
"import-memory": {
"module": "xxx",
"name": "yyy"
}
}
}
}
  • moon new 默认协议修改为 Apache-2.0

weekly 2024-07-15

· 阅读需 6 分钟

MoonBit 更新

  • 新增级联运算符(cascade operator):MoonBit 引入了 “..” 操作符,能够优雅地对可变 API 进行链式调用,同时保持可变 API 签名的整洁(依然返回 Unit)。

如图例,为了避免重复键入上图中的array, 和区分不可变与可变操作,MoonBit引入了级联运算符。对于一个类型中的所有返回Unit的方法,可以使用..将这些方法的调用串联起来,而不需要专门修改这些方法的返回类型。 array..push(5)..sort()相当于依次调用了可变操作array.push(5)array.sort(), 最终返回array

cascade.png

  • 正式移除了@package.Type::[...]的语法。推荐使用@package.of([...])作为替代。

  • 现在--target js下调试模式生成的sourcemap支持names表。因此使用 devtools 或 vscode 进行调试时,局部变量会显示为原变量名,还可以在Debug console中使用原变量名访问它。这极大的改进了调试体验。

Before: names_before.png

After: names_after.png

  • 数组支持展开语法 (spread syntax),可以在数组构造时,将任何支持iter()方法的对象表达式在语法层面展开成一组 Iter[_] 对象。

    数组表达式:

let u1 = [1, 2, 3]
let u2 = [5, 6, 7]

fn main {
let v = [..u1, 4, ..u2, 8]
println(v)
}

// [1, 2, 3, 4, 5, 6, 7, 8]

Map表达式(返回键值对):

  let map : @sorted_map.T[Int,String] = @sorted_map.of([(3, "c"), (2, "b"), (1, "a")])

fn main {
let v = [..map, (4, "d")]
println(v)
}

// [(1, a), (2, b), (3, c), (4, d)]
  • 支持了和C语言类似的位运算符(^, &, |, <<, >>),优先级同C一致。同时为了避免歧义,当表达式同时存在几个运算符并且不容易区分优先级时,formatter会插入额外的括号以改善可读性。

  • 支持重载整数字面量。在已知类型时,Int 以外的类型的字面量可以省略 UL 等特殊标记:

fn main {
let uint : UInt = 42
let int64 : Int64 = 42
let double : Double = 42
}

标准库(moonbitlang/core)更新

  • Hash Trait 即将更新为如下形式。
trait Hash {
hash_iter(Self, Hasher) -> Unit
hash(Self) -> Int
}

impl Hash with hash(self) {
let hasher = Hasher::new()
hasher.hash_iter(self)
hasher.finalize()
}

构建系统更新

测试机制调整说明

为优化黑盒测试的开发体验,moon 现支持自动将以 _bbtest.mbt 结尾的源代码文件封装为黑盒测试,moon 在编译 *_bbtest.mbt 时会自动将其所在的包作为依赖。为了更好地开发和测试 MoonBit 项目,接下来将对 MoonBit 项目的测试机制进行调整。

Background

目前一个 MoonBit 项目中可以有三种类型的测试:白盒测试(white box test)、黑盒测试(black box test)、内部测试(inline test)。

  • 白盒测试:写在 *_test.mbt 中,构建系统会把当前包中的 *.mbt*_test.mbt 一起打包编译,因此在 *_test.mbt 中可以访问当前包的私有成员,这些测试可以使用 moon.pkg.jsonimporttest-import 字段中的依赖。test-import 只在白盒测试中用到,不会打包到最终的构建产物中。

  • 黑盒测试:写在 *_bbtest.mbt 中,构建系统会在编译 *_bbtest.mbt 时会自动将其所在的包作为依赖,*_bbtest.mbt只能访问其所在包的公开成员(即模拟外部用户在使用这个包时的视角),这些测试可以使用 moon.pkg.json 中的 bbtest-import 字段中的依赖(以及其所在包,不需要显式写在bbtest-import 字段中)。bbtest-import 只在黑盒测试中用到,不会打包到最终的构建产物中。

  • 内部测试:可以直接写在 *.mbt(注意这里的 *.mbt 不包含上面提到的 *_test.mbt*_bbtest.mbt)中,可以访问当前包的私有成员,这些测试只使用 moon.pkg.jsonimport 字段中的依赖。

Change

一些命名上的调整:当前的*_test.mbt(白盒测试)后续将调整为*_wbtest.mbt,*_bbtest.mbt(黑盒测试)将调整为 *_test.mbt,鼓励大家写黑盒测试。

工具链更新

  • moonfmt改进

    • 现在当源码中存在语法错误时,格式化会忽略相关的代码,此时仍然能够执行代码格式化。

    • 当表达式同时存在几个运算符并且不容易区分优先级时,格式化会插入额外的括号以改善可读性。

  • IDE 增加对黑盒测试(*_bbtest.mbt)的支持

weekly 2024-07-08

· 阅读需 4 分钟

MoonBit 更新

  • 【重大更新】修改 array slice 的语法,从 arr[start..end] 修改为类似 Python 的 arr[start:end]。这是为了避免和接下来要支持的 cascade method call x..f() 产生语法冲突。旧的语法会在近期删除。

  • 【Wasm后端重大更新】将 fn init 中的代码编译到 start section。 之前版本中的 fn initfn main 代码块中的代码都会被编译到一个特殊函数中,这个特殊函数会被导出为 "_start" 函数,因此宿主环境需要调用 "_start" 函数来进行初始化和执行 main 函数 新版本中会使用 wasm 标准中的 start section 来存放 fn init 中的代码,从而在加载 wasm 模块的过程中完成初始化,这意味着 fn init 中代码的执行不再需要调用 "_start" 函数,只有需要执行 main 函数的时候才需要调用 "_start".

  • 【重大更新】test block 不再返回 Result 类型的结果。 现在的 test block 中使用错误处理机制对测试失败的情况进行处理,鼓励使用标准库中的 inspect 函数,和 @test 包中的 @test.eq 等辅助函数编写测试,比如:

test "unwrap should return value on Some" {
let some : Int? = Some(42)
inspect(some, content="Some(42)")!
@test.eq(some.unwrap(), 42)!
}
  • 支持使用 @pkg.C 来跨包使用构造器,比如如果在 @pkgA 中包含如下声明:
// pkgA
pub enum E1 { C1 } derive(Debug)

enum E1_hidden { C1 }

现在可以在另一个包中对 E1 的构造器 C1 直接进行使用,比如:

// pkgB
fn main {
debug(@pkgA.C1)
}

当在同一个包中,如果出现重复的 public constructor,则会报错,比如:

pub enum E1 {
C1
}

pub enum E2 {
C1
^^ ------ There can be at most one public constructor with name C1.
}

标准库更新

  • 迁移到新的错误处理机制。

  • 迁移到无符号整数,移除了Int和Int64类型旧的compare_udiv_umod_u函数;调整了下面的API:

    • Int32.trunc_double_uInt64.trunc_double_u 更改为 UInt.trunc_doubleUInt64.trunc_double

    • Int64::extend_i32_u 更改为 UInt64::extend_uint

    • Double::convert_i32_uDouble::convert_i64_u 更改为Double::convert_uintDouble::convert_uint64

构建系统更新

  • moon version --all 现在会显示 moonrun 的版本信息。
$ moon version --all
moon 0.1.20240705 (0e8c10e 2024-07-05) ~/.moon/bin/moon
moonc v0.1.20240705+7fdd4a042 ~/.moon/bin/moonc
moonrun 0.1.20240703 (52ecf2a 2024-07-03) ~/.moon/bin/moonrun
  • 修改moon new创建项目的license字段默认为空。

  • 默认开启诊断信息渲染 render

工具链更新

  • VSCode 插件安装MoonBit工具链功能调整。工具链安装的默认版本由总是安装最新版本调整为安装对应插件版本的工具链。

weekly 2024-07-01

· 阅读需 3 分钟

MoonBit 更新

  • 在没有歧义的情况下,enum构造器的使用可以省略类型前缀。比如现在可以直接使用 Some(42) 而不需要写 Option::Some(42);如果当前环境中有两个类型 T1T2 都定义了某个构造器 C,那么在使用的时候则需要通过上下文中的类型或者类型前缀指明是 T1::C 还是 T2::C,否则编译器会报错

  • 添加 UInt64 内建类型,支持加、减、乘、除、模以及 UInt64/Int64 的互相转换。

fn main {
let a = 0UL
let b : UInt64 = 1UL
println(a - b) //18446744073709551615
}
  • !! 后缀的语义修改为捕获函数调用中可能出现的错误,并返回 Result 类型,比如
fn f() -> Int!String { .. }
fn main {
let res = f()!! // res: Result[Int, String]
println(res)
}
  • moon test 中支持使用错误类型表示测试失败的情况,比如
fn eq[T : Debug + Eq](a : T, b : T, ~loc : SourceLoc = _) -> Unit!String {
if a != b {
let a = debug_string(a)
let b = debug_string(b)
raise ("FAILED: \(loc) `\(a) == \(b)`")
}
}

test "test_eq" {
eq(1+2, 3)!
}
  • 标准库中的 I/O 相关操作只保留了 println,其他操作将会在 io package 中提供

标准库更新

  • 统一 T::new()/T::make() 等创建容器对象的函数风格,移除了 T::with_capacity

  • 原先的 iteriteri 重命名为 eacheachiiter_reviter_revi 重命名为 each_reveachi_rev

  • as_iter 重命名为iter

构建系统更新

  • 预计将于本周开源

工具链更新

  • 优化调试体验,现在⽤户可在 JavaScript Debug Terminal 中执⾏ moon run --target js --debug 进行调试

  • moon info 和覆盖率工具适配错误类型和错误处理

weekly 2024-06-24

· 阅读需 2 分钟

MoonBit 更新

  • 支持了 32 位无符号整数
let num = 100U // 32位无符号整数的字面量需要后缀U
  • 在 wasm 后端导出返回值类型为 Unit 的函数时,之前导出函数的类型中会有 (result i32),现在 MoonBit 编译器会自动生成一个没有返回值 wrapper 函数,并将其进行导出

  • moonbitlang/core 的 API 一致性调整

    • forall/existall/any统一为all/any
    • containsmember 统一为contains

IDE 更新

  • 修复了 rename method 时候会丢失 type prefix 的 bug

  • 增加了 try ... catch ... 表达式中的 match clause 中补全的功能

构建系统更新

  • 增加了诊断信息渲染功能,目前还在试验阶段。可通过设置环境变量 MOON_RENDR=1 启用

diagnosis.png

  • moon bench 命令改为 moon generate-build-matrix,bench 子命令留待后续使用

weekly 2024-06-17

· 阅读需 3 分钟

MoonBit 更新

  • 支持了错误处理机制
  1. 函数返回值类型可以用 Int!String 来标识这个函数正常情况下返回 Int ,错误情况下会抛出类型为 String 的错误值,比如
fn div(x: Int, y: Int) -> Int!String { .. }
  1. raise 关键字用于中断当前控制流,直接抛出错误,比如
fn div(x: Int, y: Int) -> Int!String {
if y == 0 { raise "divide by 0" }
x / y
}
  1. try { expr0 } catch { pattern1 => expr1; pattern2 => expr2; .. } 表达式可以用于捕获 expr0 中抛出的错误,并对其进行模式匹配来处理,比如下面这个函数调用上面的 div 函数,并在 div 函数抛出错误的时候将错误信息打印,并返回默认值
fn div_with_default(x: Int, y: Int, default: Int) -> Int {
try {
div(x, y)!
} catch {
s => { println(s); default }
}
}
  1. 此外,可以用后缀运算符 !!! 进行错误处理,这些后缀运算符只能应用于函数调用,其中: f(x)! 将调用 f 的过程中发生的错误立即重新抛出。 f(x)!! 则会在 f 发生错误的情况下直接 panic,其等价于
try { f(x)! } catch { _ => panic() }

函数调用的形式包括方法调用,中缀运算符和管道运算符的调用,比如

fn init {
let _ = x.f()!!
let _ = (x + y)!!
let _ = (x |> f)!!
}
  1. 最后,对可能会抛出错误的函数如果没有使用上述任何错误处理,那么则会报 unhandled error 的错误
  • 支持 Map 字面量语法:
fn init {
// 键必须是字面量
let m1 : Map[String, Int] = { "x": 1, "y": 2 }
let m2 : Map[Int, String] = { 1: "x", 2: "y" }
}

IDE更新

  • 修复了 IDE 在补全过程中 builtin package 中的方法会重复出现两次的 bug

  • 修复了 IDE 中缺少 Byte 相关的补全功能

构建系统更新

  • 添加对 internal 包的支持,这些包被放在名为 internal 的目录中。internal 包只能被以 internal 的父目录为根的包导入。 例如,如果有一个包的路径为 username/hello/x/internal/a,该 internal 包的父目录为 username/hello/x,那么只有包username/hello/x 或其子包(例如 username/hello/x/a)能够导入username/hello/x/internal/a,而username/hello/y则不能导入该包。

weekly 2024-06-11

· 阅读需 2 分钟

MoonBit更新

  • 【Wasm MVP】Wasm1 后端添加基于 Perceus 算法的引用计数支持

  • 【语法】throw raise try catch 均被保留为关键字

    • 为了即将添加的错误处理机制
  • 【Core】Listsorted_map被移动至core/immut

    • List被移动至core/immut/list包中,并被移除内置类型支持

    let a = @immut/list.List::Cons(1, Cons(2, Nil))


    • sorted_map被移动至core/immut/sorted_map包中
  • 【Core】JSON API被优化,以提高性能并适应新的Core API

    • 新的类型定义
// Types and methods
pub enum JsonValue {
Null
// 原为Boolean(Bool)
True
False
Number(Double)
String(String)
Array(Array[JsonValue])
Object(Map[String, JsonValue]) // 原为@map.Map
}
  • 【JS】Int64性能优化
    • 在 JS 后端上,Int64现编译到两个Int,解决原先编译到BigInt的性能问题。同时,JS 下Int64的 runtime 实现现移动到 core 标准库中,便于开源社区参与 review 和改进。

构建系统更新

  • moon.mod.json 和 moon.pkg.json 在开发过程中支持注释,但是在 publish 时不允许注释(只支持标准 JSON 格式)

IDE更新

  • 【LSP】函数补全增加参数名称显示 LSP.png

weekly 2024-06-03

· 阅读需 3 分钟

MoonBit更新

  • 类型标注增加了新的语法T? 来表示Option[T]
struct Cell[T] {
val: T
next: Cell[T]?
}

fn f(x : Cell[T]?) -> Unit { ... }

相当于

struct Cell[T] {
val: T
next: Option[Cell[T]]
}

fn f(x : Option[Cell[T]]) -> Unit { ... }

旧的Option[T]仍然兼容,但是推荐使用更简短的新语法。moonfmt也会将Option[T]格式化为T?

  • 核心库 API 整理工作继续进行
    • Iter包被合入了builtin包。现在使用Iter[T]不需要@iter.前缀
pub fn any[T](xs : Iter[T], predicate : (T) -> Bool) -> Bool {
// ^不需要@iter.
match xs.find_first(predicate) {
None => false
Some(_) => true
}
}
  • Stack包被移入moonbitlang/x
  • 移除了List包,以及各类数据结构的to_listfrom_list函数。对于数据结构间转换和中间的表示结构,推荐使用Iter[T]Array[T]
  • 性能提升
    • 编译器现在会在分离编译的阶段进行一部分的闭包转化,从而改进了编译性能,并且对 JavaScript 后端生成的代码在特定情况下也进行了闭包转化
    • Option[Bool], Option[Char], Option[Byte], Option[Unit] 这些类型使用32位整数表示,其中 None 对应的值为 -1, Some(x) 对应的值为 x; Option[Int] 类型在 wasm 后端使用 64 位整数表示,其中 None 对应的值为 0x1_0000_0000, Some(x) 对应的值为 x, Option[Int]在 JavaScript 后端使用 int | undefined 表示,其中 undefined 表示 None
  • abort行为变更
    • 为了解除Wasm程序对于非标准的spectest.print_char的依赖,正在重构错误输出功能。
    • abort将不会利用spectest.print_char打印错误信息,行为与panic相同,等待功能进一步完善。

插件更新

  • 【语言服务器】修复了内存泄露的问题