Skip to main content

weekly-05-20

· 3 min read

MoonBit is a Rust-like programming language (with GC support) and toolchain optimized for WebAssembly.

Language Update

  • Breaking Change: Rename Array to FixedArray, @vec.Vec to Array
// Before
fn init {
let array : @vec.Vec[Int] = [1, 2, 3]
}
// After
fn main {
let array : Array[Int] = [1, 2, 3]
}
  • Add pattern matching support for Map, HashMap.
    • The type must implement the op_get method, where the key is a native type (Int, Char, String, Bool, etc.), and the value is an Option[T].
    • When matching, the key must be a literal.
    • In { "key": pat }, the pattern pat type is Option[T]. None means "key" does not exist, Some(p) means "key" exists, and p will be used to match the value of this key.
    • The pattern for matching key-value pairs is open: unmatched keys will be ignored even if they exist.
    • Key-value pair patterns will generate optimized code, with each key being queried at most once.
fn main {
let map = @map.Map::[ ("a", 1) ]
match map {
// Match when `map` contains "b",
// and bind the value of "b" in `map` to `y`.
{ "b": Some(y) } => println(y)
// Match when `map` does not contain "b" but contains "a",
// and bind the value of "a" to `k`.
{ "b": None, "a": Some(k) } => println(k)
// The compiler warns that the case { "b": None, "a": None } is not matched.
}
// Output: 1
}
  • Allow omitting the newtype constructor when type information is known.
type A Int

pub fn op_add(self : A, other : A) -> A {
self.0 + other.0 // omit the constructor
}

fn main {
A::A(0) + 1 |> ignore // omit the constructor of 1
let _c : A = 0 + 1 + 2
}

