Casting

cx has no C-style cast syntax. Instead, there are two explicit conversions:

void main() {
    var x = 7;
    println(float(x) / 2); // prints 3.5

    float pi = 3.14;
    println(int(pi)); // prints 3
}

cast converts between pointer types, for example from void* to a concrete pointer type:

import "stdlib.h";

void main() {
    var p = malloc(sizeof(int))!;
    int* numbers = cast<int*>(p);
    *numbers = 42;
    println(*numbers); // prints 42
    free(p);
}

cast reinterprets between pointers (T*), array pointers (T[*]), and references (T&). Any of those may have an optional (T*?, T[*]?, T&?). The pointee type may change:

void main() {
    int x = 42;
    int* ip = &x;
    uint* up = cast<uint*>(ip);
    println(*up); // prints 42

    int[*] ap = cast<int[*]>(ip);
    println(ap[0]); // prints 42

    int& r = cast<int&>(ap);
    println(r); // prints 42
}

cast also converts between pointers and integers in both directions. This supports a uintptr_t-style round trip for inspecting an address; prefer c_size_t when the integer must hold a pointer-sized value:

void main() {
    int x = 42;
    int* p = &x;
    c_size_t address = cast<c_size_t>(p);
    int* q = cast<int*>(address);
    println(q == p); // prints true
}

Casts that don't make sense are rejected at compile time, for example cast<int**>(false). Conversions that are always safe need no syntax at all: integer literals convert to the expected numeric type automatically, and values bind to T& borrow parameters automatically. Forming a T* pointer needs an explicit &, and reading one needs an explicit * (see References).

Implicit conversions

A single-parameter constructor marked implicit converts its argument type. In the example below, a bare 5 works wherever a Counter is expected:

struct Counter {
    int count;

    implicit Counter(int count) {
        this.count = count;
    }
}

void greet(Counter counter) {
    println(counter.count);
}

void main() {
    greet(5); // prints 5
}

Without implicit, constructors never convert: pass Counter(10) explicitly instead of a bare 10.

The other direction works with an implicit method that takes no parameters and returns the target type:

struct Label {
    string text;

    implicit string view() {
        return text;
    }
}

void main() {
    var label = Label("hi");
    string s = label;
    println(s); // prints "hi"
}

Implicit conversions apply when passing arguments, returning values, and initializing or assigning variables.

Conversion precedence

Only one user-declared conversion applies per step, and overloads that match without converting win. If conversions exist in both directions at once, the use is ambiguous and fails to compile.

Projects tune the builtin conversions with warning options such as -Wconversion (see Build system).