SkyHetu: Designing a Causality-First Programming Language in Rust

Published: (January 7, 2026 at 07:20 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

SkyHetu

Most bugs I’ve encountered in my career boil down to one question: “How did this variable get here?”

Modern programming languages are amnesiacs. If user.balance is 0, the application knows it is 0 now, but it has no memory of the sequence of events that led to that state. Was it a logic error? A race condition? A rogue function call? To find out, we add print statements, attach debuggers, and try to replay history in our heads.

I decided to build something different. I built SkyHetu, a programming language where Causality is a first‑class citizen.

The Philosophical Shift

In SkyHetu, you don’t just change state; you create an event. To achieve this, I enforced three radical design decisions:

  • Immutability by Default: You can’t change a variable unless you explicitly ask for it.
  • Explicit State: Mutable variables are declared with state, not let.
  • The Arrow Operator (->): Assignment (=) is for initialization. The arrow (->) is for mutation.
state counter = 0
counter -> counter + 1

The -> operator does two things:

  1. Updates the value.
  2. Logs the causality.

Building the Time Machine in Rust

To make this work, I needed performant, low‑level control over memory and execution flow, so I chose Rust. The core of SkyHetu is a stack‑based virtual machine (VM). Alongside the stack and the heap sits the CausalityLog.

pub struct CausalityLog {
    history: HashMap>,
    clock: usize, // Logical time
}

pub struct MutationEvent {
    pub old_value: Value,
    pub new_value: Value,
    pub timestamp: usize,
    pub location: Option,
}

Every time the VM executes the OP_TRANSITION instruction (triggered by ->), it captures a snapshot of the before and after values, stamps it with a logical clock tick, and pushes it into the history.

The “Detective Board” Visualization

Because the language remembers everything, debugging feels less like archaeology and more like detective work. I implemented a native function called causal_graph() that exports the internal history into DOT format (for Graphviz) or JSON.

state score = 100
score -> score - 10   // event 1
score -> score - 50   // event 2

print(causal_graph("score", "dot"))

The generated graph shows each state as a node and each timestamped transition as an edge—a “Detective Board” for your code.

Why Rust?

Rust was the perfect tool for this for three reasons:

  • Enums: Representing dynamic types (Value::Number, Value::String) is trivial and safe.
  • Performance: The overhead of tracking causality is non‑zero, but Rust’s zero‑cost abstractions let me optimize the critical path.
  • Correctness: Writing a garbage collector and VM is complex. The borrow checker saved me from countless segmentation faults that would have plagued a C++ implementation.

The Result

SkyHetu isn’t just a toy; it compiles modules, handles closures, and even supports classes. Unlike other languages, it offers introspection built‑in. You can ask the language: “Why is X true?” and get a causality chain.

print(why(counter))
// Causality chain for 'counter':
//   1. [t=1] 0 -> 1
//   2. [t=2] 1 -> 2

We spend 90 % of our time debugging. Maybe it’s time our languages helped us with the other 10 %.

Check out the source code on GitHub

Back to Blog

Related posts

Read more »

An Honest Review of Go (2025)

Article URL: https://benraz.dev/blog/golang_review.html Comments URL: https://news.ycombinator.com/item?id=46542253 Points: 58 Comments: 50...

RwLock HashMap Arc Mutex File

rust pub struct Context { pubcrate tools: HashMap>, pubcrate fifos: tokio::sync::RwLock>>>, // ^ ^ ^ }// many fifos, but only | async ref counter | | but only o...