Programming introduction

Programming introduction

Author: Loading...

Work in progress

Introduction

Simba is a tool for automating tasks using programming, it can in theory automate anything, since it uses a fully featured programming language called Lape, it can be used for all sorts of tasks, tasks not even related to automations, yes, you can probably make silly games with Simba.

Learning Simba without a background in programming, without any programming experience can be valuable beyond Simba, concepts you learn using Simba can easily be translated to other programming languages. If you are confident in Lape, you can easily within very little time write code in say for example JavaScript, C, Python, and so on. You’d be able to read code in other languages without much strain, and without even knowing those languages. So I call this a programming introduction, not a Lape introduction, not a Simba introduction.

Follow this, use it as a reference, tinker around in Simba, in the end you might just be able to make a simple macro.

 

Basic datatypes

Simba uses a dialect of Pascal, which is influenced by Object Pascal, the language is called Lape. It’s a a strongly-typed programming language, which means that all variables must be declared with a specific datatype when they are created. There are several core datatypes in Pascal, here are the ones that come to mind:

Integer - An integer is a whole number without a decimal point. Lape provides several integer types, and the same type may have many names, byte, shortint, integer, and int64. The size of these types varies, with byte being the smallest (allowing values from 0 to 255) and int64 being the largest. For more details see the next section.

Float - A float is a floating-point number with a decimal point. Lape provides up to three float types, Single and Double, and possibly Extended. Single precision numbers occupy 4 bytes of memory. Double precision numbers occupies 8 bytes of memory. While extended, which only exists on x86 architecture will occupy 10 bytes.

Boolean - A Boolean variable can only have two values: True or False. In Lape, the boolean data type is called Boolean and occupies 1 byte of memory.

Char - A char is a single character such as ‘a’ or ‘9’. This datatype will occupy 1 byte of memory, an alias for this in lape is ansichar.

String - A string is collection of characters char, for example 'Hello world'. This datatype will occupy an undefined amount of memory, it depends on the length of the string.

These basic core datatypes are used extensively when programming, and are the building blocks for more complex data structures and objects. By understanding these basic datatypes, you can start to build more complex programs and applications in Simba.

 

Complex structures

Enum

Enum is a list of named values. For example, if you wanted to represent the days of the week, you could define an enum type called EDays with the values Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, and Sunday. Enums are useful for defining a set of related constants that have a specific meaning or purpose.

type
  EDayOfWeek = (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday)

var
  DayOfWeek = EDayOfWeek;
begin
  DayOfWeek := Wednesday;
  WriteLn DayOfWeek;
end.

Set

Set is a collection of values that builds on enums. A set is defined by listing the possible values inside parentheses. For example, if you wanted to define a set of colors, you could use the following syntax: type TColors = set of (Red, Green, Blue, Yellow);. Sets are useful for grouping related values and performing operations on them, such as intersection, union, and difference. A set would be defined much like an array, but holds several enum values, so it can be Red and Blue.

Record

Lape has a composite datatype called a record, which is the same as a struct in C, Java and PHP. A record is a collection of fields that can be of different datatypes, and is defined using the record keyword. For example, you could define a TStudent record with fields for Name, Age, and GPA. Records are useful for grouping related data together and passing it as a single unit.

type
  TStudent = record
    Name: string;
    Age: Int32;
    GPA: Double;
  end;

With this we have defined the structure, and how it looks, but this is just a definition. It doesn’t store anything. We can now create a variable of this datatype to store information about a student:

var
  john: TStudent;
begin
  john.Name := 'John Smith';
  john.Age  := 19;
  john.GPA  := 4.6;

  WriteLn john;
end;

There is an alternative way to initiate the record, which is shorter:

var
  john: TStudent;
begin
  john := ['John Smith', 19, 4.6];
  WriteLn john;
end;

Arrays

Arrays are another highly important structure when working with Simba and Lape. They are used to store collections of values of the same datatype. An array is defined by specifying the datatype of the elements and using the array keyword array of Int32. Arrays can be resized and manipulated while the program is running. Arrays are useful for storing and manipulating large amounts of data.

