W# 0.1.1

A special case is a function you add, not a branch you insert.

W# is a compiled language built on multiple dispatch, for services, tools and long-running processes. Types are inferred rather than declared and checked across the whole program before it builds. Values are unboxed. The collector is built for low pause times.

$ curl -fsSL https://raw.githubusercontent.com/sinisterMage/sharpie/main/install.sh | sh $ sharpie install stable
0Status
1  Status1xx
3  Status2xx
8  Status3xx
12  Status4xx
13    BadRequest400
14    Unauthorized401
15    Forbidden403
16    NotFound404
17    MethodNotAllowed405
18    Conflict409
19    Teapot418
20    TooManyRequests429
21  Status5xx
Type ids are assigned in a preorder walk of the subtype lattice, so every type's subtypes occupy a contiguous range. Asking whether a value is a Status4xx is id - 12 <= 8: one subtract, one unsigned compare.

Dispatch that mostly is not there at run time

When inference pins the arguments, a call lowers to an ordinary direct call with no dispatch code at all. When it cannot, the test is one subtract and one unsigned compare. No vtable, no inline cache, no method-table lookup.

Types you never write and can still rely on

Hindley-Milner inference over the whole program, so fn add(a, b) has a signature rather than a hope. An ambiguous pair of overloads is a compile error, and so is a function that can reach the end of its body without returning a value.

Failure in the type, and it says which

!T carries the error set, inferred from what a function raises or written down as !{NotFound, IoFailed}str and checked. The e bound by catch |e| is worth testing against.

The standard library is W# too

SHA-2, ChaCha20-Poly1305, AES-GCM, X25519, P-256, P-384, RSA, X.509 and TLS 1.3 are all .ws files compiled with your program, monomorphised per use and dropped when nothing calls them. So this fetches a page over a connection W# negotiated itself, and verifies the chain against the root store the machine already has.

What else is in the library

const http = @import("std/http");
const text = @import("std/str");

fn main() i64 {
    const answer = http.get("https://wsharp.io/") catch return 1;
    print_int(answer.code);
    print_int(text.len(answer.body));
    return 0;
}

Threads that share no heap

A worker is an ordinary module. init makes the state, and any function taking that state first is something the worker can be asked to do. Values cross as bytes, so there is no shared collector, no lock on the fast path, and no data race to write.

Workers and the broker

const counter = @import("./modules/counter.ws");

fn main() i64 {
    const orders = @spawn(counter, 0, "orders") catch return 1;
    const total = orders.add(7) catch |e| return 2;
    print_int(total);
    @join(orders) catch return 3;
    return 0;
}

Where to start