Learn

From nothing to a live graph.

Seven steps. By the end you will have a native binary, a reactive counter, and a page that repaints itself when a row changes in the database — with no fetch call anywhere in your source.

  1. Install the compiler

    LukeLang builds from source with a C++17 compiler and make. There is nothing else to fetch for the core language.

    git clone https://github.com/lucasdmarshall/LukeLang.git
    cd LukeLang/vm && make

    That produces vm/build/luke. Full platform notes and the optional dependencies live on the download page.

  2. Write your first program

    Save this as hello.luke. Files ending in .luke or .lk use syntax v2.

    print("Hello from Luke Build")
    let name = "Luke"
    print("My name is " + name)

    Then build it into a native binary and run it:

    ./build/luke BUILD hello.luke -o hello
    ./hello

    Three ways to run. BUILD compiles to native C or WebAssembly with no garbage collector. SHOW builds when it can and falls back to the bytecode VM. SHOW … --vm forces the VM, which is the compatibility layer.

  3. Values and functions

    let binds a value you will not reassign; var binds one you will. Types are optional where the compiler can infer them and required where it cannot — most often around +, which is both arithmetic and concatenation.

    let a = 21
    var total: float = 0
    
    fn add(x: float, y: float) -> float {
      return x + y
    }
    
    total = add(a, 21)
    print(total)          // 42

    Control flow uses braces: if, while, and return. Comparisons and boolean operators are the ones you expect (==, !=, <, &&, ||, !).

  4. Structs, methods and inheritance

    A struct is a blueprint: fields with types or initialisers, an init constructor, and methods. self is the instance; super reaches the parent.

    struct Animal {
      name: str
      sound = "…"
      init(name: str) {
        self.name = name
      }
      fn speak() {
        print(self.name + " says " + self.sound)
      }
    }
    
    struct Dog : Animal {
      sound = "Woof!"
      fn speak() {
        super.speak()
        print(self.name + " wags happily.")
      }
    }

    Instances live in an arena that is released at scope exit — there is no garbage collector on the Build path.

  5. Reactive cells

    This is where LukeLang stops looking like other languages. A signal is a cell. A derived value recomputes when its inputs change. An effect runs when the cell it names changes. You never subscribe and never unsubscribe.

    signal price = 100
    signal quantity = 3
    derived total = price * quantity
    
    effect on total {
      print("total=" + total)
    }
    
    price = 200              // total=600
    
    batch {
      price = 120
      quantity = 5           // still a single flush
    }

    The engine deduplicates work, keeps flush order stable, isolates a failing effect from its neighbours, and disposes cells with their scope. Those guarantees are written down in the reactive specification and enforced by fourteen conformance programs in the test suite.

  6. Follow a row to a pixel

    The same cell model spans the network. On the server, a cell can be backed by a database row and pushed to a client. On the client, a cell can be backed by that stream and bound to an element.

    Server

    import std/server
    import std/sqlite
    
    let db = dbOpen("/tmp/luke_live_graph.db")
    watch user from db where "id = 1"
    
    let server = httpListen(8798)
    let req = httpAccept(server)
    push watch user on req for 50 beats every 50 ms

    Client

    import std/js
    
    signal user = ""
    bind("name", user)
    watch user from "http://127.0.0.1:8798/watch"

    Run an UPDATE against that row from any other process and the browser repaints one region. There is no fetch, no cache key, no subscription bookkeeping and no virtual DOM diff in that path — read Live Graph for how the wire and the incremental view maintenance work.

  7. Ship it

    One source, three targets:

    # native binary
    ./build/luke BUILD app.luke -o app
    
    # WebAssembly (WASI)
    ./build/luke BUILD app.luke -target wasm -o app
    
    # browser page — html + wasm + runtime glue
    ./build/luke BUILD app.luke -target browser -o app

    Browser and WASI targets need the WASI SDK; see download. When you are ready to put a server behind TLS, deploy covers the reverse proxy and the connection knobs.