A real world analogy of arrays could be something like your collection of screwdriver bit sets, where each bit is stored in each their little holder (called element) in the box (the box is the array). The first bit is located at index 0 and the last would be located at ""the number of bits"" minus 1. Now a bitset is not usually stored in a straight series, but have rows, and such, but ignore that, think of them as in a line, where you can count them from start to finish. It may start out ordered, but you are free to screw up the order of that screwdriver bit sets. This is how arrays work, they do not care about the order the elements are in, and if you want it ordered, it’s up to you to maintain order.

There are a number of functions that relate to arrays, such as one function for checking how long the array is Length, which takes one argument, which is the array itself Length(myArray). The function High is much like length, but it subtracts 1 from the length, so that it represents the location of the last element in the array.

To access each individual element in the array you have to keep in mind that the array starts at 0, and ends at High(myArray) access it like myArray[0], myArray[1], myArray[2], etc. For normal simple usage accessing individual points like this isn’t often needed, but it’s important to know and understand these basics if you want to venture into this.

var
  myArray: array of Int32;
begin
  myArray := [1,2,3,4,5,4,3,2,1];
  WriteLn myArray;

  // access first element:
  WriteLn myArray[0];

  // access second element:
  WriteLn myArray[1];

  // access last item:
  WriteLn myArray[High(myArray)];
end;

In Simba, you will be working a lot with arrays, notably array of TPoint called TPointArray, but also a two dimensional array. This is an array of arrays. So every element in the array is another array.

 

Why specify types

Computers need to know about the type of data they are working with. There are different types of data, such as numbers and text, and each type has different requirements for processing. For example, when dealing with numbers, a computer needs to know if the number is a whole number or a decimal number, and how big or small the number can be.

When it comes to numbers, there are different types of data that a computer can use. For example, there are data types for floating-point numbers, which are decimal numbers that can be very large or very small. These types are called single (32-bit) or double (64-bit) depending on how much space they take up in the computer’s memory.

For whole numbers, there are different types of data that a computer can use depending on whether the number can be negative or not. For positive whole numbers, the computer can use unsigned integers, which come in different sizes such as uint8, uint16, uint32, and uint64. These sizes represent how many bits are used to store the number in memory.

For whole numbers that can be negative, the computer can use signed integers, which also come in different sizes such as int8, int16, int32, and int64. These sizes represent how many bits are used to store the number in memory, and whether the number can be negative or positive.

It’s important for programmers to choose the appropriate data type for the data they are working with, as this can affect how efficiently the program runs. Smaller data types may use less memory, but they may also be less precise or take longer to process, depending on a variety of variables. Different programming languages may use different names for these data types, but they all serve the same purpose of defining how data is stored in a computer’s memory.

 

Bits and Bytes

It may be helpful to understand the terms ""bit"" and ""byte"" for those who are unfamiliar with them.

A ""bit"" is the smallest unit in an electronic circuit. In the memory (a general term) of a computer, data is stored in ""cells"" where the cell is either on or off (1 or 0), which is a bit. For RAM and CPU cache, the computer stores data as a pattern of electric signals that represent either on or off (data is only stored while the computer is on). For a storage device like an HDD or SSD, the charge of 0 or 1 is permanently stored in the cell.

A ""byte"" is the smallest unit the processor can work with, defined as 8 bits. When the processor retrieves a number from memory, it cannot retrieve just one bit; it must retrieve at least 8 at a time, 8, 16, 32, etc., following the formula 2ⁿ where n > 3, this is an oversimplification and depends on CPU architecture, the actual smallest amount modern CPUs can extract is actually a ""cache line"". When data is retrieved from RAM, it is stored in the processor’s L-cache, which is a much faster memory but has way less space. L3 cache can be 64 MB, L2 can be 512 KB, while L1 can be 128 KB; L1 is the fastest. Considering cache is more relevant if you work in a truly native language (think like C, C++).

Size of numbers (can be useful reference in the future):

Size (bytes)Size (bits)Size unsigned integerRange
1 byte8 bits0 .. 255[0, 2⁸ - 1]
2 bytes16 bits0 .. 65,535[0, 2¹⁶ - 1]
4 bytes32 bits0 .. 4,294,967,295[0, 2³² - 1]
8 bytes64 bits0 .. 18,446,744,073,709,551,615[0, 2⁶⁴ – 1]

