Skip to content

Basics

This section of the guide will rapidly cover the basics of RSL. RSL shares a lot of conventions and syntax with popular languages like Python, so if you're familiar with programming, this will be pretty straightforward.

Variables & Assignment

To create a variable, you can do it through assignment. Let's use a string example:

name = "Alice"

You can re-assign variables. Types don't need to stay the same:

name = 2

You cannot create multiple variables this way on one line.

The following is illegal syntax

a, b = "one", "two"

instead, declare each variable on one line.

a = "one"
b = "two"

Data Types

RSL has 6 data types: strings, ints, floats, bools, lists, and maps.

string

Strings can be delimited in three ways:

  1. Double quotes: "text"
  2. Single quotes: 'text'
  3. Backticks: `text`

All three behave the same way. To demonstrate:

greeting = "Hello!"
print(greeting)

greeting = 'Hello!'
print(greeting)

greeting = `Hello!`
print(greeting)
Hello!
Hello!
Hello!

Why 3 different delimiters?

Having 3 different delimiters is particularly useful when you want your string to contain one (or more) of the delimiter characters.

For example, if you want a double quote in your string, you can use double quote delimiters and escape them:

"She said \"Goodbye\""

However, this can be finicky and hard to read. Instead, you can pick one of the other two delimiters, for example:

'She said "Goodbye"'
`She said "Goodbye"`

We'll cover this again later, but as a note, backticks can be particularly useful in shell commands, as shell/bash commands may include single or double quotes, and backticks save us from having to escape them.

Strings can include special characters such as \n for new lines and \t for tabs.

print("Hello\tdear\nreader!")
Hello   dear
reader!

Strings also support interpolation. String interpolation allows you to write expressions inside your string that will be evaluated and replaced for the final string. We'll cover this in more depth in a future section, but to give a very simple example:

name = "Alice"
print("Hi, {name}!")
Hi, Alice!

Anything encapsulated in a {} gets treated as an expression. Here, the expression is just the identifier name, which gets evaluated and substituted, giving us the final Hi, Alice! string.

Those are the basics for strings - we'll cover additional string concepts in a future section, Strings (Advanced).

int

RSL has ints. There's nothing unusual about them. Example:

team_size = 20
celsius = -5

Note that if you divide two ints, you will get back a float.

liters = 10
people = 4
print("This is a float:", liters / people)
This is a float: 2.5

float

The other number type is float:

length_meters = 2.68

If you want to define a whole number as a float, simply include a decimal place:

years = 20.0

bool

RSL uses lowercase true / false:

is_running = true
is_tired = false

list

RSL has two collection types: lists and maps. First, let's look at lists. These are also sometimes referred to as 'arrays' in other languages.

names = ["alice", "bob", "charlie"]

Lists you define can contain any types:

mixed = ["alice", true, 50, -2.4]

They can also be nested:

nested = ["alice", [1, ["very nested", "ahhh"]]]

Indexing and slicing works very similarly to Python. If we assume the 3 variables above exist, you can index with both positive and negative indexes:

print(names[0])
print(mixed[-1])  // grab last element in the list
print(nested[1][1][0])
alice
-2.4
very nested

And also you can slice:

numbers = [10, 20, 30, 40, 50]
print(numbers[1:3])
print(numbers[2:])
print(numbers[:-1])
[20, 30]
[30, 40, 50]
[10, 20, 30, 40]

map

The last type, and second of two collection types, is a 'map'. These may also be referred to as 'hashmap' or 'dictionary' in other languages.

scores = { "alice": 25, "bob": 17, "charlie": 36 }

Like lists, they can contain mixed types for values, and can nest. However, keys must be strings.

mixed_map = { 
  "alice": "accountant",
  "mylist": [ "London", 25 ],
}

nested_map = {
  "error": {
    "msg": "Request failed!",
    "code": 400,
  }
}

If we take the above example, values can then be accessed in two ways. First is the square bracket lookup:

print(mixed_map["alice"])
print(nested_map["error"]["msg"])
accountant
Request failed!

Alternatively, you can use a dot syntax. Note this second way only works for keys with no spaces in the name.

print(mixed_map.alice)
print(nested_map.error.msg)
accountant
Request failed!

You can modify maps using either syntax:

Using brackets
mymap = { "alice": 30 }

mymap["alice"] = 40
print(mymap)

mymap.alice = 50
print(mymap)
{ alice: 40 }
{ alice: 50 }

You can also add keys this way:

mymap = { "alice": 30 }
mymap["bob"] = 31
mymap.charlie = 32
print(mymap)
{ alice: 30, bob: 31, charlie: 32 }

Operators

RSL offers operators similar to many other languages. Below sections very quickly demonstrate.

Arithmetic

RSL follows the standard order of operations for operators () , + , - , * , / , %:

  1. Parentheses
  2. Multiplication, Division, Modulo
  3. Addition, Subtraction
print(1 + 4 / 2)    // 3
print(2.5 * 3 - 1)  // 6.5
print((4 + 5) * 2)  // 18
print(5 % 3)        // 2

Dividing two integers will result in a floating point number.

print(5 / 2)  // 2.5

Comparison

Comparisons return bools that can be used in e.g. if statements.

String comparison is done based on contents.

print("alice" == "alice")  // true
print("alice" == "bob")    // false
print("alice" != "bob")    // true
print("alice" == "Alice")  // false

