Austral Language

Created on 2024-03-16T20:18:38-05:00

Return to the Index

This card pertains to a resource available on the internet.

This card can also be read via Gemini.

Linear type system tl;dr

No destructors or GC

These are not so bad. You are required to dispose of handles so the finalizers just become explicit. The lack of a GC is fine because the entire language is using move semantics so there is typically a single owner or a compiler-checked borrow against the single owner.

No macros

This part I don't like. I just don't like "get what you are given" languages in general. That being said the author is vehemently against complexity and compile time evaluation does add marked amounts of complexity to a compiler. So I get it even if I do not agree with it.

No function overloading

I disagree with this. It's another one of those "you could use it wrong so its bad" and I just don't really agree with that argument.

It leads to having to name things "writeString" and "writeSomeType" instead of just cleanly saying "write."

Linear Types

A "free" type is one that is allowed to be used zero or more times.

A "linear" type is one that must be used exactly once.

This is basically forcing the programmer to write the whole program in single assignment form directly; combined with "copy and move" semantics wherein linear values are always "moved." If the object remains usable then you return it again from the function, otherwise you do not.

This combination of always moving and using only once makes it trivial to enforce certain stateful workflows.

let f = openFile("somefile.bin");
let f2 = writeFileStr(f, "some text");
closeFile(f2);

You can also use this to enforce proper state transitions like creating a slot, binding it to a device, changing device mode to something and back, freeing the device, and so forth.

Regions

Lifetime markers. You can borrow a value in to a region and the value lives for as long as that region or less; so you cannot have a region valid for one task and store the value in a region representing the global state. This prevents accidents of storing things where they could end up pointing to dead references.

Values have to be fully copied to get around the region limitations.

Capabilities

Objects can be used to represent capabilities; such as a "root capability" that is required to do certain privileged actions. Functions can use the root cap to produce different capabilities, which can be handed to other functions. Thus calls can only be made when you have a relevant capability to call them which allows you to make stronger guarantees about what parts of a program might be doing.