For integers with signs you can consider that half that range is sub-zero, other half is greater than or equal to zero, so 1 byte would allow a range from -128 to +127. While for advanced datatypes like floats, they simply loose accuracy, but can store way larger numbers at lower accuracy.

 

Keywords

A ""keyword"" is a word that is linked to an instruction in the language - keywords are thus a part of the language - integrated into the language definition itself. A keyword can in some cases have multiple meanings depending on the context.

Don’t be intimidated by the vague description, we will go into more detail on several of these in later parts.

Basic keywords:

  • program: Used to start the main program. program SomeName
  • begin: Marks the beginning of a block of code.
  • end: Marks the end of a block of code.
  • if, then: Used to define conditional statements. if is followed by the condition to evaluate, and then marks the beginning of the code to be executed if the condition is true.
  • else: Marks the beginning of the code to be executed if the condition in the preceding if-statement is false.
  • repeat, until: Used to create a loop that will run repeatedly until a condition is met.
  • for, to, do: Used to create a loop that will iterate over a range of values. for is followed by the variable that will be used to iterate, to defines the range of values, and do marks the beginning of the code to be executed in each iteration.
  • while, do: Used to create a loop that will run repeatedly as long as a condition is true. while is followed by the condition to evaluate, and do marks the beginning of the code to be executed in each iteration.
  • writeln: Used to print text to the debug box in Simba. Arguably not a keyword, but a ""compiler instruction""
  • break, continue: break is used to exit a loop prematurely, while continue is used to skip to the next iteration of a loop.
  • case: Used to define a conditional statement with multiple possible outcomes based on the value of a variable.

Declarative keywords:

  • function: Used to define a function that can be called from other parts of the program, a function returns something to the caller.
  • procedure: Used to define a procedure that performs a specific task, can be considered a subprogram in your main program.
  • var: Used to declare variables.
  • const: Used to declare a constant variable, whose value cannot be changed.
  • type: Used to define custom data types.
  • array: Used to define an array variable that can store multiple values of the same data type. Like a list of things.
  • record: Used to define a custom data type that can store multiple values of different data types.

 

Operators

A large number of the same symbols are used across different programming languages. Most of these symbols are operators, and they have an ""order of precedence"", which determines the order in which operations are performed. This is similar to mathematical expressions where + and - are performed after * and /, which in turn are performed after ** (exponentiation).

Important: Note the order in which they are listed, with the ones that are performed last being mentioned first. There may be some inaccuracies in this section, but it should give you a decent image of the order of precedence.  

Assign operators

Operators are used to assign a value to a variable. In the last example, a is already defined earlier, so we are just updating it.

OperatorSymbolExample
Assign:=a := 100
Add & assign+=a += 100
Subtract & assign-=a -= 100
Multiply & assign*=a *= 2
Divide & assign/=a /= 2
Power & assign**=a **= 2

These operations are combinations to shorten the code. Let’s say we have a variable named a with an unknown value, but you want to add 100 to the variable. The obvious solution would be to write:

a := a + 100

This can be shortened to:

a += 100

All the ""combo assign operators"" or ""c-operators"" work in a similar fashion. For example, -= subtracts the sum given on the right-hand side from the variable on the left-hand side and stores the result in the variable on the left-hand side. /= divides the variable on the left-hand side by the sum given on the right-hand side and stores the result in the variable on the left-hand side.

Comparison Operators

These operators are evaluated before logical operators, allowing the logical operators to work with the resulting True or False values. The following comparison operators are available:

OperatorSymbolExample
Equal to=10 = 2
Not equal to10 2
Less than10 > 2
Less than or equal to=10 >= 2

Addition Operators

Just like in mathematics these are computer after any multiplication, or division: | Operator | Symbol | Example | |------------------|--------|--------------| | Addition | + | 10 + 2 | | Subtraction | - | 10 - 2 |

Bitwise operations

Bitwise operators modify the bit structure of a number and are less commonly used in practice. They are often used for ""bit manipulation"" to optimize complex mathematical expressions for a machine. The following bitwise operators are available:

OperatorSymbolExample
Bitwise ANDand10 and 2
Bitwise ORor10 or 2
Bitwise XORxor10 xor 2
Shift Leftshl10 shl 2
Shift Rightshr10 shr 2
NOT/Invertnotnot 2

Logical operations

