Skip to content
Tech News
← Back to articles

Borrow-checking without type-checking

read original more articles
Why This Matters

This article introduces a novel approach to borrow-checking in a dynamically typed language, enabling efficient runtime verification without static type checks. It explores blending dynamic and static typing to offer flexibility while maintaining safety, which could influence future language design and runtime safety mechanisms. The approach aims to provide a practical solution for mutable value semantics in dynamic languages, balancing performance and safety.

Key Takeaways

Published 2026-04-22

This is a demo of a toy language with dynamic typing, inline values, stack allocation, interior pointers, single ownership, and a limited form of borrowing - less expressive than rust, but much more expressive than second-class references (eg we can express external iterators).

Since there is no static typing the borrows must be checked dynamically. The interesting part of the demo is that we can do that fairly cheaply and with useful error messages.

The code is here.

background

I'm exploring a style of type-system exemplified by julia and zig. Both languages start with a dynamic type system, enforced by dynamic type-checks, and then layer on a static type system which is capable of proving that the dynamic type-checks are unnecessary. The dynamic type system provides flexibility and easy meta-programming, while the static type system removes the overhead in most of your code.

Julia and zig differ slightly in how they handle code that cannot be statically type-checked. Zig will refuse to compile the code at all, while julia will leave some dynamic type-checks and will run the static type-checks again when more type information is available.

For zest I'm exploring a third option - code can either be dynamically typed (and interpreted), or statically typed (and compiled), but switching between the two requires explicit annotations. The goal is that most of your code can have the assurances of static typing, but you can still opt in to dynamically-typed glue code to handle repls, live code reloading, runtime code generation, malleable software etc.

The tricky part is that I also want to enforce mutable value semantics. To date there are two main strategies for doing this:

Reference-counting and copy-on-write, which imposes an unpleasant performance overhead and is hard to combine with interior pointers / explicit stack allocation.

... continue reading