Discussion on Hacker News

Til is a command language written in D whose syntax is inspired by Tcl. It aims to be:

  • easy to understand: you can read the source code and easily grasp what is going on;
  • easy to use: Til have syntax, specially where it makes things more comfortable;
  • easy to extend: D is very practical and easy to learn.


The title made me think of Threaded Interpretive Languages, meaning Forth and its relatives, which have nothing to do with this language.

An example

proc list_joiner (separator list) {
    length $list | as n
    set counter 0
    list | as receiving
    range $list | foreach item {
        set counter $($counter + 1)
        push $receiving $item
        if $($counter < $n) {
            push $receiving $separator
    set s ""
    range $receiving | foreach item {
        set s "$s$item"
    return $s

scope "test list_joiner" {
    set target_list (a b c d e)
    set separator ", "
    # Compare our function's result with the built-in `join` method:
    assert $([list_joiner $separator $target_list] == [join $separator $target_list])

In the example we can see that:

  • You can create a list using both the () syntax and the command list;
  • You can set variables with set, Tcl-style, or using a pipe to as, like list a b c | as my_list;
  • Conditions are not "delegational" by default: if receives a boolean as first argument. The $() syntax takes care of turning $($a < $b) into < $a $b;
  • You iterate over "streams" using foreach; there is also a transform command that allows changing the items from the sequence in the middle of a pipeline;
  • Commands can be methods: length, when called with a list as first argument, actually calls SimpleList.commands["lenght"]. If you call, for instance, length $queue, it's going to look for a Queue's method, so you don't need to name commands different for each type.


With this package you can create Tcl interpreters and run commands in them:


scope "load Tk, just because" {
    tcl | autoclose | as t
    run $t {{ package require Tk }}
    print "Tk loaded!"

scope "interpret a String as Tcl code" {
    tcl | autoclose | as t
    run $t "set x 123"
    print "x in Tcl is " <$t x>
    assert $(<$t x> == "123")
scope "interpret Til code as Tcl" {
    tcl | autoclose | as t
    run $t {{
        set x 123
        puts "x (from inside Tcl) is $x"
    assert $(<$t x> == "123")
scope "get values from Tcl" {
    tcl | autoclose | as t
    run $t "set x 321"
    set value <$t x>
    assert $($value == "321")
    print "x in Tcl is $value"

Notice that it implements extraction of values from the interpreter (that is: getting the value from a variable) with proper syntax (<$interpreter $variable_name>).