Logical operators combine two expressions to produce a logical result of either True or False. The three examples below result in True. We use the same operator as their binary equivalent, which may be a little confusing, but that’s Pascal, not common in other languages. | Operator | Symbol | Example | |------------------|--------|----------------------------------| | Logical AND | and | (10 + 2 = 12) and (5 + 1 = 6) | | Logical OR | or | (10 + 2 = 1) or (5 + 1 = 6) | | Logical NOT | not | not (10 + 2 = 1) |

In simplified terms:

  • True and True results in True (both expressions must be True)
  • True or False results in True (at least one expression must be True)
  • not False results in True (the expression is reversed)  

Multiplication operators

These are solved second to last: | Operator | Symbol | Example | |--------------------|--------------|------------------------------------------------------| | Division | / or div | 10 / 2, where div is floor division for integers | | Multiplication | * | 10 * 2 | | Remainder | mod | 10 mod 2 - Do not confuse this with modulus. |

This has to be solved before the ones over | Operator | Symbol | Example | |------------------|--------|----------| | Unary Minus | - | -999 |

This is solved first, even before unary minus. | Operator | Symbol | Example | |--------------------|--------|--------------| | Exponentiation | ** | 10 ** 2 |

So for example in the case of the power / exponentiation operator -10**2 is actually -(10**2).

To override the default order of operations, you can use parentheses ( and ) just like in mathematics. It may be helpful to use extra parentheses at first if you’re unsure, but it may quickly clutter up the code.

 

Comments

Comments can be written in the code, after the instruction (code), or on an empty line above or below by starting with the symbol //. For example:

var
  value: Double;
begin
  // This is the number pi
  value := 3.14159265; // in front is the number pi
  // Above is the number pi
end;

A multiline comment can be created by using { and } around the text, or alternatively using (* *):

{
This is a comment that spans
over several lines!!
}

Comments in the code are strongly recommended as you are often not the only one who will use this code, and it will make it easier for others to understand and possibly encourage reuse of your work.

 

Variables

Variables are essentially words that hold a value or data. Only letters (both upper and lower case) and underscores _ are allowed, and numbers can be used after that. In many languages it is important to distinguish between uppercase and lowercase letters as they are technically different words: X is not the same as x. But in Pascal (Lape/Simba) this is not the case, Pascal is a case-insensitive language, it will not distinguish between a word in lowercase, and the same word in uppercase. Variables are used to store data that can be used later in the program. Think of a variable as a container that can hold different types of information, such as numbers or text.

Thus, it is not allowed to start a variable name with a number, e.g. 3pi. Numbers can only come after the first letters or underscore. _3pi is allowed.

If you want to bind several words together under the same variable, it is not allowed to use spaces like this: rocket speed. You can write it in one of two ways: rocket_speed or rocketSpeed, where the latter is the preferred way. Note that I use a lowercase letter; this is appropriate because capitalized first letters usually indicate that this is the name of a function. Other languages have other naming conventions, and you can often find some sort of guideline for these language specific naming conventions.

Use of Variables:

  • Examples bellow follow the formula: `v0 = v1 + a t`*

Let’s take a variable named speed. We want it to contain the number 12, and another variable called time with a value of 604, and acceleration with a value of 2.1. We proceed as follows:

// declare the variables, and their datatype. Since they may contain decimals we use double.
var
  speed, time, acceleration, newSpeed: Double;

// start the code block with begin
begin
  // give values to the variables. They are by default `0`.
  speed := 12;         // 12 m/s
  time  := 604;        // 4 minutes
  acceleration := 2.1; // 2.1 meters per second
end;

We can now use these variables in an expression to create a fourth variable, a new speed, so before the end we add

  newSpeed := speed + acceleration * time;

and finally print it:

  newSpeed := speed + acceleration * time;
  WriteLn newSpeed;

So the codeblock (the area between begin and end) would look like this:

begin
  // give values to the variables. They are by default `0`.
  speed := 12;         // 12 m/s
  time  := 604;        // 4 minutes
  acceleration := 2.1; // 2.1 meters per second

  newSpeed := speed + acceleration * time;
  WriteLn newSpeed;
end;

We can also use compound operators to further increase the speed in the original variable speed instead of creating a new variable:

  speed += acceleration * time;
  WriteLn speed;

