Skip to content

experiments in controlled mutation and readable imperative syntax

Notifications You must be signed in to change notification settings

jasonperry/dill-compiler

Repository files navigation

Dill is a statically typed programming language to capture how I want to write and read imperative code. It’s meant to be type- and memory-safe, with an orthogonal set of type-based abstractions, and as low runtime overhead as possible. The most interesting feature is how it makes mutability visible and simplifies management of the value/reference distinction. Goals and features include:

  • “Imperative locally, immutable-first globally”; local variables are reassignable, but datatypes are immutable by default, and procedure arguments are passed immutably by default and are not reassignable.
  • Non-local mutation is made explicit; passing an object mutably is indicated at both the function definition and call site. Otherwise “deep” immutability is enforced.
  • No implicit differences in behavior due to using values vs. references; explicit mutability reduces the number of places where you have to think about the distinction. You can declare a local ref variable, but for function arguments the mutability distinction is enough. Assignment of a mutable object to a var is always a copy, but you have to write an explicit copy() for dynamically-sized types.
  • Algebraic datatypes, called record and variant. Built-in Bool and Option types have the same syntax as user-defined variant types. Recursive types.
  • All types are datatypes; there are no classes (containers for a type and methods). As an alternative to method call syntax for call chaining, a pipe operator is in the works, with a parameter marker which also distinguishes mutable and non-mutable arguments.
  • Null-safety with explicit nullable (option) types, with syntactic sugar ? and value promotion convenience features.
  • Syntax: keyword-based, no curly braces or significant whitespace, semicolons as statement (not block) terminators. LL(2) parseable (mostly LL(1)), no significant whitespace. Blocks are closed by a slashed keyword (/if, /while) to be more informative than just end but still short to type. Making code easy to type and even read aloud are also goals.
  • Modules as the primary construct for code grouping and data hiding. private means private to a module; functions in a module can access private fields of datatypes in that module. All imports must be explicitly specified.
  • Separate compilation by means of auto-generated module specifications. This is strictly a compiler feature—module specs are not part of the language definition proper. What a module exposes is completely specified by its source.
  • In progress: generics, with constraints by means of module signatures (the modular equivalent of interfaces). Module imports explicitly specify which signature implementations you’re using.
  • Planned: coroutines, probably stackless.

Look in testsrc/ for examples, though many are not up to date with recent syntax changes.

We’ll see how far I get. The backend is LLVM with the Boehm garbage collector, currently targeting only x86-64.

About

experiments in controlled mutation and readable imperative syntax

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages