Hello, Hot Reloading!

Mun distinguishes itself from other languages by its inherent hot reloading capabilities. The following example illustrates how you can create a hot reloadable application by slightly modifying the Hello, fibonacci? example. In Listing 1-2, the fibonacci_n function has been removed and the pub keyword has been added to both args and fibonacci.

Filename: hello_fibonacci.mun

pub fn arg() -> i64 {
    5
}

pub fn fibonacci(n: i64) -> i64 {
    if n <= 1 {
        n
    } else {
        fibonacci(n - 1) + fibonacci(n - 2)
    }
}

Listing 1-2: A function that calculates a fibonacci number

Apart from running Mun libraries from the command-line interface, a common use case is embedding them in other programming languages.

Mun embedded in C++

Mun exposes a C API and complementary C++ bindings for the Mun Runtime. Listing 1-3 shows a C++ application that constructs a Mun Runtime for the hello_fibonacci library and continuously invokes the fibonacci function and outputs its result.

Filename: main.cc

#include <iostream>

#include "mun/runtime.h"

int main() {
    if (argc < 2) {
        return 1;
    }

    auto lib_path = argv[1];
    if (auto runtime = mun::make_runtime(lib_path)) {
        while (true) {
            auto arg = mun::invoke_fn<int64_t>(*runtime, "arg").wait();
            auto result =
                mun::invoke_fn<int64_t>(*runtime, "fibonacci", arg).wait();
            std::cout << "fibonacci(" << std::to_string(arg) << ") = " << result
                      << std::endl;

            runtime->update();
        }
    }

    return 2;
}

Listing 1-3: Hello, Fibonacci? embedded in a C++ application

Mun embedded in Rust

As the Mun Runtime is written in Rust, it can be easily embedded in Rust applications by adding the mun_runtime crate as a dependency. Listing 1-4 illustrates a simple Rust application that builds a Mun Runtime and continuously invokes the fibonacci function and prints its output.

Filename: main.rs

extern crate mun_runtime;
use mun_runtime::{invoke_fn, RetryResultExt, RuntimeBuilder};
use std::{cell::RefCell, env, rc::Rc};

fn main() {
    let lib_path = env::args().nth(1).expect("Expected path to a Mun library.");

    let mut runtime = RuntimeBuilder::new(lib_path)
        .spawn()
        .expect("Failed to spawn Runtime");

    loop {
        let arg: i64 = invoke_fn!(runtime, "arg").wait();
        let result: i64 = invoke_fn!(runtime, "fibonacci", arg).wait();
        println!("fibonacci({}) = {}", arg, result);
        runtime.borrow_mut().update();
    }
}

Listing 1-4: Hello, Fibonacci? embedded in a Rust application

Hot Reloading

The prior examples both update the runtime every loop cycle. In the background, this detects recompiled code and reloads the resulting Mun libraries.

To ensure that the Mun compiler recompiles our code every time the hello_fibonacci.mun source file from Listing 1-2 changes, the --watch argument must be added:

mun build hello_fibonacci.mun --watch

When saved, changes in the source file will automatically take effect in the running example application. E.g. change the return value of the arg function and the application will log the corresponding Fibonacci number.

Some changes, such as a type mismatch between the compiled application and the hot reloadable library, can lead to runtime errors. When these occur, the runtime will log the error and halt until an update to the source code arrives.

That's it! Now you are ready to start developing hot reloadable Mun libraries.