Quick Tour for Beginners

Commands

( this is a command )

A programming language is translated by a compiler or interpreter to generate machine instructions. An interpreter generates machine instructions on the fly to use now, while a compiler generates machine instructions to use later.

In TONAL, a single command is given in between a pair of parentheses. The TONAL compiler can be thought of as an interpreter of commands. It is not merely a translator – commands tells the TONAL compiler how to run.


Commands – Tonic Form

(verb ...subjects)

The basic form of TONAL commands is a verb, followed by zero-or-more subjects. Just like in ordinary language, verbs in TONAL are “doing words”. They tell the compiler what to do. Anything that appears in the verb position in a command is a verb. The same characters in a different position are not verbs.

eg, the characters listen is a doing word, but if it is not in the verb position, then it is not a verb. Conversely, the characters computer is not a doing word, but if it is in the verb position, then it is a verb.

Subjects take their name from linguistics – eg, the English language is a subject-verb-object order language. However, in TONAL, the meaning is not the same. We use it just so we have a name to call those parts of the command that is not the verb; but also because object has a special meaning in programming languages and so it’s a nice, easy-to-remember coincidence.

Tonic forms can be commands defined by the user, or special commands that the compiler understands.


Tonic Form example

(+ 'Hello ' 'world!')

+ is the verb of the command. It tells the compiler to find and apply the function + to subject strings. The function found might mean “join these strings together” and so might give the value 'Hello world!'.


Commands – Dominant Form

(object.verb ...subjects)

There are categories of programming languages called object oriented. Each object has a special type – eg, number, string, cake – and the type tells us what things we are allowed to do with the object. TONAL is not just an object oriented language, but the syntax is convenient and very widespread – a defacto standard – so we use it.

An object can enclose other objects, so we use names chained together by single dots in between in order to refer to them. Think of them like the slashes in a file path. The final segment of this chain is the verb when the full chain is in the verb position. Only names of objects enclosed by an object are considered, and not any other thing with the same name. The object is what the verb acts upon.

The Dominant Form is so-called because the type of object dominates how the verb and subjects are considered. Also because it is expected that this form of a command will be the most dominant in usage because it is so widespread.

The rules that TONAL defines about how to find names of the dominant form is called Dominant Name Search.


Dominant Form example

(Amazon.warehouse-managers.abuse non-union-employees)

Amazon is an object that encloses an object called warehouse-managers which in turn encloses an object called abuse. That object is in the verb position, so it is the verb – the doing word. It dominates, and the non-union-employees are the subjects.


Commands – Subdominant Form

(verb object ...subjects)

The dominant form is not mandatory, and so commands can be expressed in this form. It evokes the more mathematically familiar function. The object is always searched first for the verb. If the verb isn’t found, then the search continues from where this command occurs, and the enclosing object.

If the verb isn’t found enclosed by the object, then the object is simply a subject. That is why this is called the Subdominant Form. It behaves like Dominant Form commands for the most part, but is a regular Tonic Form otherwise.

There is no difference for names of verb that is found through Dominant Name Search of the object, and the equivalent Dominant Form of the command. If the verb refers to the same object‘s type, then they are the same function.

The rules that TONAL defines about how to find names of the subdominant form is called Subdominant Name Search.


Overloading names

(execute unarmed-suspect by police-officer)
(execute layoffs-plan by CEO)

Just like in the real world, verbs can have different results depending on what they’re used on. The candidate meanings of a verb, whether found by Dominant Name Search or Subdominant Name Search, is called the overload set. The process of choosing the most suitable candidate is called pruning.

TONAL prunes the set of overloads based on they type of the subjects. If police-officer is of type “grey-collar” and CEO is of type “white-collar”, then TONAL will choose the relevant verb from the overload set of execute if they exist.

If execute is overloaded but both candidates are defined to accept the type “person” as the third subject, then it is ambiguous and the compiler will consider it an error. In general, the TONAL compiler will not try to guess what a programmer meant in cases of ambiguity.

The pruning process ranks candidates based on how well the types of the subjects matches the candidate’s definition. This will be discussed in-depth in later slides.