Numbers can also be compared with the standard comparators > , >= , < , <= , ==.

print(2 >= 2)  // true
print(2 > 2)   // false
print(2 <= 2)  // true
print(2 < 2)   // false
print(2 == 2)  // false

You cannot use these operators (outside of ==) to compare non-numbers such as strings:

print("alice" > "bob")  // error

But you can check them for equality (will always return false, except ints and floats that are equal):

print(2 == "alice")  // false
print(2 == 2.0)      // true

Difference From Python on True == 1 and False == 0

In Python, False == 0 and True == 1 are true, because under the hood, False is really int 0 and True is really int 1, hence they're equal. That's not the case in RSL. In RSL, any two values of different types are not equal.

The reasoning stems from truthy/falsy-ness. In Python, both 1 and 2 are truthy. But only 1 equals True. RSL avoids this oddity of making 1 special by instead making any two different types not equal (except ints/floats).

Logical

RSL uses and and or for binary logical operations.

print(false and false)  // false
print(false and true)   // false
print(true  and false)  // false
print(true  and true)   // true

print(false or  false)  // false
print(true  or  false)  // true
print(false or true)    // true
print(true  or  true)   // true

And it uses not for logical negation.

print(not true)   // false
print(not false)  // true

Concatenation

You can concatenate strings with +.

first = "Alice"
last = "Bobson"
print(first + last)
Alice Bobson

You cannot concatenate a string and a non-string. First convert the non-string into a string.

This can be done in several ways, the easiest is probably via string interpolation:

a = 5
text = "Number: "
print(text + "{a}")
Number: 5

Compound Operators

a = 3
a += 2   // a is now 5
a -= 1   // a is now 4
a *= 3   // a is now 12
a %= 10  // a is now 2
a /= 4   // a is now 0.5

Increment / Decrement

You can quickly increment and decrement ints and floats using ++ and -- syntax.

a = 2
a++
print(a)

b = 2.5
b--
print(b)
3
1.5

The increment and decrement operators produce statements, not expressions. This means that a++ does not return anything, and so cannot be used inside e.g. a conditional.

For example, the following two uses are invalid, because a++ doesn't return a value:

a = 5
if a++ > 0:  // invalid, nothing for > to evaluate against on the left side
  ...

b = a++  // also invalid because a++ doesn't return any value

Because of that, there's also no reason to support pre-incrementing, and so ++a or --a are invalid statements.

Ternary

RSL supports ? : style ternary operators.

<condition> ? <true case> : <false case>

a = 5
b = a > 0 ? "larger than 0" : "less than 0"
print(b)
larger than 0

Control Flow

If Statements

RSL employs very standard if statements.

You are not required to wrap conditions in parentheses ().

if units == "metric":
  print("That's 10 meters.")
else if units == "imperial":
  print("That's almost 33 feet.")
else:
  print("I don't know what measurement system!")

For Loops

RSL allows "for each" loops for iterating through collections such as lists.

names = ["Alice", "Bob", "Charlie"]
for name in names:
  print("Hi {name}!")
Hi Alice!
Hi Bob!
Hi Charlie!

You can also iterate through a range of numbers using the range function, which returns a list of numbers within some specified range.

for i in range(5):
  print(i)
0
1
2
3
4

You can also invoke range with a starting value i.e. range(start, end) and with a step value i.e. range(start, end, step).

If you want to iterate through a list while also having a variable for the item's index, you can do that by adding in an additional variable after the for. The first variable will be the index, and the second the item.

names = ["Alice", "Bob", "Charlie"]
for i, name in names:
  print("{name} is at index {i}")
Alice is at index 0
Bob is at index 1
Charlie is at index 2

When iterating through a map, if you have one variable in the loop, then that variable will be the key:

colors = { "alice": "blue", "bob": "green" }
for k in colors:
  print(k)
alice
bob

If you have two, then the first will be the key, and the second will be the value.

colors = { "alice": "blue", "bob": "green" }
for k, v in colors:
  print(k, v)
alice blue
bob green
  • TBC
  • switch

Truthy / Falsy

RSL supports truthy/falsy logic.

For those unfamiliar, this means that, instead of writing the following (as an example):

if len(my_list) > 0:
    print("My list has elements!")

you can write

if my_list:
    print("My list has elements!")

Essentially, you can use any type as a condition, and it will resolve to true or false depending on the value.

The following table shows which values return false for each type. All other values resolve to true.

Type Falsy Description
string "" Empty strings
int 0 Zero
float 0.0 Zero
list [] Empty lists
map {} Empty maps

Note that a string which is all whitespace e.g. " " is truthy.

Converting Types

  • TBC
  • parsing
  • casting (once implemented)

Summary

  • We rapidly covered many basic topics such as assignment, data types, operators, and control flow.
  • RSL has 6 data types that map from JSON: strings, ints, floats, bools, lists, and maps.
  • RSL has operators such as + , - , * , / , %. For bool logic, it uses or and and.
  • RSL uses a "for-each" variety for loop. You always loop through items in a collection (or string).
    • If you want to increment through a number range, use the range function to generate you a list of ints.
  • RSL offers truthy/falsy logic for more concise conditional expressions.

Next

Good job on getting through the basics of the language!

Next, let's dive into one of the areas of RSL that make it shine: Args.