A statement is a basic unit of execution in Kal. It performs an operation. You have seen
stdout
in the previous chapter. It simply prints information to the screen.
Any information passed to a statement is its argument. A statement can have multiple arguments.
Take
stdout
for example.
stdout "Hello" " Kal! " "\n".
hello.kal
As you may have noticed, all Kal statements, except for preprocessor statements, beginning and ending of blocks end with a period (
.
).
You can also split statements across multiple lines as long as they end with a period.
stdout "Hello"
"Kal!"
"\n".
hello.kal
You don't always need to create and pass values immediately. You may want to store them beforehand, process them and use them later.
You can store values inside variables. Use
var
statements to create variables.
Variables can directly be used wherever needed.
var planet = "Earth".
stdout "From " planet "\n".
variables.kal
You can have as many
var
statements as needed.
When declaring a large number of variables together, the
var
statement can be extended using commas (
,
).
var name = "Kal", planet = "Earth".
stdout name " is from " planet "\n".
variables.kal
Variables are called “variables” for a reason. Their values can be changed.
You can reassign a value to a variable directly without using the
var
statement again.
var g = 10.
stdout "g = " g "\n".
;; Variable reassignment
g = 9.8.
stdout "g = " g "\n".
reassignVar.kal
Kal is dynamically typed. A variable can be reassigned to a value to different type.
var pi = "pi". ;; string
pi = 3.14. ;; float
dynamicReassign.kal
Wait, what were those semi-colons? Semi-colons in Kal are used to write comments. Comments are ignored by the Kal interpreter and are used to write instructions for the programmers.
Another use case is to comment out code which you don't wish to execute.
Kal supports both single-line and multi-line comments. Single-line comments start with
;;
and comment out everything till the end of the line.
On the other hand, multi-line comments start and end with
;
and can be used to comment as many lines as needed.
;; single line comment
;
multi
line
comment
;
stdout "Not a comment".
comments.kal
Kal offers 5 data types: Numbers, Strings, Lists, Dictionaries and Nulls.
Numbers support integers and floats together.
var pi = 3.14.
var value = 123.
numbers.kal
Strings represent textual data. They start and end with a double quote symbol (
"
).
Have you noticed that
\n
character before? That's an escape character. An escape character has a special meaning.
In this case,
\n
represents a new line. Every escape character starts with a backslash,
\
.
Kal supports the following escape characters.
| Name | Character |
|---|
| New Line | \n |
| Tab | \t |
| Backspace | \b |
| Backslash | \\ |
| Double Quote | \" |
| Carriage Return | \r |
Lists are collections of multiple values in a single container.
Lists start and end with
[
and
]
respectively with values separated by a comma (
,
).
var celestialBodies = ["Sun", "Earth", "Moon"].
lists.kal
If a list grows large, it can be split into multiple lines.
var celestialBodies = [
"Sun",
"Earth",
"Moon"
]. lists.kal
Lists in Kal are heterogenous. This means, you can have values of different types inside the same list.
As the complexity of your data grows, you can nest one list into another.
;; a 3x3 matrix
var matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]. nestedList.kal
You can use
[]
symbols to access values from the list via an index.
Index is the position of the item in the list. Indexes start from 0 in Kal.
var data = [1, 2, 3].
stdout "Value = " data[1] "\n".
listAccess.kal
Elements inside the list can also be reassigned in a similar fashion.
var data = [1, 2, 3].
stdout "Before = " data "\n".
data[1] = 20.
stdout "After = " data "\n".
listElementReassign.kal
A negative index can be used to access a list from the end. Negative indexes start with -1.
var data = [1, 2, 3].
stdout "Last = " data[-1] "\n".
data[-1] = 4.
stdout "Final = " data "\n".
negativeIndex.kal
Symbols
[]
can be chained together to get/reassign elements from/to a nested list.
;; 2x2 matrix
var matrix = [
[4, 5],
[6, 7]
].
stdout "--- Before ---\n".
stdout "Matrix = " matrix "\n".
stdout "Diagonal = " matrix[0][0] ", " matrix[1][1] "\n".
stdout "--- After ---\n".
matrix[0][0] = 10.
matrix[1][1] = 20.
stdout "Matrix = " matrix "\n".
stdout "Diagonal = " matrix[0][0] ", " matrix[1][1] "\n". nestedListReassign.kal
Similarly, Dictionaries are also heterogenous collections of elements in a key-value pair. A Dictionary starts with
#(
and ends with
)
.
var data = #(
planet -> "Earth",
species -> "Humans"
). dict.kal
Keys and values are separated by
->
whereas key-value pairs are separated by commas (
,
). Keys are stored as strings, whereas values can be of any type.
If keys contain spaces, surround them with double quotation marks (
""
).
var data = #(
planet -> "Earth",
species -> "Humans",
"total hours" -> 24
). dict.kal
Access symbols (
[]
) can be used to access a specific value using its key.
var data = #(
planet -> "Earth",
species -> "Humans",
).
stdout "Species = " data["species"] "\n". dictAccess.kal
Similarly, values can be reassigned.
var data = #(
planet -> "Earth",
species -> "Humans",
).
stdout "Before:\n".
stdout data "\n".
stdout "After:\n".
data["species"] = "Trees".
stdout data "\n". reassignValues.kal
You can add new key-value pairs in the same fashion.
var data = #(
planet -> "Earth",
species -> "Humans",
).
data["total hours"] = 24.
stdout data "\n". newPair.kal
Dictionaries can be nested.
[]
symbols can be chained together to access or reassign values.
var data = #(
planet -> "Earth",
resources -> #(
trees -> "Wood",
ores -> "Metals",
oceans -> "Water"
)
).
stdout data["resources"]["oceans"] "\n".
data["resources"]["oceans"] = "Salt".
stdout data["resources"]["oceans"] "\n". nestedDict.kal
Lists and Dictionaries can be nested within each other.
;; dict
var data = #(
planet -> "Earth",
;; nested list
resources -> ["Wood", "Metal", "Water"],
;; list
biomes -> [
;; nested dict
#(
land -> ["forest", "desert"],
),
#(
water -> ["ocean", "river"]
)
]
).
stdout data["resources"][2]
" comes from the "
data["biomes"][1]["water"][0] ".\n". nestedDictList.kal
Null represents absence of value. Variables set to
null
can be reassigned to actual values later.
var data = null.
stdout "Data = " data "\n".
data = 100.
stdout "Data = " data "\n".
null.kal
Uninitialized variables are set to
null
.
var data.
stdout "Data = " data "\n"
nullInitialize.kal
If you are unsure of the type of the variable you are dealing with, you can confirm it using the type statement.
So far you have seen statements that perform operations. Oftentimes that is not enough. You’ll also be requiring the end result of a statement. Kal statements return values wherever appropriate.
type
is one of those statements.
var name = "Kal".
type name -> t.
stdout "Type = " t "\n".
type.kal
Observe the syntax of the
type
statement:
type
is the name of the statement. name
is the argument passed to it. ->
is the target operator. t
is the variable that holds the return value.
The target operator assigns the return value to the provided variable. If the variable already exists, it's reassigned to hold the return value.
If not, a new variable is declared and the return value is assigned.
Alternatively, you can convert a statement into an expression by wrapping it into
$(
and
)
.
Doing so removed the need to use a target operator. The return value also becomes part of a larger expression.
var name = "Kal".
var t = $(type name).
stdout "Type = " t "\n".
typeExpr.kal
Conversion of types between numerical and string data is possible using the
as
operator.
The
as
operator takes the value to be converted as the first operand and the type to be converted to as the second operand.
var data = "123" as int.
stdout $(type data) "\n".
strToInt.kal
var data = 456 as str.
stdout $(type data) "\n".
intToStr.kal
var data = "3.14" as float.
stdout $(type data) "\n".
strToFloat.kal
Number is an umbrella term for both integers and floats.
Conversion of a float to integer removes the fractional part.
var data = 3.14 as int.
stdout data "\n".
stdout $(type data) "\n".
floatToInt.kal
Complicated data involving string literals and variables can be easily composed together. Formatted strings start with f( and end with ). Values encompassed inside these symbols are separated by commas.
The very first value is the template string which defines dynamic parts using
{}
as a place holder. Rest of the values are positionally placed inside the template string replacing their respective placeholders.
var string = f("Formatted {}!", "String").
stdout string "\n". fstr.kal
Variables can also be embedded dynamically.
var data = "String".
var string = f("Formatted {}!", data).
stdout string "\n". dynFstr.kal
Expressions are evaluated and used as values.
var string = f("5 + 8 = {}", (5 + 8)).
stdout string "\n". exprFstr.kal
There can be multiple placeholders and values to embed.
var string = f("{} + {} = {}", 5, 8, (5 + 8)).
stdout string "\n". multiFstr.kal
You can nest formatted strings together.
var string = f(
"For{} {}",
"matted",
f(
"Str{}{}",
"ing",
"!"
)
).
stdout string "\n". nestedFstr.kal
You may need to extract values from lists and dictionaries into distinct variables. This is called unpacking.
Use the list's
[
and
]
syntax to unpack variables from a list.
First, let's see how values are extracted without unpacking.
var data = [1, 2, 3].
var x = data[0],
y = data[1],
z = data[2].
stdout x " " y " " z "\n".
extractValues.kal
Compact this using unpacking.
var data = [1, 2, 3].
var [x, y, z] = data.
stdout x " " y " " z "\n".
unpack.kal
You are not required to unpack all values. Consider unpacking 2 values from a list of 3 values.
var data = [1, 2, 3].
var [x, y] = data.
stdout x " " y "\n".
partialUnpack.kal
Values are unpacked sequentially. The placeholder symbol,
_
is used to maintain the sequence without unpacking a value from that position.
Consider unpacking the first and third value from a list.
var data = [1, 2, 3].
var [x, _, z] = data.
stdout x " " z "\n".
placeholderUnpack.kal
The syntax can be nested to unpack more complex structures.
var data = [1, 2, [3, 4]].
var [_, x, [_, y]] = data.
stdout x " " y "\n".
nestedUnpack.kal
Here, data contains a nested list. The unpack syntax matches the same structure to extract 2 and 4.
Similarly, values can be unpacked from dictionaries.
var data = #(
planet -> "Earth",
species -> "Human"
).
var #(species) = data.
stdout "Hi " species "\n". dictUnpack.kal
List and Dictionary unpacking syntaxes can be combined together in case of nested structure.
var data = [
"Hi",
"Hello",
#(
name -> "Kal",
runsOn -> "Interpreter"
)
].
var [_, greet, #(name)] = data.
stdout greet " " name "\n". combinedUnpack.kal
Variables in Kal are evaluated as soon as they are initialized. It's possible to delay the evaluation to the point where the variable is actually used.
Similar to a
var
statement, the
inert
statement declares a lazy variable.
inert data = 5 + 8.
stdout data "\n".
inert.kal
In this case, the
data
variable was defined but its value was not evaluated immediately.
It's evaluated when it is used on the next line.
Let's look at another example which makes more sense.
var a = 20.
inert x = a + 10.
a = 90.
stdout x "\n".
lazyEval.kal
Let's break this down line by line.
- A variable
a
is initialized to value 20. - An inert variable
x
is lazily initialized to expression a + 10
. However, it's not evaluated immediately, so the final value 30 is never obtained. a
is reassigned to 90. x
is used by stdout
and thus the expression a + 10
is revisited and evaluated at this point. The value of a has changed to 90, therefore the final evaluated value of x
becomes 90 + 10 = 100
.
Inert variables may cause unintended side-effects and must be used with caution.
Since the evaluation is delayed for inert variables, you may use it in cases where regular variables may not work.
inert data = x + y. ;; no error
var x = 200,
y = 100.
stdout data "\n".
noErrInert.kal
So far you have used
stdout
which is used to write to the terminal.
stdin
allows you to read data from user input into a variable.
stdin "Name? " -> name.
stdout "Hello " name "\n".
stdin.kal