Do, a deer, a female deer

tonic
supertonic
mediant
subdominant
dominant
submediant
subtonic
do
re
mi
fa
so
la
ti

You may have noticed the theme of using scale degrees to refer to forms of commands. This coincidence makes it easy to remember the 7 TONAL forms, since it fits with a music theme. The ones we have explored so far – tonic, dominant, and subdominant – have a coincidentally similar role as their musical counterparts.

The tonic serves as the base for the rest of the language. The dominant really resonates with the tonic to establish the feel of the language. The subdominant is similar to the dominant and rounds the language out.

Many languages have many incidental names for their grammar rules and are not accessible to the average user of the language. TONAL‘s scale degrees makes it easy for programmers talk about code with only a few, but distinctive (memorable) names. There will be a few more musical references down the line.

If these seven forms you know, you can write most any code.


Commands – Supertonic Form

(keyverb ...subtonics)

Most languages have special words called keywords that have predefined meanings from the outset. Some languages allow you redefine keywords. Most languages reserve keywords and so do not allow you to redefine them. Most languages have context insensitive keywords, meaning that the language considers them keywords in any position. Some languages also have context sensitive keywords which only have the predefined meaning when used in certain positions.

TONAL has keyverbs. Keyverbs are verbs for specially named commands for instructing the compiler. Outside of the verb position, they have no meaning and can be used for whatever purpose. A command that has a keyverb is a Supertonic. They’re tonics with special powers.

Supertonic subjects are special forms called subtonics. Verbless, they get their meaning from their position inside a supertonic command. They’re like tonics with a bit taken out. Supertonics may also have context sensitive keyword subjects that only have a special meaning when used in the exact language-defined position. Subtonics differ from subjects because subjects must have a value, while subtonics are just syntax.


But why keyverbs?

(yield)
(co_yield)
(hype.yield)

Future proofing software is hard. For a compiler even more so. Either the language changes features every version, annoying a lot of people who don’t want that to break the code they’ve already written, tested, and make money from.

Or, no feature gets removed, and new features like yield still get added or changed, annoying a lot of people who want to use the new feature, but they have to settle for co_yield because some other programmer already used yield as an object name.

The keyverb design maximizes the number of usable names available to the programmer, now and into the future. TONAL also provides more advanced escape hatches, such as the hype prefix, and ways to make that more usable.


Keyverbs

Declaration

let
func
type
()

Control Flow

if
loop
stop
skip
pass

Control Whoa!

wait
goto
give
trip
trap

Lifecycle

push-in
pull-in
push-out
pull-out

Access Control

readers
writers
virtual
include
grab

These are all the keyverbs that TONAL defines. Many of them pull double duty in the other command forms with related but different purposes.

Declaration keyverbs command the compiler to define or create new things. Control flow and control whoa! keyverbs command the compiler to change what command to jump to. The jumps of the first kind are “small”, but the jumps of the second kind are “far away”. Lifecycle keyverbs command the compiler to change an object‘s default lifetime. Access control keyverbs command the compiler to change a definition’s default structure.


Supertonic – Declaration – Function

(func feed ((pet cat) (food cat-food))
      ((pet.nom food) (pet.abandon food)))
(func feed ((pet dog) (food dog-food))
      ((pet.chomp food) (pet.spill food)))

In all of mathematics/computer-science, the humble function is the primary tool for managing complexity. Functions bundle up a series of commands such that they represent an algorithm that can be used again and again. If there is something you need to do more than once, put it in a new function.

Funcs can have zero-or-more parameters, each with or without an explicit type. All of a func‘s parameters must be fulfilled by matching arguments for it to be chosen from an overload set to use as a verb.

Funcs can be enclosed by a type or another func. Funcs enclosed by a type can refer to the names defined by the type. A func can refer to names declared outside its own declaration if they are grabbed implicitly or explicitly.


Supertonic – Declaration – Type

(type space-ship ((species alien-species)) base vehicle
      (func launch () (...)))

You may notice that an algorithm tends to do the same thing to a subset of variables that it is not doing as often on another subset. Then imagine if some variables get repurposed halfway through and it results in days of debugging because it wasn’t not clear at what line that the purpose was assumed changed.

