20260608 MoonBit v0.10.0 Release
moonc version: v0.10.0+84519ca0a
This update is for MoonBit 0.10, an important step before the official 1.0 release. We are continuing to refine the language, toolchain, and ecosystem experience, and are currently targeting MoonBit 1.0 for Q3. The final timeline may be adjusted based on testing progress and community feedback.
Language Updatesβ
-
traitandimplsyntax now require thefnkeyword: This change makes it easier to add support for polymorphic methods in traits. Existing code can be migrated automatically by runningmoon fmt. The old syntax withoutfnis still supported for now; in the next version, it will start producing warnings and will be removed in the future.implentries in.mbtpfiles are also now required to include thefnkeyword.trait I { fn f(Self) -> Unit //^^ } impl I for Int with fn f(_) {} // ^^ -
Polymorphic
traitmethods are now supported. Methods inside atraitcan now have their own type parameters. When implementing a polymorphic trait method, the method's own type parameters do not need to be annotated explicitly. If you do annotate them, put the method type parameters after thefnkeyword, while the type parameters of theimplitself still go after theimplkeyword:trait Logger { fn[X : Show] write_object(Self, X) -> Unit } impl Logger for StringBuilder with fn write_object(self, x) { self.write_string(x.to_string()) }trait Poly { fn[X] f(Self, X) -> Unit } impl[A] Poly for Array[A] with fn[X] f(self, x : X) { // ^^^ impl type parameters ^^^ method type parameters ... } -
for .. inloops now support default updates for state variables.for i in 0..<10; p1 = 1, p2 = 0; p1 = p1 + p2, p2 = p1 { // ^^^^^^^^^^^^^^^^^^^^^ // New in this release. The semantics are // the same as default updates in regular // `for` loops. When `continue` with arguments // is not called explicitly, these declarations // update the loop variables at the end of // each iteration. println("fib#\{i + 1} = \{p1}") } -
List comprehensions now support extra loop variables from
for .. in.let fibs = [ for _ in 0..<10 p1 = 1, p2 = 0 p1 = p1 + p2, p2 = p1 => { p1 } ] -
When using list comprehensions to construct types other than
Iter, the body can contain side effects. This includesraiseandasync. -
String interpolation improvements.
-
String interpolation used to compile to string concatenation. It now compiles to efficient writes into a
StringBuilder. For example,let r = "a\{b}c":// Previous compilation result let r = "a" + b.to_string() + "c" // Current compilation result let r = { let builder = StringBuilder(size_hint=2) builder.write_string("a") builder.write(b) builder.write_string("c") builder.to_string() } -
Inside string interpolation
\{...}, the use of{,}, and"is no longer restricted, so nested string interpolation is allowed.let xs = ["cd", "ef"] let r1 = "ab\{xs.join(";")}" assert_eq(r1, "abcd;ef") -
Nested anonymous functions are supported inside string interpolation and receive special handling:
let r = "a\{builder => builder.f()}" // Equivalent to let r = { let builder = StringBuilder() builder.write_string("a") (builder => builder.f())(builder) builder.to_string() }
-
-
Added template write syntax
lhs <+ rhs. In web backend development, a common pattern is to assemble strings through a buffer. CallingStringBuilder::write_stringandStringBuilder::writemanually is verbose. HTML DSLs or template engines can also be used for this scenario, but they introduce extra memory allocation and string replacement overhead. Template write syntax provides a lighter, more readable solution with zero additional overhead. The following is equivalent code using the new feature:fn render( style : String, li_class : String, items : Array[String], ) -> String { let buf = StringBuilder() // <ul prop=foo> buf..write_string("<ul prop=foo>") // <li class="{li_style}">{item}</li> for item in items { buf..write_string("<li class=\"") ..write(li_class) ..write_string("\">") ..write(item) .write_string("</li>") } // </ul> buf.write("</ul>") buf.to_string() }fn render( style : String, li_class : String, items : Array[String], ) -> String { let buf = StringBuilder() buf <+ "<ul prop=foo>" for item in items { buf <+ $|<li class="\{li_class}">\{item}</li> } buf <+ "</ul>" buf.to_string() }For
buf <+ "a\{b}", it is decomposed directly intobuf..write_string("a")..write(b).The right-hand side of
<+supports the following expressions:-
A string:
"abc\{x}" -
A multiline string:
#| multiline string... -
A multiline string interpolation:
$| multiline string with \{x} -
A map literal:
{"k1": v1, "k2": v2}
The left-hand side of
<+does not have to be aStringBuilder; it can be any typeTthat implements the following methods:-
T::write_string(T, String) -
T::write(T, X) -
Optional, for map literals:
T::write_object_begin(T),T::write_object_field(T, String, X), andT::write_object_end(T)
The syntax rules for string interpolation inside
\{...}are the same as regular string interpolation. -
-
Added conditional template write syntax
lhs <? rhs. On top of template write syntax, writes can now have a precondition. This is useful for debug logging and similar scenarios: the program should output debug information only in debug mode and should not pay the logging cost in normal mode. In the following example,loggerhas typeOption[T]. In debug mode, its value isSome(...); in normal mode, it isNone.logger <? "[tag] message \{x}..." // Equivalent to if logger is Some(x) { x <+ "[tag] message \{x}..." } -
Removed the old struct constructor syntax. The previously deprecated custom constructor syntax
fn new(..)is no longer supported. The unified new constructor syntax isfn Type::Type(..). -
Deprecated the
try?syntax. The compiler now provides migration suggestions during checking. -
Added the experimental built-in
V128type. It currently compiles to thev128type on the wasm/wasm-gc backends. On the native backend that generates C code, it compiles touint8x16_ton Arm architectures with NEON support and to__m128ion x86 architectures with SSE2 support. In other cases, it is simulated with twouint64values. None of these details are ABI guarantees; efficientV128operations will be provided through the standard library in the future.
Toolchain Updatesβ
-
The new MoonBit native backend has been released and can be tried with the
MOONBIT_NEW_NATIVE=1environment variable. It currently supports macOS on Apple Silicon only; Linux and Windows support will be rolled out gradually. -
Added
moon test --profileandmoon run --profile. On macOS, these commands usexctraceto profile native programs. Linux support has also been completed. -
Added
--diagnostics-limitto limit the number of errors and warnings and reduce the noise from printing the underlyingmoonccommand directly on failure. -
The Wasm backend's
printlnimplementation has been replaced with a WASI-based implementation. -
Added the experimental
moon runwasmcommand and SKILL marketplace. Usemoon runwasm Yoorkin/cowsay -- helloto directly run packages published on mooncakes.io that support the Wasm target. mooncakes.io automatically builds wasm-opt-optimized*.wasmfiles for packages that support Wasm compilation targets and displays anySKILL.mdin the same directory on the mooncakes.io/skills page.

-
Use
moon.modinstead ofmoon.mod.jsonby default.moon.modnow supports top-level fields such assupported_targets,preferred_target,readme,license,keywords,repository, anddescription.moon fmtenables migration frommoon.mod.jsontomoon.modby default. If issues occur, setNEW_MOON_MOD=0to disable it. -
The behavior of
moon add path/to/modhas been changed: adding an existing dependency again now only emits a warning and no longer updates the version implicitly. Usemoon add --upgrade path/to/modwhen an update is needed. -
Native LSP is now the default LSP, with newly added LSP support for
moon.modandmoon.pkg. -
Added the experimental
moon cram testcommand for testing MoonBit CLI applications. It first builds CLI programs in the project with the native backend, puts them into thePATH, and then runs cram tests. See the basic example at moonbit-community/cram_test_poc. -
Added experimental
moon run --profileandmoon test --profiletooling. It currently supports the native backend on macOS and Linux, usingxctraceandperfrespectively for profiling and demangling symbols in the results.
Standard Library Updatesβ
-
moonbitlang/asyncis now at version 0.19.2. The main updates since the previous monthly report, 0.19.0, are as follows:-
Added support for watching file system changes. Use
@fs.Watcher(..)to watch changes under all child files and folders of a directory. Currently,@fs.Watcheronly provides thewait_anymethod and does not yet report the specific changed content. Support for reporting detailed change information will be added in the future. See the@fs.Watcherdocumentation for details. -
Added the
@raw_fd.RawFdStreamtype. It is similar to@raw_fd.RawFd, but implements@io.Reader/@io.Writer, making it easier to operate file descriptors with stream semantics. -
Added the
@async.Mutextype for synchronization across concurrent tasks. -
Added optional file descriptor leak checking, which can be enabled with
MOONBIT_ASYNC_CHECK_FD_LEAK=1. When enabled, if the program forgets to release resources managed bymoonbitlang/async, such as files, it willabortbefore exit and report the leak.
-