We have now stored the new velocity/value in the variable newSpeed, and we have updated the old variable speed with a new value.

We’ve looked at some examples with simple data types, and now let’s move on to something a little more complex: arrays. Arrays allow us to store multiple values in a single container. For instance, we can store several values for speed, time, and acceleration on the same line.

Here’s an example:

var
  speeds, times, accels: array of Double;
begin
  speeds := [12,   5.3,  3.7,  23];
  times  := [100,  35,   10,   60*3];
  accels := [0.1,  1.2,  2.1,  0.5];
end;

The elements in the array are numbered starting from 0, with the first element being element 0. We can access the elements of the array using their index. For example, speeds[0] corresponds to the first value in the speeds array, which is 12.

We can use the values stored in the lists to perform calculations, as in the following code:

var
  speed0, speed1, speed2, speed3: Double;
begin
  speed0 = speeds[0] + times[0] * accels[0];  // 12 + 100  * 0.1
  speed1 = speeds[1] + times[1] * accels[1];  // 5.3 + 35 * 1.2
  speed2 = speeds[2] + times[2] * accels[2];  // 3.7 + 10 * 2.1
  speed3 = speeds[3] + times[3] * accels[3];  // 23 + 60*3 * 0.5
end;

In the code above, we calculate the speed at different times using the values stored in the speeds, times, and accels lists.

You can also assign new values to elements in the list just as you would with a regular variable:

begin
  speeds[0] = 3;   // set speeds[0] to 3
  times[1] -= 30;  // subtract 30 from times[1]
  accels[3] = 0.5; // set accels[3] to 0.5
end;

This changes the value of the first element in the speeds list to 3, subtracts 30 from the second element in the times list, and changes the value of the last element in the accels list to 0.5.

This numbering system is similar to the mathematical convention of using subscripts (e.g., v₁, v₂, v₃) to denote different values of a variable in a formula.

Functions

Programming languages generally support functions, which are much broader than mathematical functions. Functions in programming are like mini-programs within the code that accomplish specific tasks, such as an algorithm, mathematical formula, or any task you want the program to perform later. Using functions can help you avoid writing repetitive code, and the code snippet within the function is not executed until you call the function later. This way, you can create a library of functions that you can use in multiple programs.

A function has a name and takes a certain number of arguments. If needed, it can return an answer that depends on the argument values. We will also discuss indentation and blocks. Indentation means to shift in. For instance, in Pascal, we indent with two spaces when creating a new block of code. The contents of a function is a new block and should be indented with two spaces.

Here’s an example of a function and how it’s used. Later, we’ll explain how it’s structured, pay no attention to the mathematical formula I chose, you don’t have to understand the formula itself to understand how to create a function:

(*
 returns the field strength / gravity of an object in space
 mass is given in 10²⁴ kg, and radius is given in kilometers
*)
function Gravity(mass, radius: Double): Double;
var
  gc: Double; //variable to hold the gravitational constant.
begin
  gc := 6.67*10**-11;
  Result := gc * (mass*10**24) / (radius*1000)**2;
end;

// Using the function:
var
  earthGravity, marsGravity, venusGravity: Double;
begin
  earthGravity := Gravity(5.974, 6371);
  marsGravity  := Gravity(0.64, 3400);
  venusGravity := Gravity(4.9, 6050);
end;

We can now use one of the built-in special function WriteLn to write the numbers in the debug box of Simba, so within that code-block, right before the end we can add the following:

  WriteLn(earthGravity);
  WriteLn(marsGravity);
  WriteLn(venusGravity);

in sum it should look like this:

function Gravity(mass, radius: Double): Double;
var
  gc: Double; //variable to hold the gravitational constant.
begin
  gc := 6.67*10**-11;
  Result := gc * (mass*10**24) / (radius*1000)**2;
end;

var
  earthGravity, marsGravity, venusGravity: Double;
begin
  earthGravity := Gravity(5.974, 6371);
  marsGravity  := Gravity(0.64, 3400);
  venusGravity := Gravity(4.9, 6050);

  WriteLn(earthGravity);
  WriteLn(marsGravity);
  WriteLn(venusGravity);
end;

