The cweet programming language aims to be a safer, more expressive alternative to the C programming language. It has:

Statement Expressions

Statement expressions allow us to rewrite a sequence of statements computing a value as an expression.

// if-else as expressions.
var max = if (a > b) a else b;

// A block of code as an expression.
var sum: [100][100]int = do {
    var r = undefined;
    loop for (var i; 0 ..^ r.len[0]) {
        loop for (var j; 0 ..^ r.len[1]) {
            r[i][j] = i+j;
    r; // value of the block.

Lambda Syntax

Lambda syntax allows writing short-lived functions without giving them a name. Lambda functions can access their environment if they can be inlined into the environment.

alias string_proc = :&fn(: string): void;

fn with_input_string(inline f: string_proc): void
    var s = readline();

fn main(): int
    with_input_string(\s => do {
        import io (print, println);
        print("Hello ");
    return 0;

Type Inference

Types of function parameters and return value have to be explicit. Types of other values are inferred.

fn foo(): int
    var y = undefined;
    with (
        var primes = [2, 3, 5, 7, 11];
        y = 0;
    ) loop for (var p; primes[..]) {
        y += p;
    return y;

Pattern Matching

choice types provide tagged unions in the language ensuring that the programmer does not incorrectly access invalid fields. The match construct can be used to destructure objects by pattern matching.

// Tagged discriminative unions.
choice Netstatus {
    Connected{ip: [4]byte},

// import data constructors.
using type Netstatus;

// match expression.
var desc = match (status) {
    Connected{...} => "connected",
    Disconnected   => "disconnected",

Scope Guards

Scope guards allow code that deallocates a resource to be close to code that allocates the resource and ensures proper cleanup.

fn copy(from, to: string): void
    var f1 = open(from, "r");
    scope (exit) { close(f1); }
    var f2 = open(to, "w");
    scope (exit) { close(f2); }
    with (
        var buf: [1024]char = undefined;
        var n = undefined;
    ) loop while (
        do {
            n = read(f1, buf[..]);
            n > 0;
    ) {
        write(f2, buf[..^n]);

Error Handling

An expression that has type T|Error (T or Error) may produce a value of type T or cause an error.

extern fn sqrt(a: double): double|Error;

fn len(v: [2]double): double
    return sqrt(
        v[0]*v[0] +
    )!; // Ignore error.

fn maxsqrt(a, b: double): double|Error
    // Propagate error.
    var aa = sqrt(a)^;
    var bb = sqrt(b)^;
    return if (aa > bb) aa else bb;

fn maxsqrt1(a, b: double): double
    // Handle errors.
    try {
        var aa = sqrt(a)^;
        var bb = sqrt(b)^;
        return if (aa > bb) aa else bb;
    } else {
        panic("sqrt of a negative number.");


Packages facilitate modularity of code and separate compilation. A package interface can be optionally specified which ensures that clients can only use functionality advertised by the interface. Packages can be organized into a hierarchy using namespaces.

// The namespace file.
namespace foo;
package type BAR;
package bar: BAR;

// The package type file specifies an interface.
package type foo.BAR;
type t; // An opaque type.
fn baz(): *t;

// Now the implementation.
// t is opaque and x is inaccessible.
alias t = :int;
var x: int = 0;
fn baz(): *int {
    return &x;

// Using the package.
package client;


fn client() {
    assert(baz() == baz());

Learn More