Basics
This section of the guide will rapidly cover the basics of Rad. Rad shares a lot of conventions and syntax with popular languages like Python, so if you're familiar with programming, this will be a breeze.
Variables & Assignment¶
To create a variable, you can do it through assignment. Let's use a string example:
1 |
|
You can re-assign variables. Types don't need to stay the same:
1 2 |
|
Data Types¶
Rad has 6 basic types: strings, ints, floats, bools, lists, and maps.
string¶
Strings can be delimited in three ways:
- Double quotes:
"text"
- Single quotes:
'text'
- Backticks:
`text`
All three behave the same way. To demonstrate:
1 2 3 |
|
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 those 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¶
Rad 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¶
Rad uses lowercase true
/ false
:
is_running = true
is_tired = false
list¶
Rad has two collection types: lists and maps. First, let's look at lists.
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. Using the above 3 variables for an example, 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
You can also 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 other collection type is '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.
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:
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 }
Other Types¶
Rad has other types that we won't cover here. For example null
and function references.
Operators¶
Rad offers operators similar to many other languages. Below sections very quickly demonstrate.
Arithmetic¶
Rad follows the standard order of operations for operators () , + , - , * , / , %
:
- Parentheses
- Multiplication, Division, Modulo
- 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
You can multiply strings to repeat them:
name = "alice"
print(name * 3) // alicealicealice
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) // true
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 Rad. In Rad, any two values of different types are not equal (except ints/floats).
The reasoning stems from truthy/falsy-ness. In Python, both 1
and 2
are truthy. But only 1
equals True
.
Rad avoids this oddity of making 1
special by instead making any two different types not equal (except ints/floats).
Logical¶
Rad 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 can concatenate strings with non-strings, as long as the string is the first operand. This means you may need to convert the non-string to a string first.
This can be done in several ways, the easiest is probably via the str
function.
a = 1
text = ". Bullet point one"
print(str(a) + text)
1. Bullet point one
Compound Operators¶
Rad also supports compound operators for modifying variables in-place.
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¶
Rad 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¶
Rad 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!")
Blocks use whitespace & indentation
Note that Rad uses whitespace & indentation to denote blocks, instead of braces.
As a convention, you can use 4 spaces for indentation. Mixing tabs and spaces is not allowed.
For Loops¶
Rad 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
A useful function to know when iterating is zip
.
It lets you combine parallel lists into a list of lists. To demonstrate:
1 2 3 4 |
|
These inner lists can then be unpacked by specifying the appropriate number of identifiers in a for loop:
1 2 3 4 |
|
alice 30
bob 40
charlie 25
Use of _
Note the use of _
in the above for loop. It technically is the index, previously denoted by i
, but by convention,
we use _
to indicate that a variable is unused.
Switch Statements¶
Rad has switch statements and switch expressions.
You can switch
on a value and write cases to match against, including a default
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Cases can be written as blocks or single-line expressions.
For example, the above default
could be made into a single line:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
The above examples are switch statements, because they do not return anything. Switch expressions can be used in assignments.
1 2 3 4 5 6 7 8 9 |
|
The above example cases are all single-line expressions (case ... -> ...
).
If you want to write a case as a block in a switch expression, you can use the yield
keyword to return values (yes plural, switch cases can return multiple values).
1 2 3 4 5 6 7 8 9 10 11 |
|
Truthy / Falsy¶
Rad supports truthy/falsy logic.
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 |
Blank strings and null
- A string which is all whitespace e.g.
" "
is still truthy. null
is falsy.
Converting Types¶
Converting types may involve simple casts, or parsing.
When casting, you can use the following functions:
str
, int
, float
print(int(2.1)) // 2
print(float(2)) // 2.0
print(str(2.2)) // "2.2"
Note that int
and float
will error on strings. To parse a string, use the following functions:
parse_int
, parse_float
print(parse_int("2")) // 2
print(parse_float("2.2")) // 2.2
print(parse_int("2.2")) // error
print(parse_float("bob")) // error
Summary¶
- We rapidly covered many basic topics such as assignment, data types, operators, and control flow.
- Rad has 6 basic types: strings, ints, floats, bools, lists, and maps.
- Rad has operators such as
+ , - , * , / , %
. For bool logic, it usesor
andand
. - Rad 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.
- If you want to increment through a number range, use the
- Rad offers truthy/falsy logic for more concise conditional expressions.
- Rad has switch statements and expressions. The latter uses
yield
as a keyword to return values from cases. - Rad has functions for casting
str
,int
,float
and for parsingparse_int
,parse_float
values.
Next¶
Good job on getting through the basics of the language!
Next, let's dive into one of the areas of Rad that make it shine: Args.