2025-06-03
Language Updatesβ
1. Omission of !
for Effectful Callsβ
Calling effectful functions (those that may throw errors or are asynchronous) no longer requires explicitly appending !
. The IDE will automatically underline functions that may throw and render asynchronous functions in italics using semantic highlighting.
2. f?(..)
Replaced by try? f(..)
Expressionβ
try? expr
is equivalent to try Ok(expr) catch { err => Err(err) }
, allowing errors to be converted into the Result type. Compared to the original f?(..)
, try?
is more flexible and can handle multiple function calls with potential errors at once, for example:
try? {
f(..)
g(..)
}
When migrating, special attention should be paid to the following case:
f?(g!(..))
cannot be simply rewritten as try? f(g(..))
, because this would redirect the error from g
into the Result
. In this case, the result of g
should first be extracted with let
, and then passed into try?
.
3. Add Support for Error Polymorphism in Higher-Order Functionsβ
fn[X] Array::each(arr: Array[X], f: (X) -> Unit?Error) -> Unit?Error {
for x in arr {
f(x)
}
}
fn main {
let arr = ["a", "b", "c"]
arr.each(println) // no error
println(try? arr.each(fail)) // outputs Err(Failure)
}
The syntax for error polymorphism is (..) -> T?Error
. At the call site, ?Error
can be replaced with an actual error type, or it can be elided to represent a case where no error may occur.
Specifically, in the example above,
- If the argument
f
does not throw,?Error
will be replaced with "no error", and the entireeach
call will not throw either. - If
f
throws an error, then?Error
will be replaced with the actual error type off
, and the entireeach
call will throw the same type of error.
4. Deprecation of fn meth(self: T)
as Both Method and Functionβ
Previously, methods defined in the form fn meth(self: T)
acted as both methods and regular functions, and could be invoked using either meth(..)
or @pkg.meth(..)
.
This behavior treating methods as regular functionsis now deprecated. The compiler will issue a warning when such usage is detected.
As a result of this change, the recommended API design is:
-
Always define methods using the form fn
T::meth(..)
. Avoid usingfn meth(self: T)
in new code. (This syntax itself may be removed in the future.)- Any API that is associated with a specific type should be defined as a method, unless there is a compelling reason not to.
5. The dot syntax now supports anonymous functions using _
, written as _.meth(..)
.β
At the same time, the right-hand side of the pipe operator |>
also supports this form of anonymous method calls.
When using this syntax, it's important to ensure that the type of _
can be determined from the context; otherwise, the method cannot be resolved.
Example:
fn main {
let array_of_array = [ [], [ 1 ], [ 1, 2 ] ]
let lens = array_of_array.map(_.length())
lens |> _.each(println)
}
Compared with writing x.meth(..)
directly, the advantage of x |> _.meth(..)
is that it allows method calls to be embedded into an existing pipeline.
For example: x |> regular_func(..) |> _.meth(..)
.
6. In method declarations using the fn TypeName::meth(..)
β
you can use Self
to refer to TypeName
, which helps shorten the type signature.
type MyLongTypeName Int
fn MyLongTypeName::to_string(x : Self) -> String {
x._.to_string()
}
If TypeName
has parameters, using Self
will also require those parameters to be provided.
7. The behavior of implementing trait
via method definitions has been officially removed.β
8. The position of type parameters in function declarations has been changed from fn f[..]
to fn[..] f
, making it consistent with impl
.β
This change can be automatically migrated using the formatting tool.
9. The format of methods in .mbti
files generated by moon info
has changed.β
Previously, all methods were merged into a single large impl
block.
Now, each method is listed individually in .mbti
, consistent with MoonBit's own syntax.
10. The syntax for asynchronous functions has been adjusted back to async(..) -> T
, and !Async
syntax (used for error handling and async) has been removed due to incompatibility.β
This change can also be automatically migrated using the formatting tool.
11. The literal suffix for Float
types now supports .314f
.β
Standard Library Updatesβ
- The
Show::output
implementation forChar
has changed. Now, all non-printable characters will be escaped, including: Control, Format, Surrogate, Private Use, Unassigned, and Separator (except space).
Toolchain Updatesβ
- A single
.mbt.md
file now supports external dependencies.
Usage example:
---
moonbit:
deps:
moonbitlang/x: 0.4.23
# moonbitlang/x:
# path: "/Users/flash/projects/x" # local deps
backend:
js
---