Tenet language

Tenet is an intuitive language to share data between systems with consistent and reliable semantics.

Source

Right now the source is on gitlab.

Examples

This is a tech demo at the moment, so these examples let you see how the compiler works step by step. When Tenet has a working compiler, the site will be refocused on the target audience.

CodeMirror didn't run; is Javascript enabled?

Types

Tenet lets you define complex types using tuples, unions, enums, lists, sets, maps, strings and integers. Read more.

type Category := Union:
    raw_material ~~
    work_in_progress ~ Integer
    finished_good ~~
    service_inventory ~~
    transportation ~~
    future ~ String

type Inventory := Tuple:
    sku: String
    item_name: String
    alt_names: Set[String]
    category: Category
    vendor: String
    inventory_count: Integer
    base_price: Integer

Functions

Unlike most serialization languages, Tenet is fully programmable, so you can define complex behavior along with types, but it has very predictable and simple semantics.

def inventory_summary(inventory: List[Inventory]):
    # Construct an empty map.
    summary := [:]
    for entry in inventory:
        # Extract the fields we're interested in.
        {category, vendor} := entry
        # Tenet supports complex keys in maps.
        key := {category::, vendor::}
        # Count the items found, by defaulting to 0.
        if key not in summary:
            summary[key] := 0
        summary[key] += 1
    # Returns the combined map.
    return summary

More examples

There are some more examples.

Features

  • A faux-mutable type system.
  • It’s an immutable type system that prevents global side-effects.
  • But using an imperative language accessible to subject matter experts and amateurs.
  • Static types that are as easy as JSON.
  • If you want to return ok ~ { data: "my data", count: 6 } you can just do that.
  • Type inference figures out the actual type.
  • And then Tenet can document it correctly for you.
  • User-defined functions in a serialization language.
  • Build smart API clients with functions that further analyze data.
  • Evolve your API by writing functions to cast between versions.

How does it work?

To compile to different languages, you first need to simplify everything down to a common micro-language, and then rewrite that into the target languages.

Different languages only have a few things in common we can largely depend on, such as user-defined functions, local variables, etc. Even things like for-loops aren’t available in all languages.

The underlying principle used here is the same as any compiler: take a tree and repeatedly modify it.

As you perform those modifications, you simplify the problem slightly. For instance, Tenet is faux-mutable, so one step is “delensing” which means converting a.b = c into a = !!set_slot(a, 'b', c).

The last tree will be the target language’s syntax, and then that can be written out as text.

Future improvements

It may be possible to avoid some transformation steps for some target languages. For instance, most languages support looping, so it would probably be better to translate a loop directly when possible. What we’ll want to do, though, is make sure any shortcut like that behaves exactly the same as the common micro-language.