This documentation is, just like Runtime, still a work in progress. While it is technically done, I have no doubts that people
will be able to find problems with it. If you notice something is awry, don't hesitate to create an issue on the runtime-site github page.
To get started, you should install Runtime. Links and instructions are available here.
First, you should try seeing if you can get into the Runtime environment. Assuming you have it properly
installed, you can simply run Runtime in the terminal. Note the uppercase R.
You should be met by something like this
Runtime runs code in two seperate ways, either in the live interpreter, which is what you're looking at here,
or it can directly run files, in which there will be no pretty visuals. You can also run files directly in the live
interpreter using the Include() function, but we will take a proper look at that later.
This guide is written under the assumption that you have atleast a cursory level understanding of programming,
however you might be able to follow along even if you don't.
Everything in Runtime is either object or value. This makes learning the workings of the language extremely simple,
in exchange for making the process of actually writing code quite a bit harder.
In the following image, everything can be grouped into values or objects.
As you (maybe) can see, Object and Print are both functions.
However, in Runtime, functions are objects.
This leaves us with "Hello world" and str, the former of which is a literal, and
the latter a variable, which also happens to be an object.
This might leave you with some questions. If str is an object, then what are values?
The answer is quite simple, the literal, which is assigned to str, IS the value. In this case the str object
acts as a short of container for the literal, as values cannot exist by themselves in Runtime.
Like you would assume, objects can have members. For example, in the previous snippet of code, str had an
unnamed member with the value of "Hello world".
You can access members using the accession operator -
Object(str "Hello") # Commas are completely optional in Runtime. You can add them if you feel they help code readability
Print(str-0)
# This prints Hello
Here str was assigned the value, by default, at it's 0th index. You can think of objects as arrays.
However, you can also think of objects as dictionaries, since you can also assign members via a string key.
Object(str)
Assign(str, "msg", "Greetings!")
Print(str-"msg")
# This prints Greetings!
Print(str-0)
# This also prints Greetings
Every member with a string key also has an int key, however this is not necessarily true the other way around.
Objects can be created simply by referring to them
int # This creates an empty object called int
If you want to give objects members, this can be done using either the Object()
or Assign() functions.
TODO: object doesnt evaluate, assign does
Object() will simply assign new members by giving them incrementing unique int keys.
Assign() will assign a value to a specific member. This allows you to change existing values,
as well as create new ones with specific keys, which don't have to abide to an incrementing schema.
Object(i Input()) # Assign user input to the variable i
Print("Hello")
Print(i)
How would you assume the control flow would work?
Surprisingly enough, we see the "Hello" message before we are asked for input.
Why does this happen?
The answer is lazy-evaluation, or as I call it in Runtime, questionable-evaluation.
Lazy-evaluation means that values are only evaluated when needed. For exaple, in Haskell
you may assign the numbers 0-infinity to an array. While in most languages this would be
impossible, Haskell allows this because it will only evaluate the numbers when you ask it to.
This is also how it works in Runtime. In the code snippet above, while i is assigned the value of Input()
before "Hello" is printed, we only access it's value later in the line Print(i).
The Print() function will evaluate it's arguments, in order to print them.
However if you're a Haskell aficionado, you may see a problem with this: Runtime is not purely functional, which
means functions can have side effects. This is where the "questionable" part comes in.
It is entirely possible, that the return value of a function has changed in the time it took between assigning it
to a variable and actually evaluating it.
This is simply one of the things you will have to keep in mind when writing code in Runtime.
In order to understand evaluation fully, you will need to be aware of the specific mechanisms behind
how it works.
In the last chapter we went over how an object with a single value is evaluated. However what if an object
has multiple members? In that case the member which was lasted assigned to will be evaluated.
When we first print obj, it will result in "I love you :D", as that is the last member it
was assigned. The next time however, it will print "I no longer hate you :)", since the first member
had been assigned to again.
As showcased above, the index of a member doesn't necessarily have anything to do with when it was last assigned to.
In the last chapters, we went over evaluation. However in order for Runtime to be langauge that can actually be used for
anything, there needs to be a second mechanism for evaluating objects. That mechanism is calling .
Every object can be both evaluated and called, and in principle they are not so different from eachother.
While evaluating an object will... evaluate it's last assigned to member, calling an object will evaluate all of an objects
members in order of assignment, before returning the last one.
This, however, is where things start to get difficult. While the basic concept of functions is what was just described,
there are quite a lot of quirks in the implementation which make things harder. For example, evaluating an object or its value
will write the objects value to memory, whereas calling it will not. Heres an example to try to help you understand.
The first time we print a, it will evaluate its Print("Hello") member, thereby calling it.
It will then return 0, which is the value actually printed by the top level print statement.
The second time we print a however, it will only print 0.
This is because the value of Print("Hello") has already been evaluated, and since it returned a value of 0,
that is what was written to memory, and thus its what is returned the second time a is evaluated.
In this case we have a similar setup: the object b is identical to the object a.
However, instead of printing the value of b, we callb, which will only evaluate its
member. However, calling an object does not write the evaluated values down, meaning we can call the b
object as many times as we want.
The last image should give you decent idea of how functions work. You create an object with a series of object calls, then
you call that object, which results in all of its members being evaluated. Now we must move on to arguments/parameters.
Here is a simple function which takes a single number as an parameter and prints its following digit.
The function func takes a single parameter x, then prints the result of x + 1.
Parameters work in kind of strange way. Whenever you create an object instead of just always creating an empty
object with the value of 0, the interpreter will first look if there are any parameters which need to be defined.
For example, in the code snippet above, when the function is called, it will create an object called x. Then,
when instantiating it, it will see that there is currently a single argument which is yet to be assigned to anything
(since we passed args to func), and it will then assign its value to x. So the first time in the snippet
we call func, x will be assigned a value of 1, since that's the argument we gave the function. The last
time we call the function, we don't pass any arguments, so when x is created, it will simply be assigned a value of 0
by default. Note that this does mean that if you have some complex code with deep, multi-layered function calls,
omitting arguments may be problematic, assuming the functions don't deal with it themselves.
Objects are always passed by reference, and values are always passed by value.
Object(one, 1)
Object(value, one-0) # Passed the value of one
Object(reference, one) # Passed a reference to one
Assign(one, 0, 2)
Print(value) # Will print 1
Print(reference) # Will print 2
This is another case where the workings of evaluation will be prone to mess things up.
Congratulations! You've made it to the end of the documentation. In theory, you should now be able to write functional
Runtime code, although in practice it will of course take some time before you're able to fully grasp the language.
This section will be a quick overview of some of the most useful functions that come with Runtime. A full reference of
all Runtime objects can be found here.
Name
Evaluates args
Returns
Function
Print
Yes
1
Prints all arguments to the standard output.
Input
No
Input
Returns a single line from the standard input.
Object
No
Success (1/0)
Adds members to object.
Assign
Yes
Success (1/0)
Assigns a member to a specific index on an object.
Include
Yes
Success (1/0)
Runs a Runtime file and includes its defined objects.
This page is licensed under the CC0-1.0 license. You are free to use the source code of this site however you want,
even without any attribution. The source code is available at my Github