Language Update
-
Added support for
for .. in
loops based onIter
andIter2
types:fn main { for x in [1, 2, 3] { println(x) } for k, v in {"x": 1, "y": 2} { println("\{k} => \{v}") } }
You can bind one or two variables between
for
andin
to iterate over elements inIter
. A single-variable loopfor x in expr1
iterates overexpr1.iter() : Iter[_]
, while a two-variable loopfor x, y in expr2
iterates overexpr2.iter2() : Iter2[_, _]
. Underscores can be used to ignore elements, but pattern matching is not allowed betweenfor
andin
.The loop body in
for .. in
can use control flow statements likereturn
/break
/raise
:test "for/in" { // `iter2` for arrays iterates over index + elements for i, x in [1, 2, 3] { assert_eq!(i + 1, x) } }
-Introduced new string interpolation syntax \{}
, deprecating the old \()
. This allows embedding more complex expressions directly into strings. Future updates will relax syntax restrictions within string interpolations, such as supporting \{1 + 2}
and \{x.f(y)}
.
"hello, \(name)!" // warning: deprecated
"hello, \{name}!" // new syntax
- Expanded numerical handling: Added a new built-in
BigInt
type for managing large values beyond the range of regular integers.
// BigInt literals end with N
let num = 100000000N
// Like Int literals, underscores are allowed between digits. Hexadecimal, octal, and binary formats are also supported.
let n2 = 0xFFFFFFFFN
let n3 = 0o77777777N
let n4 = 0b1111111100000000N
let n5 = 1234_4567_91011N
// If the type is explicitly BigInt, the N suffix is not required
let n6 : BigInt = 1000000000000000000
// Pattern matching also supports BigInt
match 10N {
1N => println(1)
10N => println(10)
100 => println(100)
}
-
Added support for declaring error types using enums. For example, errors in the Json package can be declared as follows:
pub type! ParseError { InvalidChar(Position, Char) InvalidEof InvalidNumber(Position, String) InvalidIdentEscape(Position) } derive(Eq)
You can also use labeled and mutable arguments within error types using enums, the same as how you would use them in regular enum types.
type! Error1 {
A
B(Int, ~x: String)
C(mut ~x: String, Char, ~y: Bool)
} derive(Show)
fn f() -> Unit!Error1 {
raise Error1::C('x', x="error2", y=false)
}
fn g() -> Unit!Error1 {
try f!() {
Error1::C(_) as c => {
c.x = "Rethrow Error2::C"
raise c
}
e => raise e
}
}
fn main {
println(g?()) // Err(C(x="Rethrow Error2::C", 'x', y=false))
}
- Introduced
catch!
syntax to rethrow errors that are not handled within an error handler. By usingcatch!
, you can more easily manage and propagate errors through your code, simplifying the process of error handling. For example, the functiong
above can be rewritten as:
fn g() -> Unit!Error1 {
try f!() catch! {
Error1::C(_) as c => {
c.x = "Rethrow Error2::C"
raise c
}
}
}
- The generated JavaScript code no longer relies on the
TextDecoder
API. If Node.js support forTextDecoder
improves in the future, we might consider adding it back.
IDE Update
-
Fixed an issue where the source code in the core library couldn’t load in web-based VSCode plugin while debugging. Debugging features in MoonBit IDE are now functional.
-
MoonBit IDE now supports auto-completion for constructors in pattern matching based on type:
match (x : Option[Int]) {
// ^^^^ Auto-completes `None` and `Some`
}
Core Update
- Added a new
Iter2
type for iterating over collections with two elements, like Map, or iterating over arrays with an index:
fn main {
let map = {"x": 1, "y": 2}
map.iter2().each(fn (k, v) {
println("\{k} => \{v}")
})
}
Compared to Iter[(X, Y)]
, Iter2[X, Y]
offers better performance and native support for for .. in
loops.
-
Moved
@json.JsonValue
to the@builtin
package and renamed it toJson
.@json.JsonValue
is now an alias forJson
, so this change is backward compatible. -
Added a
ToJson
interface in@builtin
to represent types that can be converted toJson
.
Build System Update
-
Added
-C/--directory
commands tomoon check|build|test
, equivalent to--source-dir
, to specify the root directory of a MoonBit project, i.e., wheremoon.mod.json
is located. -
Updated the
root-dir
inmoon.mod.json
tosource
. This field specifies the source directory for modules, and the value of thesource
field can be a multi-level directory but must be a subdirectory of the directory containingmoon.mod.json
, e.g.,"source": "a/b/c"
.This field is introduced because package names in MoonBit modules are related to file paths. For example, if the current module name is
moonbitlang/example
and a package is located atlib/moon.pkg.json
, you would need to import the package using its full namemoonbitlang/example/lib
. Sometimes, to better organize the project structure, we may want to place the source code in thesrc
directory, such assrc/lib/moon.pkg.json
. In this case, you would need to usemoonbitlang/example/src/lib
to import the package. However, generally, we do not wantsrc
to appear in the package path, so you can specify"source": "src"
to ignore this directory level and still import the package asmoonbitlang/example/lib
.
Toolchain Update
- MoonBit AI supported generating code explanations: In MoonBit IDE, click the MoonBit logo and select
/explain
to get code explanations which will appear on the right side. Don’t forget to click or to give us your feedback.