You’d probably want to group them together under a common name, ensure that they always have correct values in relation to each other, and tell other programmers what they can and can’t touch or do with them. Wrap them up and guard them in a type. Types can even select which – and how – variables and funcs can be referenced by specific types and funcs.

Every object has a type. Even a func has a type, which is hype.func; and a type has type hype.type. Types can be enclosed by another type and even a func. A type can refer to names declared outside its own declaration if they are grabbed explicitly. A type can be derived from a base type if the base type is a superset of the type‘s allowed values. A type can also have parameters like a func.


Supertonic – Declaration – Type

Types have special features and requirements. They must have at least one way to create an object. That is called its constructor.

They must have a way to clean up after themselves. That is called its destructor.

They may have a way to copy themselves, called its copy constructor, or it may have been deleted. Copy constructors may be used to create a copy, or modify an existing object.

A type may have many other constructors.

A type may have a custom method to reference its names. That is called its redirection operator.

A type may have many other types it can be converted to. They are called conversion operators.


Archetypes

longWhole numbers with an “unlimited” range.0realNumbers with an “unlimited” range.0.0
atomAn unbounded string of almost any characters.''listAn unbounded sequence of values of any type.()
funcThe common type of all functions.typeThe common type of all types.

When the compiler begins compiling, it defines these built-in types – called archetypes – for the rest of the program to build on. They are defined under the hype type, but the hype prefix can be omitted if the type‘s name is not overloaded.

All archetype variables must be present-tense or past-tense.

During compilation, all variables start with a known value. As commands are being processed, the variables’ values are tracked. When its value is known by the compiler, it is said to be in present-tense. If its value becomes unknown (eg, overwritten by future-tense values coming from the OS) then it is in future-tense. An object that is destroyed is in past-tense.

Future-tense values are so named because their actual values are defined when the compiled program runs in the future. Present-tense values can be discarded from the final program. The naming carries on the grammatical theme (ie, verb object subjects) so as to be easy to remember.


Supertonic – Declaration – Values

(let answer 42)
(let pi 0x3.243f6a8885a3p0)
(let fruits-that-are-not-oranges (() 'watermelon' 'apples'
     'plum' ''))

Let is the command for defining named variables. They can defined in funcs and only live inside the running func. They can be defined in types, and live as long as the object constructed by that type.

All named variables must have a starting value. The variable’s type is the type of its starting value and cannot be altered.

The value of fruits-that-are-not-oranges is a list. The keyverb () is the list constructor. Since commands are already special syntax, it saves TONAL from reserving list as a keyverb. The list constructing command is a tonic that is the subject of another tonic, so it is deemed a minor tonic. The let is a major tonic as it is not in the subject position.


Supertonic – Control Flow – Return

(func can-haz-cheezburger?
    (oh-hai)
    (pass true))

When a command is being processed by the compiler, it is temporarily in control of the compiler. When that command has finished, control flows on to the next command. Verbs are the primary form of control flow – it tells the compiler to find a func and jump to it, and when it finishes, jump back to where it came from.

To jump back from a func, we use the pass keyverb. When a func has no more commands, it automatically jumps back. Sometimes we want to jump back a bit earlier if a func can finish quicker, so we explicitly pass. Some funcs’ purpose is to calculate or create a value. We explicitly pass, and provide a value to pass.

All funcs have a return type – the type of value that it passes. For funcs that don’t explicitly pass a value, they implicitly pass an empty list. Funcs must only have one return type, even if that type is a list and is used to return many values.


Supertonic – Control Flow – If

(if ((let i (cat)) (i.can-haz-cheezburger?))
    (i.nom (cheezburger))
 if (= question (x 6 9))
    (return answer)
 else
    (next-question))

Jumping to a func is all well and good, but it is an all or nothing action. A lot of the time, we need to make a choice between what do do, or whether do something.

The if command is made up of branches, and can have any number of branches. Inside the branch can contain any commands, just like funcs. A branch is only jumped into when the corresponding condition is true. An else branch is optional, and no branches can follow the else branch.