We can also print it out in a slightly nicer and more organized way:

  WriteLn('Gravity on Earth: ', earthGravity, ' m/s^2');
  WriteLn('Gravity on Mars : ', marsGravity,  ' m/s^2');
  WriteLn('Gravity on Venus: ', venusGravity, ' m/s^2');

 

Let’s take a few steps back and go through the creation and use of a function. A function has a ""header"", that is, the definition of the function itself, this part defines what the function will be called, what the parameters of the function will be called, and the number of parameters, and what type the parameters are. Arguments are the data we send to the function when it is to be used, these arguments fill in the parameters.

The function keyword is used to indicate the beginning of a function definition. After this, we write the name of the function, for example, function Gravity, where Gravity is the name. Then we list the function parameters within parentheses, separated by commas and or semicolons. If there are no parameters, the parentheses should still be present after the name.

For example:

function Gravity(mass, radius: Double)
function NameAndAge(name: String; Age: Int32)
function SimpleFunction()

After this portion we have to define the output type. So for example, the function Gravity should always return a decimal number, so we will use double as the return type:

function Gravity(mass, radius: Double): Double;
function NameAndAge(name: String; Age: Int32): Int32;
function SimpleFunction(): Boolean;

Next, we start the function body. This may contain a number of variations, some functions need some variables, so we can declare them now, we can also declare types and constants, but not going to show that here, but it’s the same as declaring variables.

function Gravity(mass, radius: Double): Double;
var
  gc: Double;
begin

while others do not, we we can skip that

function SimpleFunction(): Boolean;
begin

Now, we can begin to write the code for the function. As previously mentioned, a function is like a small program within a program. It can be an algorithm, a simple mathematical formula, or a task that you want the program to perform. This code is not executed until you make a function call, which means you can have many functions that are not executed in one program.

The content of the function is a new block, and this block should be indented to show that it belongs to the function. When you start writing code in a new indentation level (2 spaces further to the right), you have left the current block.

A function does not necessarily need to return a value, these types of functions are in pascal called procedure. Returning means leaving the function and returning to the part of the code that called the function. This can be done in one of two ways, either by directly using the exit command or by letting the interpreter read the function to the end where there is an implicit exit (a hidden return).

Don’t worry if you don’t fully understand the math used in this example function. The focus here is on the overall structure of a function.

First, we define the function ""gravity"" with two parameters, ""mass"" and ""radius"", and then we define the type of both these parameters. Inside the function, we calculate the force of gravity using a formula and assign the result to the variable ""Result"". However, keep in mind that ""Result"" has no concrete value yet because we haven’t provided values for ""mass"" and ""radius"" - we haven’t used the function yet.

Result is a special variable, I do not declare it, it’s already declared by Lape when you create the function. It will contain the resulting value of our function, which will be returned to the caller.

To use the function, we need to ""call"" it by providing the required arguments. Each argument should be separated by a comma and should match the order and type of the parameters in the function definition. In this case, we specify the values for mass and radius as 5.974 and 6371, respectively, and the result of the function call is stored in the variable named ""Result"" before it is returned.

The we close the block, which we started with begin, by adding an end after the contents of the function.

Here is the complete code:

function Gravity(mass, radius: Double): Double;
var
  gc: Double; //variable to hold the gravitational constant.
begin
  gc := 6.67*10**-11;
  Result := gc * (mass*10**24) / (radius*1000)**2;
end;

Which we can now call, and print to the debug box in Simba:

begin
  WriteLn Gravity(5.974, 6371);
end;

I also mentioned the exit command, the function could use that instead of the implicit return, like so:

function Gravity(mass, radius: Double): Double;
var
  gc: Double; //variable to hold the gravitational constant.
begin
  gc := 6.67*10**-11;
  Exit(gc * (mass*10**24) / (radius*1000)**2);

  // any code here bellow that exit will never be executed
end;

 

If-statements

If-statements are used in code to execute a part of it only if a certain condition is met. The condition is usually a logical or mathematical expression that evaluates to either True or False, which are values of the boolean data type. To use an if-statement, you write the keyword if, followed by the condition and a then. The code that should be executed if the condition is True is written in a new code-block under the if-statement.

begin
  if 100 = 100 then
  begin
    WriteLn('It seems that 100 is in fact 100!');
  end;
end;

