Show HN: Axe - A Systems Programming Language with Builtin Parallelism and No GC

axelang.org

13 points by death_eternal 2 days ago

I'm writing a compiler for a systems language focused on concurrency and parallelism. It’s a re-engineering of a prior work, with an explicit emphasis on memory management and type safety, plus first-class parallel primitives at the language level.

The language is now capable of compiling a substantial portion of its own source code to tokens using a single-pass C back-end. The self-hosted compiler includes a handwritten lexer and a parser, with an arena-based allocator to support fast compilation and eliminate GC complexity.

The primary goals for the project are: First-class parallel and concurrent constructs built directly into the language, strong static memory and type guarantees, and a toolchain suitable for building high-performance software

Example:

  def main() {
      parallel local(mut arena: Arena) {
          arena = Arena.create(1024);

          val tid = Parallel.thread_id();
          val result = worker(ref_of(arena), tid);

          println $"Thread {tid} computed {result}";
          Arena.destroy(ref_of(arena));
      }
  }
You can find the repository here: https://github.com/axelang/axe
Panzerschrek 13 hours ago

How does it achieve memory safety?

Does it have destructors and RAII?

Does it have type and function templates?

  • death_eternal 7 hours ago

    1. It manages memory through deterministic ownership rules and optional arena allocation. Pointers never outlive the allocator that created them, and the compiler performs lifetime checks to prevent use-after-free or double-free errors.

    2. Axe does not use C++-style RAII. It employs deterministic cleanup through defer, which allows resources to be released predictably. Also, objects allocated inside an arena are freed as a group when the corresponding arena is destroyed.

    3. Not yet. There is an overload system currently:

      overload println(x: generic) {
          string => print_str;
          char*  => println_chrptr;
          i32    => println_i32;
          char   => println_char;
      }(x);
    • Panzerschrek an hour ago

      How does your compiler manages to perform lifetime check? What if I save a pointer allocated from an arena somewhere, so it outlives it? What if I forgot to free memory via defer?

      What about spatial memory safety? Can I read/write outside allowed memory by misusing pointer arithmetic?

      What about concurrent access? What if a pointer to some piece of memory is invalidated by some other code?