Each branch may declare a named variable that only exists until the end of the whole if command. It is also accessible to all branches following, unless hidden by another of the same name.


Supertonic – Control Flow – Loop

(loop (i (() 1 2 3 4))
    (if (= i 4)
        (declare-thumb-war i)))

Many tasks require doing things over and over. Many tasks require waiting until something happens, and then doing something. Some tasks should run forever (but computers crash).

The loop command repeats a sequence of commands for every value in a sequence of values, until the are no more values, or is stopped early. The sequence of values can be limited or infinite.

It is possible to stop a loop command to finish early, or skip to the next round of the loop command without finishing the current round. When a loop command contains a loop command, and so on and so forth, it is possible to label each and any loop command, and stop, or skip, a labelled loop command.


How do you solve problems with memoria?

Bad things happen when you touch memory you’re not supposed to. Even the most skilled programmers are not immune from doing this. Don’t touch a piece of memory:

  1. Before an object is constructed in it
  2. After the object in it is destroyed
  3. Outside of known regions
  4. With an existing object in it
    1. But it’s the wrong type for a command
    2. Try to construct a new object on top
    3. While something else is modifying parts of it
  5. Without being granted permission

These are often related, but not always. Many of these problems can be avoided by the language’s syntax (compiler) itself. Some of these problems can be avoided by types provided by the language. Other problems are handled by the system, unless the program is it.


How do you use syntax to pin it down?

Where ever a let command is allowed in a func, its value moves to past-tense at the ) that is paired with the ( that encloses it. For a minor tonic, the evaluated value moves to past-tense at the ) of its enclosing major tonic, even those enclosed by another minor tonic. This is called its lexical scope, and TONAL is a lexically-scoped language. Values declared by let commands within a type is in dominant-scope and moves into past-tense when the enclosing object does. The enclosing object may be in a lexical-scope.

Values that are passed to a func as arguments, whether they are let names, or minor tonic values, are always nonpast-tense while the func is in control.

For lexically-scoped variables, their nonpast-tense begins where they are declared, and so they move into past-tense in the reverse of the order of their declaration at the end of their lexical-scope.

Variables directly referenced within their lexical-scope are modifiable by default. This is because objects are often created to be modified. Variables referenced via a func‘s parameters are readonly by default. This is because most of the things we do with objects are just reading the value. Past-tense values cannot be referenced at all because they no longer exist. Unnamed variables have no name to be referred to.


What keyverbs to use for memoria?

push-in
pull-in
push-out
pull-out

The use of types and the default memory rules make memory safe by restricting when it can be accessed, and keeping track of what is being accessed. As with all things, no set of rules can cover all legitimate uses.

Some languages requires special keywords to declare an object unmodifiable. Some languages requires special keywords to declare an object modifiable. TONAL wants the programmer to declare how they intend to use an object. Declaring a variable inside a func probably means you intend to modify it within that func, but you probably don’t intend that other funcs modify it when you pass it to them. These are the default behaviours discussed previously.

But maybe you do want to stop modifying an object locally once you’ve finished customizing it. Maybe you do want to allow another func to modify it just once. Maybe you want to tell the compiler you’re done with an object and it can be destroyed before the end of lexical-scope.


TOWAL

TONAL gives you Total Ownership over Waste And Lifecycle. This extends what other languages call RAII (seriously, you don’t want to know), but giving programmers a little extra control by allowing them to declare intentions. A little extra control actually makes programming simpler because you don’t have to twist code to work around it, but without giving up safety. In effect it is like a Lite version of RAII.

Some languages without RAII expects you to track every bit of memory manually and with the usual reliance on human error. Other languages allows you to leave everything lying on the floor like garbage, but you have to pay for someone to clean it up eventually. Not to mention you still have to manually clean some things up anyway because that garbage collector you paid a lot for is late.

With TOWAL RAII(L), you always know where your TOWAL is.

By now, you have a feel for what this language is like. TOWAL is a pretty big subject, so you may as well finish this tour and (goto 'Principles of Operations') to learn TONAL in full.

Leave a comment