You can also add an ‘else if’ statement, to test for another condition if the previous one was not met. You may add as many ‘else if’ statements as needed.

begin
  if 100 = 100 then
  begin
    WriteLn('It seems that 100 is in fact 100!');
  end
  else if 100 = 150 then
  begin
    WriteLn('It seems as though logic is broken, because this is impossible');
  end;
end;

Lastly, you can add an ‘else’ statement to the end of the block of ‘if’ and ‘else if’ statements. This block of code will be executed only if none of the previous conditions are met. The ‘else’ statement doesn’t require a condition, just the keyword ‘else’.

begin
  if 100 = 100 then
  begin
    WriteLn('It seems that 100 is in fact 100!');
  end
  else if 100 = 150 then
  begin
    WriteLn('It seems as though logic is broken, because this is impossible');
  end
  else
  begin
    WriteLn('Well, this is interesting...');
  end;
end;

Now this looks quite lengthy for such a piece of code, and in fact it is. In any case where you only have a single statement after the conditional, you can drop writing ""begin"" and ""end"", this also requires you to trim away the semicolons after each statements:

begin
  if 100 = 100 then
    WriteLn('It seems that 100 is in fact 100!')
  else if 100 = 150 then
    WriteLn('It seems as though logic is broken, because this is impossible')
  else
    WriteLn('Well, this is interesting...'); // b then
    WriteLn('a is greater than b')
  else if a  to  do
  begin
    { statements to be executed }
  end;
end;

The counter variable (known as iterator) is the loop control variable that is initialized to , and the loop executes until counter reaches the , this is an inclusive value. The specifies the increment or decrement value of counter after each iteration. This is not something that exists in Pascal languages in general, and is a quirk of the Lape dialect.

For example, the following for-loop prints the numbers 0 to 10:

var i: Int32;
begin
  for i:=0 to 10 do
  begin
    WriteLn(i);
  end;
end;

In this example, i is the iterator that is initialized to 0 and incremented by 1 after each iteration. The loop executes until i reaches 10.

The following for-loop prints the even numbers from 2 to 10:

var i: Int32;
begin
  for i := 2 to 10 with 2 do
  begin
    WriteLn(i);
  end;
end;

You can also use a for-loop with an array, there are two ways of doing this. For example, the following for-loop calculates the sum of an array:

var
  arr: array of Int32;
  sum, i: Int32;
begin
  arr := [1,2,3,4,5,6,7,8,9];
  for i:=0 to High(arr) do
  begin
    WriteLn('Adding current value to sum: ', arr[i]);
    sum := sum + arr[i];
  end;
  WriteLn('The sum is: ', sum);
end.

In this example, the arr array contains 9 integers, and the for-loop reads each integer and adds it to the sum variable. The loop executes until i reaches High(arr) which is equal to the length of the array minus one.

The other way is to use the for-in-do loop, which is another one of Lapes special features:

var
  arr: array of Int32;
  sum, element: Int32;
begin
  arr := [1,2,3,4,5,6,7,8,9];
  for element in arr do
  begin
    WriteLn('Adding current value to sum: ', element);
    sum := sum + element;
  end;
  WriteLn('The sum is: ', sum);
end.

This may in a lot of cases be a better, simpler solution when dealing with arrays.

 

In conclusion, for-loops in Lape are an essential tool for executing a set of statements repeatedly. They provide a straightforward and flexible way to perform iterative tasks, such as printing values or iterating over arrays. Understanding how to use for-loops in Lape is critical for any programmer who wants to create efficient and effective programs.

 

While loops

Much like for loops, while loops repeat the contents of the loop, until the condition is no longer met. They are in a sense equal to if-statements your learned about above, in the sense that they only enter the loop block when the condition is met. And they will repeat going into it until the condition is no longer met.

while True do
begin
  // do something
end;

This is a basic while-loop that never ends, it’s condition is always True.

Another simple example would be a counting loop, say we want to count to 10, with a 1 second interval between:

var
  counter: Int32;
begin
  counter := 1;
  while counter <= 10 do
  begin
    WriteLn('The value is: ', counter); // Write the value to debug box

    Sleep(1000); // wait for 1000 milliseconds (or 1 second)

    counter += 1; // increase the counter by 1 for next iteration.
  end;
end;