Skip to content

Migrating to v0.1.5

Returning an any from a function declared with another type checks the value

A function declared to return a type other than any used to hand an any value through to its caller unchecked, whatever the value held. The value is now checked on the way out, and a value of the wrong type raises bad_downcast.

This affects you if a function returns an any, such as the result of json_parse, from a function declared with a narrower type, and the value can hold something else. This used to print x and now stops with Cannot read this string value as int:

fn count(text: string) -> int {
    return json_parse(text);
}

fn main() {
    print(count("\"x\""));
}

Catch the error where a wrong value is expected:

fn main() {
    try {
        print(count("\"x\""));
    } catch "bad_downcast" {
        print("not a number");
    }
}

Or declare the function -> any and check the value in the caller:

fn count(text: string) -> any {
    return json_parse(text);
}

fn main() {
    let value = count("\"x\"");
    if is_int(value) {
        print(as_int(value) + 1);
    } else {
        print("not a number");
    }
}

A call has the type its function declares, not the type its body returns

A call used to take the type of the value the function's body returns, even when the function declared something wider. It now takes the declared return type. A function declared -> any therefore gives its callers an any, even when every return in it is an int.

This affects you if a function declares a wider return type than it returns and a caller uses the result as the narrower type. That code no longer compiles:

fn limit() -> any {
    return 10;
}

fn main() {
    print(limit() + 1); // Cannot perform operation any + int
}

Declare the type the function returns:

fn limit() -> int {
    return 10;
}

Or, where the function has to stay -> any, downcast at the call:

fn main() {
    print(as_int(limit()) + 1);
}

A generic function declared to return a type parameter the call leaves unbound still takes the type its body returns.

Rebuild your .cdlb artifacts: the artifact format is now version 14

The .cdlb format moved from version 12 to version 14. Version 13 added instructions, which renumbers the ones after them, and version 14 added the machine code sections and the function table a release build now writes.

This affects you if you ship or keep .cdlb files built by candela 0.1.4 or earlier. The new candela-vm, and load_program in an embedding host, refuse them:

candela-vm: unsupported .cdlb format version 12 (this runtime understands version 14)

Rebuild each artifact from its source with the new toolchain:

candela build game.cdl

An embedding host that builds artifacts with build_bytecode needs no code change; rebuild the artifacts it wrote before the upgrade.