Build System Update

  • Configuration file options are converted to kebab-case (we'll still support snake_case for a while).
{
"is-main": true,
"test-import": []
}
  • Wasm, Wasm-GC: The backend supports specifying the exported memory name (default is moonbit.memory) and compile options (e.g., -no-block-params for compatibility with the Binaryen toolchain) in moon.pkg.json.
{ 
"link": {
"wasm": {
"export-memory-name": "custom_memory_name",
"flags": ["-no-block-params"]
},
}
  • moon check adds a --deny-warn option, treating warnings as failures and returning a non-zero exit code.
  • Optimized the execution speed of moon fmt and moon info.
  • moon fmt adds a --check option to check if the current code is formatted.

Core Update

  • Added an experimental library moonbitlang/x for developing and testing packages with unstable APIs. Once packages in moonbitlang/x are stable, we will select important packages to merge into moonbitlang/core based on community feedback.
    • num, time, uuid, and json5 have all been moved to moonbitlang/x.
  • The Bytes API moved from the Int type to the Byte type.
fn Bytes::op_get(self : Bytes, index : Int) -> Byte
fn Bytes::op_set(self : Bytes, index : Int, value : Byte) -> Unit
fn Bytes::length(self : Bytes) -> Int
fn Bytes::make(len : Int, ~init : Byte = b'\x00') -> Bytes

weekly-05-13

· 4 min read

MoonBit is a Rust-like programming language (with GC support) and toolchain optimized for WebAssembly.

Language Update

  • Support mutable fields in the payload of the constructor, here is how to use it:
enum E {
C(mut ~x : Int, mut ~y : Int)
} derive(Debug)


fn swap_xy(x : E) -> Unit {
match x {
// `~y` will bind to the value of the `y` field in the `C` before pattern matching.
// When encountering a pattern like `C(..) as c`, the compiler will know that `c` must be the constructor,
// so `c.x` and `c.y` can be directly accessed within the branch to access the fields of `C`.
C(~y, ..) as c => {
// `c.x` and `c.y` can be used to modify/read the latest values in `C`.
c.y = c.x
c.x = y
}
}
}

fn init {
let e : E = C(x=1, y=2)
debug(e) // C(x=1, y=2)
swap_xy(e)
debug(e) // C(x=2, y=1)
}

In this example, the swap_xy function swaps the values of the x and y fields of the constructor C, and this swap is done in-place without introducing additional memory allocation.

  • Array literals by default construct vectors. Array literal syntax has been overloaded. Now, array literals can be used to construct Vectors and Arrays, with the specific type determined by the context. If the type is ambiguous in the context, Vector is used by default, for example:
fn init {
let v = [1, 2, 3] // v has type @vec.Vec[Int]
let a : Array[_] = [1, 2, 3] // a has type Array[Int]
}

In the future update, Array will be FixedArray, Vec will be Array.

  • Error messages now include error codes, for example:
./vec/sort.mbt:68:16-68:23 [E4021] The value identifier minimum is unbound.
./vec/sort_by.mbt:90:16-90:23 [E4021] The value identifier minimum is unbound.
./vec/vec.mbt:962:37-962:50 [E4020] Package "iter" not found in the loaded packages.
./vec/vec.mbt:963:3-963:13 [E4024] The type/trait @iter.Iter is not found.

IDE Update

  • Support functionalities like gotodef/gotoref/rename for the labels of labeled fields in constructors, for example: label.PNG

Build System Update

  • Support configuring the warn list and alert list at the package level.
    • Configuration in moon.pkg.json is as follows, where you can disable corresponding warns and alters during compilation. (Here, 2, alter_1, and alert_2 are respectively the compiler's predefined warn id for Unused variable and user-defined alert id.)
{
"warn_list": "-2",
"alert_list": "-alert_1-alert_2"
}
  • - represents closing the corresponding id's warn and alter. Check the predefined warns with moonc build-package -warn-help.

  • The default backend for moon check|build|run|test has been switched from wasm to wasm-gc

  • The default execution mode for moon test has been changed from release to debug.

  • moon check|build|run|test now supports automatic dependency installation without the need to manually execute moon install

  • moon doc --serve now supports specifying the address and port.

-b, --bind <BIND> [default: 127.0.0.1]
-p, --port <PORT> [default: 3000]
  • Optimize moon size.
PlatformBeforeAfter
macOS arm647.3 MiB3.6 MiB
macOS x86_648.2 MiB4.1 MiB
Ubuntu x86_6414.0 MiB9.6 MiB
Windows x86_649.4 MiB4.9 MiB

Toolchain Update

  • moonrun now supports printing backtrace. Sample: Create a new project with moon new hello, and replace main/main.mbt with:
  fn bar() -> Unit {
abort("")
}

fn foo() -> Unit {
bar()
}

fn main {
foo()
}

Execute moon run main --debug, and you will see output similar to:

error: RuntimeError: unreachable
at $username/hello/main.bar.fn/1 (wasm://wasm/6fe99e5e:wasm-function[3]:0xe6)
at $username/hello/main.foo.fn/2 (wasm://wasm/6fe99e5e:wasm-function[4]:0xea)
at *init*/3 (wasm://wasm/6fe99e5e:wasm-function[5]:0xef)
at <anonymous>:9:22

weekly-04-30

· 4 min read

MoonBit is a Rust-like language (with GC support) and toolchain optimized for WebAssembly experience. This is our recent update:

  • MoonBit now supports JavaScript backend, up to 25x faster than native JS and 8x faster than Json5!

Read our latest blog and see how we did it: https://www.moonbitlang.com/blog/js-support

Play with this example and try MoonBit JS now: https://github.com/moonbit-community/benchmark-202404/tree/master/bench_json5

  • MoonBit now allows passing callback functions to FFI. However, the parameters and return types of callback functions are currently limited to simple types such as Int. Example:
// Example: passing a callback to external code
fn set_callback(f : () -> Int) = "ffi" "set_callback"

// Example
fn use_callback() -> Int = "ffi" "use_callback"

test {
let i = { val : 0 }
set_callback(fn () {
i.val += 1
i.val
})
inspect(use_callback(), content="1")?
inspect(use_callback(), content="2")?
inspect(use_callback(), content="3")?
inspect(use_callback(), content="4")?
}
let f

export default {
// Necessary external interface: converting a closure to a JS function. Implementation varies in different runtimes depending on the language.
'moonbit:ffi': {
make_closure: (funcref, context) => funcref.bind(null, context)
},
// Example
ffi: {
set_callback: (func) => {
f = func
}, // Set callback function
use_callback: () => f() // Use callback function
}
}
  • Modified the syntax for explicitly implementing a trait (extension method), allowing explicitly specifying which type is implementing the trait.
// Provide a default implementation for method method of trait Trait
impl Trait with method(...) { ... }

// Implement method method of trait Trait for type Type
impl Trait for Type with method(...) { ... }

// With type parameters
impl[X] Trait for Array[X] with method(...) { ... }

Compared to the previous syntax fn Trait::method(...), the new syntax allows explicit specification of the implementing type, providing richer and clearer signature information. Since the type is specified, the compiler can automatically infer the method's parameter and return types, eliminating the need for manual annotations:

trait MyTrait {
f(Self) -> Option[Int]
}

// No need to annotate `self` and the return type
impl MyTrait for Int with f(self) {
// Compiler can automatically infer that the return type is `Option[Int]`
Some(self)
}
  • Support Bytes literals.

Bytes literals b"..." will convert the ASCII string inside the double quotes to the Bytes type, with support for hexadecimal and octal escapes within the string.

 let b1 : Bytes = b"ASCII"
let b2 : Bytes = b"\xFF\o000"
  • Fixed the issue where { x } is too ambiguous.

Now { x } will be parsed as a struct with only one x field, equivalent to { x: x }. For this potentially confusing syntax, the compiler will issue a warning.

IDE Update

  • Added the option moonbit.autoUpdate in plugins to control whether to enable automatic update prompts.
  • Plugins now support multi-backend development:
    • Users can choose different backends within VSCode.
    • The code diff visibility decreases for non-current backends.

plugins.gif

Build System Update

  • Support for backend-specific files, where these files have extensions named with .wasm|wasm-gc|js.mbt, for example: foo.wasm.mbt, foo.wasm-gc.mbt, foo.js.mbt. For instance, in moon build --target js, only regular .mbt files and .js.mbt files will participate in the build. Accordingly, modifications have been made to moon check|build|test and the linking process in moonbitlang/core to be backend-specific.
  • In the moon.pkg.json file, a new format field is added to ["link"]["js"], used to specify the output JavaScript module format. Possible values are esm|cjs|iife, with the default being esm.
    • In esm mode, export { x as y } statements are used for exporting.
    • In cjs mode, exports.y = x is used for exporting.
    • In iife mode, globalThis.y = x is used for exporting.

Example moon.pkg.json:

{
"link": {
"js": {
"exports": [
"hello"
],
"format": "cjs"
}
}
}

  • moon test -u now supports automatically updating multiple inspect functions within test blocks, and adds the -limit option to restrict the maximum number of iterations for automatic updates.

Toolchain Update

  • moonrun has switched from wasmtime to V8, now supporting the wasm-gc backend.
moon new hello
cd hello
moon run main --target wasm-gc
  • moon info update
    • Support grouping methods to facilitate comparison between implementations of different data structures.
    • Support tagged parameters, default parameters, and automatic parameter filling.
type Map
impl Map {
debug_write[K : Debug, V : Debug](Self[K, V], Buffer) -> Unit
elems[K, V](Self[K, V]) -> List[V]
fold[K, V, T](Self[K, V], (T, V) -> T, ~init : T) -> T
from_array[K : Compare + Eq, V](Array[Tuple[K, V]]) -> Self[K, V]
// ...
}

weekly-04-22

· 4 min read

MoonBit is a Rust-like language (with GC support) and toolchain optimized for WebAssembly experience. This is our recent update:

Language Update

  • The standard library has added the Iter type, which efficiently accesses elements in a container and optimizes the access process into a loop. Here's an example of how to use it:
test "iter" {
let sum = Iter::[1, 2, 3, 4, 5, 6]
.filter(fn { x => x % 2 == 1 })
.take(2)
.map(fn { x => x * x})
.reduce(fn (x, y) { x + y }, 0)
inspect(sum, content="10")?
}
  • A VecView type has been added to the standard library, and you can obtain its VecView[T] for values of type Vec[T] using the following method.
test "view" {
let v = Vec::[1, 2, 3, 4, 5]
let vv1 = v[..]
let vv2 = v[1..]
let vv3 = v[..4]
let vv4 = v[1..4]
inspect(vv1, content="VecView::[1, 2, 3, 4, 5]")?
inspect(vv2, content="VecView::[2, 3, 4, 5]")?
inspect(vv3, content="VecView::[1, 2, 3, 4]")?
inspect(vv4, content="VecView::[2, 3, 4]")?
}
  • The array pattern supports the form [a, .. as rest, b], where rest will be bound to a VecView.
test "view_pattern" {
fn is_palindrome(s: VecView[Int]) -> Bool {
match s {
[] => true
[_] => true
[x, .. as rest, y] => x == y && is_palindrome(rest)
}
}
let v1 = Vec::[1, 2, 3, 4, 5]
@assertion.assert_false(is_palindrome(v1[..]))?
let v2 = Vec::[1, 2, 3, 2, 1]
@assertion.assert_true(is_palindrome(v2[..]))?
}
  • Allow the omission of the tilde ~ inside tags when calling tag parameters, for example:
inspect(1, content="1")
  • Constructor now supports labelled arguments:
enum Tree[X] {
Nil
Branch(X, ~left : Tree[X], ~right : Tree[X])
}

fn leftmost[X](self : Tree[X]) -> Option[X] {
loop self {
Nil => None
// use `label=pattern` to match labelled arguments of constructor
Branch(top, left=Nil, right=Nil) => Some(top)
// `label=label` can be abbreviated as `~label`
Branch(_, left=Nil, ~right) => continue right
// use `..` to ignore all remaining labelled arguments
Branch(_, ~left, ..) => continue left
}
}

fn init {
// syntax for creating constructor with labelled arguments is the same as callig labelled function
let t: Tree[Int] = Branch(0, right=Nil, left=Branch(1, left=Nil, right=Nil))
println(t.leftmost()) // `Some(1)`
}
  • The default value of optional parameters can depend on preceding parameters, for example:
fn f(~x: Int = 1, ~y: Int = x) -> Int {
x + y
}
  • Byte literals support octal escapes.

Byte.PNG

IDE Update

  • IDE supports test codelens for local environments and automatic updates for expect tests.

test-codelens.GIF

  • Fixed an issue where the online IDE couldn't find core on Windows.

  • Support for identifying test_import and *_test.mbt files.

Toolchain Update

  • moonfmt

    • Fixed an issue where escape sequences in String and Char literals were not formatted correctly.
    • Adjusted formatting for { ..record }
  • moon info and moon coverage now support Windows.

  • moon info supports shortening type names when it doesn't cause ambiguity, making the generated results cleaner. - Hide the builtin package name prefix when there is no type definition with the same name. - Use the last part of the package name instead of the full package name when there is no ambiguity. Before:

package moonbitlang/core/map

// -- snip --

type Map
fn Map::debug_write[K : @moonbitlang/core/builtin.Debug, V : @moonbitlang/core/builtin.Debug](Map[K, V], @moonbitlang/core/builtin.Buffer) -> Unit
fn Map::keys_set[K : @moonbitlang/core/builtin.Compare + @moonbitlang/core/builtin.Eq, V](Map[K, V]) -> @moonbitlang/core/immutable_set.ImmutableSet[K]
fn Map::lookup[K : @moonbitlang/core/builtin.Compare + @moonbitlang/core/builtin.Eq, V](Map[K, V], K) -> Option[V]
fn Map::to_vec[K, V](Map[K, V]) -> @moonbitlang/core/vec.Vec[Tuple[K, V]]

After:

package moonbitlang/core/map

alias @moonbitlang/core/immutable_set as @immutable_set
alias @moonbitlang/core/vec as @vec

// -- snip --

type Map
fn Map::debug_write[K : Debug, V : Debug](Map[K, V], Buffer) -> Unit
fn Map::keys_set[K : Compare + Eq, V](Map[K, V]) -> @immutable_set.ImmutableSet[K]
fn Map::lookup[K : Compare + Eq, V](Map[K, V], K) -> Option[V]
fn Map::to_vec[K, V](Map[K, V]) -> @vec.Vec[Tuple[K, V]]

Build System Update

  • moon test adds options related to test filtering:
-p, --package <PACKAGE_NAME>  Run test in the specified package
-f, --file <FILE> Run test in the specified file, only valid when --package is specified
-i, --index <INDEX> Run the index-nth test in the specified file, only valid when --file is specified

Command example: moon test -p username/hello/A -f hello.mbt -i 0 (runs the 0th test block in the hello.mbt file in the username/hello/A package); -f and -i are effective only when specified with -p; if -f is not specified, all tests in the package specified by -p will be run, and if -i is not specified, all tests in the file specified by -f will be run.

  • moon check|build|test adds the -sort-input option for generating stable build orders.

  • The ~content= generated by expect tests omits the ~ and is changed to content=.

weekly-04-15

· 2 min read

MoonBit is a Rust-like language (with GC support) and toolchain optimized for WebAssembly experience. This is our recent update:

Core Update

We have received 221 Repositories to MoonBit core since its open source in March, with 26 excellent contributors contributing about 10,000 lines of code of high quality. Thanks a lot for your passion and support for MoonBit!

0.PNG

Language Update

  • Expanded array patterns in pattern matching.

    • Support the vec type in the standard library.
    • Support for generic types [a, .., b].
    fn main {
    let xs = @vec.from_array([1, 2, 3])
    match xs {
    [1, .., 3] => { println("ok")}
    _ => println("not ok")
    }
    // Output: ok
    }

IDE Update

  • Changed the printing output of the online IDE from the Output channel to the terminal. Fixed the issue where the printing output was occasionally truncated in Firefox browsers. ANSI escape sequences can be used in browser code, for example:

1.PNG

  • Support autocompletion in the form of x |> @pkg.

1.5.PNG

  • Disabled inlay hint for matrix functions.

Before

2.PNG

After

3.PNG

Toolchain Update

  • Added (experimental) test coverage tools. (*Windows is not supported at the moment)

    • Added -enable-coverage option to moon test for enabling coverage during runtime.
    • Added moon coverage command for reading and processing coverage data.
      • After testing, moon coverage report -f <format> can be used to output coverage data. Supported output formats include:
        • bisect (default output format of OCaml Bisect tool)
        • html (output result webpage)
        • coveralls (JSON format suitable for CodeCov and Coveralls tool upload)
        • summary (output summary in the terminal) More functionalities can be viewed through moon coverage report -h.
      • moon coverage clean command can be used to clean up previous coverage data output.
  • The build system has added the moon info command for generating public interface files of software packages. (*Windows is not supported at the moment) Example:

    $ moon new hello
    $ cd hello
    $ moon info
    $ cat lib/lib.mbti
    package username/hello/lib

    // Values
    fn hello() -> String

    // Types and methods

    // Traits

    // Extension Methods
    ```

  • Fixed the issue where the annotation was misaligned caused by trailing commas in moonfmt.

  • Fixed the issue where file paths cannot contain spaces in moon.

weekly-04-08

· One min read

MoonBit Update

  • Support array.iter intrinsic and annotate functions in the standard library, enabling inline loops in specific cases to improve runtime efficiency.

    /// @intrinsic %array.iter
    pub fn iter[T](self : Array[T], f : (T) -> Unit) -> Unit {
    for i = 0; i < self.length(); i = i + 1 {
    f(self[i])
    }
    }

Toolchain Update

  • Support the experimental code coverage tool:
    • The tool has experimentally supported MoonBit Core CI.
    • We are optimizing the user-facing interface.

image

image

  • By default, the unsafe/throw/raise warnings in Alerts pragmas are turned off, while deprecated alerts are enabled.
  • moonfmt
    • Fixed an issue where comments were misaligned after printing literals with negative signs.
    • Fixed an issue where parentheses disappeared after printing literals with negative signs.
  • Fixed variable highlighting.
  • moonrun now supports printing UTF-16 strings.

Build System Update

  • expect test now supports Unicode characters.

image

weekly-04-01

· 4 min read

MoonBit Update

  • inspect function added for the Show interface in expect testing with the following signature:
pub fn inspect(
obj : Show,
~content : String = "",
~loc : SourceLoc = _,
~args_loc : ArgsLoc = _) -> Result[Unit, String]

⚠️ This API is currently unstable and may be changed to the expect function in the future.

For example, in the following code:

fn add(x: Int, y: Int) -> Int {
x + y
}

test {
inspect(add(1, 2))?
}

test {
(add(3, 4) |> inspect)?
}

After executing moon test -u, the file is automatically updated to:

fn add(x: Int, y: Int) -> Int {
x + y
}

test {
inspect(add(1, 2), ~content="3")?
}

test {
(add(3, 4) |> inspect(~content="7"))?
}

  • Move compiler builtins to moonbitlang/core

Some fundamental MoonBit definitions, previously maintained inside the MoonBit compiler, is now migrated to moonbitlang/core

  • Alert pragma supported

MoonBit now supports writing multiple pragma in the top-level doc comments. All pragma start with @ and occupy a line by themselves.

Untitled

Currently, function and method alert pragma are supported. If functions or methods marked with alert are used, a warning will be generated. This mechanism can be used to mark functions as deprecated or unsafe. The format for alert pragmas is @alert id "explanation string", where id can be any identifier.

Untitled

  • Supported marking intrinsics in pragmas. For example, after the following code in the standard library was marked as intrinsic, the JavaScript backend would use the String(..) function to convert floating-point numbers into strings. We will add support for more functions as intrinsics in the future.
/// @intrinsic %f64.to_string
pub fn to_string(self : Double) -> String {
double_to_string(self)
}

  • Added ArgsLoc, used to automatically insert the position of each argument in the source code.
fn test_args_loc(a: Int, b: Int, ~args_loc : ArgsLoc = _) -> Unit {
println(args_loc)
}

fn init {
test_args_loc(1, 2)
// Output: [Some(path/to/xx.mbt:6:17-6:18), Some(path/to/xx.mbt:6:20-6:21), None]
}

  • Improved the completeness check for pattern matching.

  • Improved moonfmt

    • Adjusted the print format for function for loops; semicolons are no longer printed in special cases.
    • For cases of poor readability due to nested if/match, extra parentheses were added after formatting. The effects before and after formatting are as follows:

    Untitled

Untitled

  • Enhanced the performance and size of the generated code.
    • Introduced optimizations to eliminate local aliases, thus avoiding the generation of unnecessary local variables.
    • Introduced constant propagation optimizations.
    • Optimized the type declaration part of the generated wasm code, reducing redundant type declarations.
  • Adjusted string encoding to UTF-16.

IDE Update

  • The VSCode plugin supported installing or updating the MoonBit toolchain.

Untitled

Build System Update

  • Supported custom function export names in the moon.pkg.json file using the ["link"][BACKEND]["exports"] field, and by default, not all pub functions are exported anymore. It is now required to explicitly specify them in the exports. Additionally, linking non-main packages through the link field is now supported.

For example, creating a new project with moon new hello results in the following directory structure:

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

In the past, executing moon build would only generate a wasm file for the main package. Now, the link field in moon.pkg.json supports generating wasm files for non-main packages. The link field can be a boolean value:

{
"link": true // Indicates that the current package needs to be linked
}

Or an object, which allows setting link options for different backends like wasm or wasm-gc. Currently, only the exports option is supported. Exports is an array of strings that includes the functions to be exported and their names:

{
"link": {
"wasm": {
"exports": [
"hello" // This exports the function hello as hello
]
},
"wasm-gc": {
"exports": [
"hello:hello_wasm_gc" // This exports the function hello as hello_wasm_gc
]
}
}
}

If the content of lib/moon.pkg.json is modified to:

{
"link": {
"wasm": {
"exports": [
"hello"
]
}
}
}

Then executing moon build --output-wat, the output in target/wasm/release/build/lib/lib.wat will include the following content:

(func $username/hello/lib.hello.fn/1 (export "hello") (result i32)
(i32.const 10000))

Where (export "hello") indicates the configuration took effect.

weekly-03-25

· 2 min read

Build System Updates

  1. Added support for expect testing. a. Use moon new to create a new MoonBit project. b. Write in lib/hello.mbt:
pub fn hello() -> String {
"Hello, world!"
}

test {
let buf = Buffer::make(10)
buf.write_string(hello())
buf.expect()?
}

c. Then run moon test --update or moon test -u:

$ moon test --update
expect test failed at lib/hello.mbt:8:3-8:15
Diff:
----
Hello, world!
----

Total tests: 1, passed: 0, failed: 1.

Auto updating expect tests and retesting ...

Total tests: 1, passed: 1, failed: 0.

d. Reopen the lib/hello.mbt file, and you can see that the test result has been promoted to the source code.

pub fn hello() -> String {
"Hello, world!"
}

test {
let buf = Buffer::make(10)
buf.write_string(hello())
buf.expect(~content="Hello, world!")?
// ^~~~~~~~~~~~~~~~~~~~~~~~ Test result updated
}

  1. moon run no longer supports the output-wat option.

MoonBit Update

  1. Supported the backend code generation for multi-argument constructors. Now, when constructing a value of a generic type, if the generic parameter is a tuple, parentheses must be used to first explicitly construct a tuple, as in:

    enum A[X] {
    A(X)
    }

    fn init {
    // Error, expecting 1 arg, getting 2
    A::A(1, 2) |> ignore

    // Ok
    A::A((1, 2)) |> ignore
    }

    Multi-argument constructors unbox the parameters, which can improve the performance of the generated code and also allow programmers to have more control over the data's memory layout.

  2. Adjusted the lsl, lsr, asr methods of Int64, now the shift parameter is no longer Int64, but Int. Also adjusted the clz, ctz, popcnt methods, now their return type is no longer Int64, but Int. This change helps us generate more efficient code on platforms that do not support native Int64.

IDE Update

  1. Supported renaming of labeled arguments.
  2. The MoonBit VSCode plugin provides support for automatically installing or upgrading the MoonBit toolchain.

a. First, updating the plugin. If Moon is not installed or outdated, a notification will pop up to you to install or upgrade your MoonBit toolchain.

Untitled

b. Click "yes" to start the automatic installation task. When the task is completed, your MoonBit toolchain will be installed or upgraded to the latested version.

Untitled

weekly-03-18

· 3 min read

MoonBit is a Rust-like language (with GC support) and toolchain optimized for WebAssembly experience. This is our recent update:

Language Update

1. Experimental support for default method in trait

trait MyShow {
repr(Self) -> String
str (Self) -> String // it has a default implementation
}

impl MyShow::str(self : Self) -> String {
// default implementation of str
self.repr()
}

type MyInt Int
fn repr(self:MyInt) -> String {
self.0.to_string()
}
// Now MyInt implements MyShow now

2. The type parameters of type definitions can be _, which can be used to define phantom types to restrict some logically illegal operations in the program. For example, we want to prevent adding lengths of different units together:

type Length[_] Int

type Kilometer
type Mile

fn add[T](x: Length[T], y:Length[T]) -> Length[T] {
Length::Length(x.0 + y.0)
}

let d_km: Length[Kilometer] = Length(10)
let d_mile: Length[Mile] = Length(16)

At this point, lengths with different units cannot be directly added:

fn init {
add(d_km, d_mile) |> ignore
// ^~~~~~ Error: Expr Type Mismatch
}

However, lengths with the same units can be added:

fn init {
add(d_km,d_km) |> ignore
// OK
}

3. Now, a top-level function without a marked return value is an error.

fn print_hello() {
// ^~~~~~~~~~~ Error:
// Missing type annotation for the return value.
println("Hello!")
}

4. Added the bitwise NOT operator.

fn main {
println((1).lnot())
}

Output:

-2

5. Improved the output of List::to_string/debug_write.

fn main {
let l = List::Cons(1, Cons(2, Cons(3, Nil)))
println(l)
}

Output:

List::[1, 2, 3]

6. Added the Byte type.

The byte literals are prefixed by b. The following snippet demonstrates its usage:

fn init {
let b1 = b'a'
println(b1.to_int())
let b2 = b'\xff'
println(b2.to_int())
}

More utility methods on Byte type are around the corner.

IDE Update

1. Added support for autocompletion of moonbitlang/core.

2. Formatting Update:

a. Adjust empty structs, enums, and traits to avoid blank lines.

Before:

struct A {

}

After:

struct A {}

b. Fixed incorrect indentation for continue c. Fixed issues with semicolons appearing after formatting multiline statements

Build System Update

1. Added the test_import field to moon.mod.json, which contains dependencies that are only used during testing.

2. Optimized the output of moon test; by default, it now only outputs information for failed test cases. Use the moon test -v command for complete output.

weekly-03-11

· 4 min read

MoonBit Update

  1. moonbitlang/core is now open-source at https://github.com/moonbitlang/core. We are thrilled to receive positive feedback from the community. To learn more about the moonbitlang/core open source details, click here: https://www.moonbitlang.com/blog/moonbitlang-core-opensource

  2. MoonBit now supports labeled argument and optional argument. Labelled arguments are useful for distinguishing different parameters of the same type in a function:

    fn greeting(~name: String, ~location: String) {
    println("Hi, \(name) from \(location)!")
    }

    fn init {
    greeting(~name="somebody", ~location="some city")
    let name = "someone else"
    let location = "another city"
    // `~label=label` can be abbreviated as `~label`
    greeting(~name, ~location)
    }

    Optional arguments must be labelled, and you must specify a default value when declaring an optional parameter. When the function is called, if no argument is explicitly provided, the default value will be used. Note: the default value expression will be evaluated on every function call:

    fn greeting(~name: String, ~location: Option[String] = None) {
    match location {
    Some(location) => println("Hi, \(name)!")
    None => println("Hi, \(name) from \(location)!")
    }
    }

    fn init {
    greeting(~name="A") // Hi, A!
    greeting(~name="B", ~location=Some("X") // Hi, B from X!
    }

  3. A new builtin type SourceLoc is added, representing source code location. If a function declares an optional parameter of type SourceLoc with _ as default value, MoonBit will automatically inject the location of call site when calling this function:

    fn f(~loc : SourceLoc = _) {
    println("called at \(loc)")
    }

    fn g(~loc : SourceLoc = _) {
    f() // show the position inside `g`
    f(~loc) // autofilled arguments can be manually overidden:
    // this call should show the location of the caller of `g`
    }

    test "source loc" {
    g()
    }

    Paste the above code into a new file called test.mbt at try.moonbitlang.com, and run the test "source loc", you should see the following output:

    test source loc ...
    called at memfs:/sample-folder/test.mbt:6:3-6:6
    called at memfs:/sample-folder/test.mbt:11:3-11:6

    SourceLoc can be used to write test utilities, providing handful location information when tests fail:

    fn assert_eq[X: Eq + Show](result: X, expect: X, ~loc : SourceLoc = _) -> Result[Unit, String] {
    if (result == expect) {
    Ok(())
    } else {
    Err("\(loc): Assertion failed: \(result) != \(expect)")
    }
    }

    test "1 =? 2" {
    assert_eq(1, 2)?
    }

    running 1 tests
    test 1 =? 2 ... FAILED memfs:/sample-folder/test.mbt:10:3-10:18: Assertion failed: 1 != 2

    test result: 0 passed; 1 failed

  4. === has been deprecated; please use physical_equal as its replacement.

  5. A new builtin type UnsafeMaybeUninit[T] and a few related builtin primitives have been added to support implementing high performance data structures, like vectors, in the MoonBit Core. Because they are unsafe, regular MoonBit programs are not expected to use them.

IDE Updates

  1. The online IDE now supports running tests via CodeLens.

  1. Significantly improved how moonfmt handles source code with comments.

  2. Enhanced stability and user experience for the IDE and VSCode plugin.

    a. The VSCode plugin now invokes moon check on file changes rather than starting moon check -w.

    b. Improved the typing experience for multi-line strings and docstrings. Now, inserting a line break inside a multi-line string/docstring automatically prefixes it with #| or ///.

    c. Fixed issues with hover, errors in moon.pkg.json, empty files, etc., that caused lsp errors.

Build System Update

Fixed several issues with moonbuild.

a. Fixed an issue where moon upgrade failed on Windows.

b. Fixed an issue where moon add did not remove the old version when adding a new version.

c. Fixed an issue where moon check could fail locally but still allow publishing.

Toolchain Update

Markdown linter now supports expr tags.

```moonbit expr
1 * 2 + 3
```

You can see the corresponding output when running mdlint:

5