Procedural programming Reference

# Getting started

## Select the procedural programming profile

To undertake procedural programming (PP) in Elan, ensure that Elan is set to the Procedural profile from the menu at the top of the IDE. This will ensure that:

- The list of demo programs will now show only programs that use PP.
- The options shown on the new code menus in the editor are all appropriate to PP. These are listed below under Global Instructions and Statement Instructions.

# Why coding with Elan is different

To start programming with Elan, first familiarise yourself using the Elan IDE, and especially with entering and editing code, by watching the videos in this document [LINK REQUIRED]. You will learn, therein, that Elan supports programming in Python, VB, C#, or Java (as well as the Reference Language), and offers the option of immediate translation between all four languages - either way - if desired. However, if you have previously programmed in any of those languages you will finds that Elan enforces a few constraints on how code is written. There are three forms of these constraints:

- Enforced best practices in coding
- Use of a common library across all the supported languages.
- Some, generally smaller, constraints required by the need for portability across languages.

These are described in more detail below

## Enforced best practices in coding

Elan supports, and in many cases enforces a set of good programming practices. This applies across all the supported languages - even where a language, if used outside Elan, would allow you to do otherwise. In the context of procedural programming - where the procedural profile has been selected in the IDE, there are seven such best practices.

Some of these best practices are widely recognised, others less so. Some programmers will argue that there are very specific circumstances where breaking the rules should be acceptable. The problem with this line of argument is that most of the places where even professional programmers break the rules don't fit those circumstances - they are broken because the programmer just finds it more convenient. It is far better that you learn to program without breaking these rules than that you adopt bad habits from the beginning. This will result in you writing better code, and encountering fewer unexpected problems.

The seven best practices enforced by Elan - for procedural programming, this is -are:

[INSERT TOC of the h3 headings in this section]

### No global variables

It is widely recognised that global variables are a bad idea - encouraging poor program structure and leading to unexpected behaviour. Yet most programming languages permit them. The Elan editor solves this by offering the variable definition instruction only within the main routine, functions, or procedures. At global level the only permitted definition of a named value is a constant, and that, too, is constrained to be of a type that cannot be mutated by any instruction in the program.

In Java, all code must be within a class. Elan provides a boilerplate class named `Global Code does not parse as Elan.Global Code does not parse as Elan.Global Code does not parse as Elan.Global Code does not parse as Elan.Global Code does not parse as Elan.` to adhere to this rule, and all code must be added within this, and everything added immediately within the `Global Code does not parse as Elan.Global Code does not parse as Elan.Global Code does not parse as Elan.Global Code does not parse as Elan.Global Code does not parse as Elan.` is deemed, in Elan terms, to be 'global code', so you will not be able to add a variable - even in the form of a 'property' there.

### Static typing

Static typing means that the type of any variable, or parameter, or value returned by a function, is known at compile time, and that type never changes, even though the value may change. VB, C#, and Java, are inherently statically-typed. Python is inherently dynamically-typed but since Python 3.5 has offered the option to add 'type hints' which allow working in a statically typed manner. While some programmers like the idea of dynamic typing, there is almost no need for it in most forms of programming, and it is well established that dynamic typing does not work well when building large, complex systems. Moreover, in a pure educational context, using static typing gives a stronger understanding that, in all modern languages, statically- or dynamically-typed, all data elements have an associated type - and static typing helps you to understand the nature of those types. When entering/editing Python, Elan therefore enforces the use of type hints where needed.

Elan requires types to be specified for all parameters for procedures or functions, and for the return type of a function.

Elan does not, however, require the type to be specified explicitly for any variable (or constant) because the type is inferred from the initial value given to it.

### No null references

All programmers have encourntered the notorious 'Null Reference ...` (or 'Null Pointer ...`) error message, and these can sometimes be very hard to track down. Tony Hoare, Turing Medal recipient and one of Britain's greatest computer scientists, magnanimously described his invention of 'null' as a Billion Dollar Mistake.

All the supported programming languages inherently permit null reference errors - but when you are coding in Elan it is impossible for one to arise because:

- Every variable definition must specify an initial value.
- It may never be reassigned to null.
- (Additional, related rules are enforced in object-oriented programming.)

### No breaking out of loops before they have completed

Python, C#, and Java all have a break instruction (the VB equivalent is exit) which allow you to break out of a loop. Elan does not permit any of those instructions to be used. Why?

The break instruction (or equivalent) was invented when the only possible kind of loops that programming languages supported executed a specified number of times - there were no 'conditional loops'. With the advent of 'structured programming' came proper conditional loops, of which the most common form is the 'while loop'. After structured programming it is never necessary to break out from a loop before its natural termination.

### Return from a function or procedure only after the final instruction

This principle is somewhat analogous to the previous one - where programmers find it 'convenient' to include multiple `returnreturnreturnreturnreturn` statements within a procedure or a function. All the supported languages permit this in most other environments. Elan, however, deliberately prevents this practice. In Elan a function always has a return statement as its last instruction (which specifies the value to be returned), and there is no option to add another one earlier. And in Elan a procedure never has a return instruction - the procedure exits after the last instruction.

But where is the harm in 'early returns'? Here are four answers:

- You cannot jump into the middle of a procedure or function, nor should be able to jump out of it in the middle
- They lead to poorly-structured code
- They make it harder to debug code - because you may need to find, and put a separate break-points on each return instruction.
- When you change the requirements of the function - for example that the returned string is always uppercase - you need to enforce this in several places, and you run the risk of overlooking one them. (Some languages offer a 'finally' clause to make that easier - but this is really just a kludge to paper over the cracks of poor structure.)

Some programmers argue that the constraint of no early returns in a function, means you have to write an extra line of code at the start to define a variable that holds the result. True - but that's a small price to pay, and it also makes your code more readable.

### All functions must be pure

Many textbooks draw no distinction between procedures and functions, except that the latter return a value to the calling code. Used properly, the two are distinct in another, very important, respect.

#### Understanding procedures

A procedure:

- can be thought of as a way of adding you own custom instruction to the language
- makes a change to the state of the system: which might be a result printed on the screen or saved to a file, or maybe changing the data it was given, such as sorting a list (for example, the 'in place' Ripple Sort demo)
- may depend on the system in others ways, for example requesting a response from the user
- should be called in isolation, never within an expression.

By contrast, a properfunction:

- can be thought of as a way of adding a custom operator to the language - a way to derive a new value from values provided.
- does not make any change to the state of the system. The only observable effect of calling a function is the returned value, which is held, temporarily, only on the stack, to be consumed by something else. Another way to say this is that a function creates no side-effects,
- may not depend on the system. The value returned must depend solely, and deterministically, on the values provided as parameters.
- should always be called within an expression (or as the complete expression), never in isolation - also known as a 'hanging function call'.

Although some programming languages make a syntactic distinction between a procedure and a function (some don't), the only ones that enforce the distinctions made above are the 'pure' functional programming languages, such as Haskell, OCAML, F# ...

Elan ensures that all functions are proper functions, but places no restrictions on what you can do in a procedure (except return a value). In the long term, if you wish to progress further with programming, laying this foundation will make it far easier for you to transition to 'functional programming' than otherwise. But making this distinction from the outset offers more immediate benefits:

- Fewer bugs - specifically those arising from the unforseen clashes between the side-effects of procedures.
- Easier to 'reason about' the correctness of the program, because functions then behave like mathematical functions. Specifically if function foo is correct, and function bar is correct, then combining them in any way is also correct code. That cannot be inferred from combining two procedures.
- Functions can be more easily tested, which leads us on to our last best practice, here ...

### Every function should be unit tested

Historically, most testing of programs was done by humans, running through a large number of 'test scripts' (or 'cases') manually to check that the delivered system worked correctly, then again after every single change or extension to the system, to ensure that existing functionality had not been broken accidentally.

In recent years, the emphasis as shifted to automated testing. Although writing the test scripts/cases still takes, once written, all the tests can be run repeatedly at the touch of a button, and even triggered automatically by any change to the code.

There are many forms of automated testing, but 'unit testing' is the most popular. All modern languages offer a 'unit testing framework', but they vary considerably in how easy they are to write or run.

Unit tests are intended for testing proper functions though many do not enforce that. But running unit tests on procedures, or improper functions (that create side effects) is dangerous - running the tests might result in data being written to a file or database, or a network message being sent repeatedly, for example. There are software frameworks for automated tesing of procedures and even whole applications (known as 'end to end testing') - but these frameworks are much harder to use.

Many professional software development teams enforce the writing of unit tests for every function, but this is typically something that most programmers don't discover unless they turn professional. But it is a practice that even complete beginners would benefit from:

- It gives you confidence that code is correct, especialy code that you haven't looked at recently.
- It gives you an immediate sense of reward when all the tests 'go green' (pass).
- It gives you confidence to improve existing code (also known as 'refactoring') without the fear of unknowingly breaking it in subtle ways.

Elan provides unit testing, for all the supported languages, that is even simpler to use (both for writing the tests and running them) than most other tools. Although it does not enforce the rule that every function written should have automated unit tests, it does make it so easy, that it hopefully encourages learners to use the practice

## Use of a common library across all the supported languages.

All programming languages have their own standard libraries for:

- mathematical and scientific functions
- manipulating strings, lists, and other data structures
- textual input/output
- graphics

and more. There are many similarities between the libraries of different languages, but also significant differences. Elan defines its own library which offers the identical functions in each of the supported languages. The Elan library has been designed to find as much common ground as possible but, inevitably, it is not identical to the standard library for any of the supported languages.

One consequence of this is that even though the Python, C#, VB, or Java code generated within Elan is always syntactically valid for the language, you won't typically be able to run exported code in another environment without editing the library calls. (We hope to provide automated, or semi-automated, tools for this in future.)

## Other constraints

Elan enforces a few other constraints that aren't driven by best practices, or by the common library, but because of small arbitrary differences between the target languages. Fortunately these are quite small both in number and impact. There is no need to learn them explicitly, because in all cases where you might encounter one, you will get a clear error message that gives you the solution. But here is a list of the most important ones:

- Elan is case-sensitive for identifiers, but you deliberately cannot define two identifiers in the same scope that differ only by case.
- All languages disallow the use of certain reserved words as identifiers. Elan deliberately disallows the reserved words from all the supported languages - so that translations are guaranteed to run.
- Literal strings must be bounded by double-quotes, not by single-quotes
- Some languages distinguish between a 'for loop' and a 'for each loop'. Elan, like Python, uses the same syntax for both. When you for loop in Elan the syntax in VB, C#, and Java will be that of a 'for each' loop.
- Raising a number to a power must be done with the pow function: the 'power operator' symbols will not be recognised in the languages that have them.
- Individual values are extracted from a tuple using the syntax `myTuple.item_0myTuple.item_0myTuple.item_0myTuple.item_0myTuple.item_0`, `myTuple.item_1myTuple.item_1myTuple.item_1myTuple.item_1myTuple.item_1` etc. Dedicated 'Tuple deconstruction' syntax is not recognised for any of the languages.
- Equality testing of value types uses the equality operator for each language e.g. `a is ba == ba == ba = ba == b`, but if the types are reference types (e.g. lists or strings) you must use the syntax `a.equals(b)a.equals(b)a.equals(b)a.equals(b)a.equals(b)`
- Division of two floating point numbers (or one floating point and one integer) may use the division operator - e.g. `a/ba/ba/ba/ba/b` - and the result will always be floating point. But if both values are integer type then you must use either `divAsInt(a, b)divAsInt(a, b)divAsInt(a, b)divAsInt(a, b)divAsInt(a, b)` or `divAsInt(a, b)divAsInt(a, b)divAsInt(a, b)divAsInt(a, b)divAsInt(a, b)` to make clear which result you are looking for (divAsInt will round down the result if necessary).
- 2-dimension arrays are implemented as a list of lists. However,
- Negative index values, and index ranges are not supported, but you can use subString or subString to achieve the same effect.
- Passing by reference, if wanted, is done by, for example, wrapping a parameter of type `IntintintIntegerint` as a `Ref Code does not parse as Elan.Ref Code does not parse as Elan.Ref Code does not parse as Elan.Ref Code does not parse as Elan.Ref Code does not parse as Elan.`.

# Global instructions

Global instructions are placed directly in your code file. They are never indented from the left-hand edge, nor may they be located within other instructions.

## Main routine

### Examples of main routines

p>From the Burrow demo. For very simple applications like this, the main routine is the whole program:
+main 1 variable blocks name? set to createBlockGraphics(white)value or expression?2 variable x name? set to 20 value or expression?3 variable y name? set to 15 value or expression?4 +while true condition? 5 reassign blocks[x][y]variableName? to red value or expression?6 call displayBlocks procedureName?(blocks arguments?)7 reassign blocks[x][y]variableName? to black value or expression?8 variable direction name? set to randint(0, 3)value or expression?9 +if direction is 0 condition? then 10 reassign x variableName? to min([x + 1, 39])value or expression?11 elif direction is 1 condition? then 12 reassign x variableName? to max([x - 1, 0])value or expression?13 elif direction is 2 condition? then 14 reassign y variableName? to min([y + 1, 29])value or expression?15 elif direction is 3 condition? then 16 reassign y variableName? to max([y - 1, 0])value or expression?17 end if end while end main
+def main() -> None: 1 blocks name? = createBlockGraphics(white)value or expression? # variable definition 2 x name? = 20 value or expression? # variable definition 3 y name? = 15 value or expression? # variable definition 4 +while True condition?: 5 blocks[x][y]variableName? = red value or expression? # reassign variable 6 displayBlocks procedureName?(blocks arguments?) # call procedure 7 blocks[x][y]variableName? = black value or expression? # reassign variable 8 direction name? = randint(0, 3)value or expression? # variable definition 9 +if direction == 0 condition?: 10 x variableName? = min([x + 1, 39])value or expression? # reassign variable 11 elif direction == 1 condition?: # else if 12 x variableName? = max([x - 1, 0])value or expression? # reassign variable 13 elif direction == 2 condition?: # else if 14 y variableName? = min([y + 1, 29])value or expression? # reassign variable 15 elif direction == 3 condition?: # else if 16 y variableName? = max([y - 1, 0])value or expression? # reassign variable 17 main()
+static void main() { 1 var blocks name? = createBlockGraphics(white)value or expression?;2 var x name? = 20 value or expression?;3 var y name? = 15 value or expression?;4 +while (true condition?) { 5 blocks[x][y]variableName? = red value or expression?; // reassign variable 6 displayBlocks procedureName?(blocks arguments?); // call procedure 7 blocks[x][y]variableName? = black value or expression?; // reassign variable 8 var direction name? = randint(0, 3)value or expression?;9 +if (direction == 0 condition?) { 10 x variableName? = min([x + 1, 39])value or expression?; // reassign variable 11 } else if (direction == 1 condition?) {12 x variableName? = max([x - 1, 0])value or expression?; // reassign variable 13 } else if (direction == 2 condition?) {14 y variableName? = min([y + 1, 29])value or expression?; // reassign variable 15 } else if (direction == 3 condition?) {16 y variableName? = max([y - 1, 0])value or expression?; // reassign variable 17 } // if } // while } // main
+Sub main() 1 Dim blocks name? = createBlockGraphics(white)value or expression? ' variable definition 2 Dim x name? = 20 value or expression? ' variable definition 3 Dim y name? = 15 value or expression? ' variable definition 4 +While True condition? 5 blocks[x][y]variableName? = red value or expression? ' reassign variable 6 displayBlocks procedureName?(blocks arguments?) ' call procedure 7 blocks[x][y]variableName? = black value or expression? ' reassign variable 8 Dim direction name? = randint(0, 3)value or expression? ' variable definition 9 +If direction = 0 condition? Then 10 x variableName? = min({x + 1, 39})value or expression? ' reassign variable 11 ElseIf direction = 1 condition? Then 12 x variableName? = max({x - 1, 0})value or expression? ' reassign variable 13 ElseIf direction = 2 condition? Then 14 y variableName? = min({y + 1, 29})value or expression? ' reassign variable 15 ElseIf direction = 3 condition? Then 16 y variableName? = max({y - 1, 0})value or expression? ' reassign variable 17 End If End While End Sub
public class Global {
+static void main() { 1 var blocks name? = createBlockGraphics(white)value or expression?;2 var x name? = 20 value or expression?;3 var y name? = 15 value or expression?;4 +while (true condition?) { 5 blocks[x][y]variableName? = red value or expression?; // reassign variable 6 displayBlocks procedureName?(blocks arguments?); // call procedure 7 blocks[x][y]variableName? = black value or expression?; // reassign variable 8 var direction name? = randint(0, 3)value or expression?;9 +if (direction == 0 condition?) { 10 x variableName? = min([x + 1, 39])value or expression?; // reassign variable 11 } else if (direction == 1 condition?) {12 x variableName? = max([x - 1, 0])value or expression?; // reassign variable 13 } else if (direction == 2 condition?) {14 y variableName? = min([y + 1, 29])value or expression?; // reassign variable 15 } else if (direction == 3 condition?) {16 y variableName? = max([y - 1, 0])value or expression?; // reassign variable 17 } // if } // while } // main
}

From the Ripple Sort demo. The main routine defines the list to be sorted, delegates most of the work to the inPlaceRippleSort procedure (not shown here), then prints the sorted list:

+main 1 variable li name? set to [3, 6, 1, 0, 99, 4, 67]value or expression?2 call inPlaceRippleSort procedureName?(li arguments?)3 print(li arguments?)4 end main
+def main() -> None: 1 li name? = [3, 6, 1, 0, 99, 4, 67]value or expression? # variable definition 2 inPlaceRippleSort procedureName?(li arguments?) # call procedure 3 print(li arguments?)4 main()
+static void main() { 1 var li name? = [3, 6, 1, 0, 99, 4, 67]value or expression?;2 inPlaceRippleSort procedureName?(li arguments?); // call procedure 3 Console.WriteLine(li arguments?); // print 4 } // main
+Sub main() 1 Dim li name? = {3, 6, 1, 0, 99, 4, 67}value or expression? ' variable definition 2 inPlaceRippleSort procedureName?(li arguments?) ' call procedure 3 Console.WriteLine(li arguments?) ' print 4 End Sub
public class Global {
+static void main() { 1 var li name? = [3, 6, 1, 0, 99, 4, 67]value or expression?;2 inPlaceRippleSort procedureName?(li arguments?); // call procedure 3 System.out.println(li arguments?); // print 4 } // main
}

From the Life procedural demo. The whole program is 157 instructions (including tests), but the main routine contains just 9. It is good practice to keep the main routine small.

+main 1 variable grid name? set to createBlockGraphics(white)value or expression?2 call fillRandom procedureName?(grid arguments?)3 +while true condition? 4 call displayBlocks procedureName?(grid arguments?)5 variable gridRef name? set to new AsRef<of List<of List<of Int>>>(grid)value or expression?6 call nextGeneration procedureName?(gridRef arguments?)7 reassign grid variableName? to gridRef.value()value or expression?8 call sleep_ms procedureName?(50 arguments?)9 end while end main
+def main() -> None: 1 grid name? = createBlockGraphics(white)value or expression? # variable definition 2 fillRandom procedureName?(grid arguments?) # call procedure 3 +while True condition?: 4 displayBlocks procedureName?(grid arguments?) # call procedure 5 gridRef name? = AsRef[list[list[int]]](grid)value or expression? # variable definition 6 nextGeneration procedureName?(gridRef arguments?) # call procedure 7 grid variableName? = gridRef.value()value or expression? # reassign variable 8 sleep_ms procedureName?(50 arguments?) # call procedure 9 main()
+static void main() { 1 var grid name? = createBlockGraphics(white)value or expression?;2 fillRandom procedureName?(grid arguments?); // call procedure 3 +while (true condition?) { 4 displayBlocks procedureName?(grid arguments?); // call procedure 5 var gridRef name? = new AsRef<List<List<int>>>(grid)value or expression?;6 nextGeneration procedureName?(gridRef arguments?); // call procedure 7 grid variableName? = gridRef.value()value or expression?; // reassign variable 8 sleep_ms procedureName?(50 arguments?); // call procedure 9 } // while } // main
+Sub main() 1 Dim grid name? = createBlockGraphics(white)value or expression? ' variable definition 2 fillRandom procedureName?(grid arguments?) ' call procedure 3 +While True condition? 4 displayBlocks procedureName?(grid arguments?) ' call procedure 5 Dim gridRef name? = New AsRef(Of List(Of List(Of Integer)))(grid)value or expression? ' variable definition 6 nextGeneration procedureName?(gridRef arguments?) ' call procedure 7 grid variableName? = gridRef.value()value or expression? ' reassign variable 8 sleep_ms procedureName?(50 arguments?) ' call procedure 9 End While End Sub
public class Global {
+static void main() { 1 var grid name? = createBlockGraphics(white)value or expression?;2 fillRandom procedureName?(grid arguments?); // call procedure 3 +while (true condition?) { 4 displayBlocks procedureName?(grid arguments?); // call procedure 5 var gridRef name? = new AsRef<List<List<int>>>(grid)value or expression?;6 nextGeneration procedureName?(gridRef arguments?); // call procedure 7 grid variableName? = gridRef.value()value or expression?; // reassign variable 8 sleep_ms procedureName?(50 arguments?); // call procedure 9 } // while } // main
}

### What you need to know about the main routine

- The first instruction added within the main routine, is always the first instruction to be executed when the program is run.
- Without a main routine, there is nothing to run. However you may write and test functions without a main.
- The main routine does not have to be at the top of the file, but this is a good convention to follow.
- You may not add another main routine within a program, unless you first ghost the existing one.
- The main routine may form the entire program (as in the Burrowexample above); more commonly it will delegate to procedures and functions defined by the programmer.

## Procedure

### Examples of procedures

From the Bubbles demo. It changes the vertical position, and the size, of each bubble in the provided list:

+procedure moveGrowBurst name?(bubbles as List<of CircleVG>parameter definitions?) 1 +for b item? in bubbles source? 2 +if random() < 0.05 condition? then 3 # 5% chance bubble 'bursts' and starts again tiny at bottom comment? call b.setRadius procedureName?(0 arguments?)4 call b.setCentreY procedureName?(75 arguments?)5 else 6 # bubble rises and grows slightly comment? call b.setCentreY procedureName?(b.centreY - 1 arguments?)7 call b.setRadius procedureName?(b.radius + 0.2 arguments?)8 end if end for call displayVectorGraphics procedureName?(bubbles arguments?)9 call sleep_ms procedureName?(5 arguments?)10 end procedure
+def moveGrowBurst name?(bubbles: list[CircleVG]parameter definitions?) -> None: # procedure 1 +for b item? in bubbles source?: 2 +if random() < 0.05 condition?: 3 # 5% chance bubble 'bursts' and starts again tiny at bottom comment? b.setRadius procedureName?(0 arguments?) # call procedure 4 b.setCentreY procedureName?(75 arguments?) # call procedure 5 else:6 # bubble rises and grows slightly comment? b.setCentreY procedureName?(b.centreY - 1 arguments?) # call procedure 7 b.setRadius procedureName?(b.radius + 0.2 arguments?) # call procedure 8 displayVectorGraphics procedureName?(bubbles arguments?) # call procedure 9 sleep_ms procedureName?(5 arguments?) # call procedure 10
+static void moveGrowBurst name?(List<CircleVG> bubbles parameter definitions?) { // procedure 1 +foreach (b item? in bubbles source?) { 2 +if (random() < 0.05 condition?) { 3 // 5% chance bubble 'bursts' and starts again tiny at bottom comment? b.setRadius procedureName?(0 arguments?); // call procedure 4 b.setCentreY procedureName?(75 arguments?); // call procedure 5 } else {6 // bubble rises and grows slightly comment? b.setCentreY procedureName?(b.centreY - 1 arguments?); // call procedure 7 b.setRadius procedureName?(b.radius + 0.2 arguments?); // call procedure 8 } // if } // foreach displayVectorGraphics procedureName?(bubbles arguments?); // call procedure 9 sleep_ms procedureName?(5 arguments?); // call procedure 10 } // procedure
+Sub moveGrowBurst name?(bubbles As List(Of CircleVG)parameter definitions?) ' procedure 1 +For Each b item? In bubbles source? 2 +If random() < 0.05 condition? Then 3 ' 5% chance bubble 'bursts' and starts again tiny at bottom comment? b.setRadius procedureName?(0 arguments?) ' call procedure 4 b.setCentreY procedureName?(75 arguments?) ' call procedure 5 Else 6 ' bubble rises and grows slightly comment? b.setCentreY procedureName?(b.centreY - 1 arguments?) ' call procedure 7 b.setRadius procedureName?(b.radius + 0.2 arguments?) ' call procedure 8 End If Next b displayVectorGraphics procedureName?(bubbles arguments?) ' call procedure 9 sleep_ms procedureName?(5 arguments?) ' call procedure 10 End Sub
public class Global {
+static void moveGrowBurst name?(List<CircleVG> bubbles parameter definitions?) { // procedure 1 +foreach (b item? in bubbles source?) { 2 +if (random() < 0.05 condition?) { 3 // 5% chance bubble 'bursts' and starts again tiny at bottom comment? b.setRadius procedureName?(0 arguments?); // call procedure 4 b.setCentreY procedureName?(75 arguments?); // call procedure 5 } else {6 // bubble rises and grows slightly comment? b.setCentreY procedureName?(b.centreY - 1 arguments?); // call procedure 7 b.setRadius procedureName?(b.radius + 0.2 arguments?); // call procedure 8 } // if } // foreach displayVectorGraphics procedureName?(bubbles arguments?); // call procedure 9 sleep_ms procedureName?(5 arguments?); // call procedure 10 } // procedure
}

It is called within the main routine by this instruction: `call moveGrowBurstprocedureName?(bubblesarguments?)0moveGrowBurstprocedureName?(bubblesarguments?) # call procedure0moveGrowBurstprocedureName?(bubblesarguments?); // call procedure0moveGrowBurstprocedureName?(bubblesarguments?) ' call procedure0moveGrowBurstprocedureName?(bubblesarguments?); // call procedure0`

From the Turtle Dragon demo. The procedure defines two parameters of different types. The body of this procedure consists of a straight sequence of call procedure instructions, but all the procedures are defined on the turtle (the parameter named `ttttt`) using 'dot-syntax':

+procedure setupTurtle name?(t as Turtle, order as Int parameter definitions?) 1 call t.turnToHeading procedureName?(180 + order*45 arguments?)2 call t.placeAt procedureName?(-40, 20 arguments?)3 call t.penColour procedureName?(red arguments?)4 call t.penWidth procedureName?(10.0/order arguments?)5 call t.penDown procedureName?(arguments?)6 call t.show procedureName?(arguments?)7 end procedure
+def setupTurtle name?(t: Turtle, order: int parameter definitions?) -> None: # procedure 1 t.turnToHeading procedureName?(180 + order*45 arguments?) # call procedure 2 t.placeAt procedureName?(-40, 20 arguments?) # call procedure 3 t.penColour procedureName?(red arguments?) # call procedure 4 t.penWidth procedureName?(10.0/order arguments?) # call procedure 5 t.penDown procedureName?(arguments?) # call procedure 6 t.show procedureName?(arguments?) # call procedure 7
+static void setupTurtle name?(Turtle t, int order parameter definitions?) { // procedure 1 t.turnToHeading procedureName?(180 + order*45 arguments?); // call procedure 2 t.placeAt procedureName?(-40, 20 arguments?); // call procedure 3 t.penColour procedureName?(red arguments?); // call procedure 4 t.penWidth procedureName?(10.0/order arguments?); // call procedure 5 t.penDown procedureName?(arguments?); // call procedure 6 t.show procedureName?(arguments?); // call procedure 7 } // procedure
+Sub setupTurtle name?(t As Turtle, order As Integer parameter definitions?) ' procedure 1 t.turnToHeading procedureName?(180 + order*45 arguments?) ' call procedure 2 t.placeAt procedureName?(-40, 20 arguments?) ' call procedure 3 t.penColour procedureName?(red arguments?) ' call procedure 4 t.penWidth procedureName?(10.0/order arguments?) ' call procedure 5 t.penDown procedureName?(arguments?) ' call procedure 6 t.show procedureName?(arguments?) ' call procedure 7 End Sub
public class Global {
+static void setupTurtle name?(Turtle t, int order parameter definitions?) { // procedure 1 t.turnToHeading procedureName?(180 + order*45 arguments?); // call procedure 2 t.placeAt procedureName?(-40, 20 arguments?); // call procedure 3 t.penColour procedureName?(red arguments?); // call procedure 4 t.penWidth procedureName?(10.0/order arguments?); // call procedure 5 t.penDown procedureName?(arguments?); // call procedure 6 t.show procedureName?(arguments?); // call procedure 7 } // procedure
}

From the Life - procedural demo. The code sets each of the cells in the 40x30 `gridgridgridgridgrid`

+procedure fillRandom name?(grid as List<of List<of Int>>parameter definitions?) 1 +for col item? in range(0, 40)source? 2 +for row item? in range(0, 30)source? 3 reassign grid[col][row]variableName? to blackOrWhite(random())value or expression?4 end for end for end procedure
+def fillRandom name?(grid: list[list[int]]parameter definitions?) -> None: # procedure 1 +for col item? in range(0, 40)source?: 2 +for row item? in range(0, 30)source?: 3 grid[col][row]variableName? = blackOrWhite(random())value or expression? # reassign variable 4
+static void fillRandom name?(List<List<int>> grid parameter definitions?) { // procedure 1 +foreach (col item? in range(0, 40)source?) { 2 +foreach (row item? in range(0, 30)source?) { 3 grid[col][row]variableName? = blackOrWhite(random())value or expression?; // reassign variable 4 } // foreach } // foreach } // procedure
+Sub fillRandom name?(grid As List(Of List(Of Integer))parameter definitions?) ' procedure 1 +For Each col item? In range(0, 40)source? 2 +For Each row item? In range(0, 30)source? 3 grid[col][row]variableName? = blackOrWhite(random())value or expression? ' reassign variable 4 Next row Next col End Sub
public class Global {
+static void fillRandom name?(List<List<int>> grid parameter definitions?) { // procedure 1 +foreach (col item? in range(0, 40)source?) { 2 +foreach (row item? in range(0, 30)source?) { 3 grid[col][row]variableName? = blackOrWhite(random())value or expression?; // reassign variable 4 } // foreach } // foreach } // procedure
}

### What you need to know about procedures

- A procedure (also known as a 'subroutine') defines a part of the program to which work is delegated, either by the main routine, or by another procedure.
- The Elan library provides some ready-made procedures such as print and pause.
- The procedure instruction allows you to define your own procedures.
- A procedure is defined with a unique name, starting lower-case (moveGrowBurst).
- It may optionally define one or more parameters (one in the example above), comma-separated if more than one.
- Each parameter specifies a name, starting lower-case (`bubblesbubblesbubblesbubblesbubbles` above) and a type (`List<of CircleVG>list[CircleVG]List<CircleVG>List(Of CircleVG)List<CircleVG>` above) using the syntax `bubbles as List Code does not parse as Elan.bubbles as List Code does not parse as Elan.bubbles as List Code does not parse as Elan.bubbles as List Code does not parse as Elan.bubbles as List Code does not parse as Elan.`
- The procedure is called from elsewhere using a call procedure instruction. which specifies the name of the procedure to be called, and includes a value(s) or expressions(s) that match the type(s) for the parameter(s).
- The procedure always finishes on the last instruction defined within it, at which point the program continues from where the call instruction was located.
- Changes made to parameter values (where possible) within the procedure (such as changing the radius and centre of each bubble in the list `new codenew codenew codenew code
  public class Global {
  new code
  }` which specifies the name of the procedure to be called, and includes a value(s) or expressions(s) that match the type(s) for the parameter(s).
- The procedure always finishes on the last instruction defined within it, at which point the program continues from where the call instruction was located.
- Changes made to parameter values (where possible) within the procedure (such as changing the radius and centre of each bubble in the list `bubblesbubblesbubblesbubblesbubbles`) will be visible to the calling code when the procedure exits.
- Functions may be called from within a procedure, but not vice versa.
- Instructions within a procedure - unlike within a function - may call other procedures, undertake input/output, and use system methods.

### More advanced techniques

#### Call by reference

To change the value in named value arg supplied as an argument in a procedure call, both the call argument and the procedure parameter must use a reference (or pointer) to it, defined as type `AsRefAsRefAsRefAsRefAsRef`. This then allows use of the dot methods value and set on it to read and change its value, as in this example where argRef is a pointer to variable arg in main, so that arg can be accessed elsewhere by reference:

+main 1 variable arg name? set to "abc"value or expression?2 variable argRef name? set to new AsRef<of String>(arg)value or expression?3 call changeArg procedureName?(argRef arguments?)4 print(argRef.value()arguments?)5 end main +procedure changeArg name?(pointer as AsRef<of String>parameter definitions?) 6 variable r name? set to pointer.value()value or expression?7 call pointer.set procedureName?(r.upperCase()arguments?)8 end procedure
+def main() -> None: 1 arg name? = "abc"value or expression? # variable definition 2 argRef name? = AsRef[str](arg)value or expression? # variable definition 3 changeArg procedureName?(argRef arguments?) # call procedure 4 print(argRef.value()arguments?)5 +def changeArg name?(pointer: AsRef[str]parameter definitions?) -> None: # procedure 6 r name? = pointer.value()value or expression? # variable definition 7 pointer.set procedureName?(r.upperCase()arguments?) # call procedure 8 main()
+static void main() { 1 var arg name? = "abc"value or expression?;2 var argRef name? = new AsRef<string>(arg)value or expression?;3 changeArg procedureName?(argRef arguments?); // call procedure 4 Console.WriteLine(argRef.value()arguments?); // print 5 } // main +static void changeArg name?(AsRef<string> pointer parameter definitions?) { // procedure 6 var r name? = pointer.value()value or expression?;7 pointer.set procedureName?(r.upperCase()arguments?); // call procedure 8 } // procedure
+Sub main() 1 Dim arg name? = "abc"value or expression? ' variable definition 2 Dim argRef name? = New AsRef(Of String)(arg)value or expression? ' variable definition 3 changeArg procedureName?(argRef arguments?) ' call procedure 4 Console.WriteLine(argRef.value()arguments?) ' print 5 End Sub +Sub changeArg name?(pointer As AsRef(Of String)parameter definitions?) ' procedure 6 Dim r name? = pointer.value()value or expression? ' variable definition 7 pointer.set procedureName?(r.upperCase()arguments?) ' call procedure 8 End Sub
public class Global {
+static void main() { 1 var arg name? = "abc"value or expression?;2 var argRef name? = new AsRef<String>(arg)value or expression?;3 changeArg procedureName?(argRef arguments?); // call procedure 4 System.out.println(argRef.value()arguments?); // print 5 } // main +static void changeArg name?(AsRef<String> pointer parameter definitions?) { // procedure 6 var r name? = pointer.value()value or expression?;7 pointer.set procedureName?(r.upperCase()arguments?); // call procedure 8 } // procedure
}

### Recursive procedure calls

A procedure may call itself, directly or indirectly (calling another procedure that then calls back to the first one). The following example is from the Turtle Snowflake demo, you can see that the drawSide procedure calls itself from four separate places within its body - in order to achieve the 'fractal' effect, where a basic shape repeats itself at different levels of scale. You can also observe two very important principles of recursion here:

- That calls back into itself are with a smaller version of the problem - in this case a `thirdthirdthirdthirdthird` of the `lengthlengthlengthlengthlength` that the procedure was given.
- That there is a terminating condition where the recursion 'bottoms out' - in this when the side length gets down to 1.

+procedure drawSide name?(length as Float, t as Turtle parameter definitions?) 1 +if (length > 1)condition? then 2 variable third name? set to length/3 value or expression?3 call drawSide procedureName?(third, t arguments?)4 call t.turn procedureName?(-60 arguments?)5 call drawSide procedureName?(third, t arguments?)6 call t.turn procedureName?(120 arguments?)7 call drawSide procedureName?(third, t arguments?)8 call t.turn procedureName?(-60 arguments?)9 call drawSide procedureName?(third, t arguments?)10 else 11 call t.move procedureName?(length arguments?)12 end if end procedure
+def drawSide name?(length: float, t: Turtle parameter definitions?) -> None: # procedure 1 +if (length > 1)condition?: 2 third name? = length/3 value or expression? # variable definition 3 drawSide procedureName?(third, t arguments?) # call procedure 4 t.turn procedureName?(-60 arguments?) # call procedure 5 drawSide procedureName?(third, t arguments?) # call procedure 6 t.turn procedureName?(120 arguments?) # call procedure 7 drawSide procedureName?(third, t arguments?) # call procedure 8 t.turn procedureName?(-60 arguments?) # call procedure 9 drawSide procedureName?(third, t arguments?) # call procedure 10 else:11 t.move procedureName?(length arguments?) # call procedure 12
+static void drawSide name?(double length, Turtle t parameter definitions?) { // procedure 1 +if ((length > 1)condition?) { 2 var third name? = length/3 value or expression?;3 drawSide procedureName?(third, t arguments?); // call procedure 4 t.turn procedureName?(-60 arguments?); // call procedure 5 drawSide procedureName?(third, t arguments?); // call procedure 6 t.turn procedureName?(120 arguments?); // call procedure 7 drawSide procedureName?(third, t arguments?); // call procedure 8 t.turn procedureName?(-60 arguments?); // call procedure 9 drawSide procedureName?(third, t arguments?); // call procedure 10 } else {11 t.move procedureName?(length arguments?); // call procedure 12 } // if } // procedure
+Sub drawSide name?(length As Double, t As Turtle parameter definitions?) ' procedure 1 +If (length > 1)condition? Then 2 Dim third name? = length/3 value or expression? ' variable definition 3 drawSide procedureName?(third, t arguments?) ' call procedure 4 t.turn procedureName?(-60 arguments?) ' call procedure 5 drawSide procedureName?(third, t arguments?) ' call procedure 6 t.turn procedureName?(120 arguments?) ' call procedure 7 drawSide procedureName?(third, t arguments?) ' call procedure 8 t.turn procedureName?(-60 arguments?) ' call procedure 9 drawSide procedureName?(third, t arguments?) ' call procedure 10 Else 11 t.move procedureName?(length arguments?) ' call procedure 12 End If End Sub
public class Global {
+static void drawSide name?(double length, Turtle t parameter definitions?) { // procedure 1 +if ((length > 1)condition?) { 2 var third name? = length/3 value or expression?;3 drawSide procedureName?(third, t arguments?); // call procedure 4 t.turn procedureName?(-60 arguments?); // call procedure 5 drawSide procedureName?(third, t arguments?); // call procedure 6 t.turn procedureName?(120 arguments?); // call procedure 7 drawSide procedureName?(third, t arguments?); // call procedure 8 t.turn procedureName?(-60 arguments?); // call procedure 9 drawSide procedureName?(third, t arguments?); // call procedure 10 } else {11 t.move procedureName?(length arguments?); // call procedure 12 } // if } // procedure
}

## Function

### Examples of functions

From the Snake - procedural demo. Given the coordinates of the snake's head, determines whether or not the head has gone outside the bounds of the 40x30 grid:

+function hasHitEdge name?(headX as Int, headY as Int parameter definitions?) returns Boolean Type? 1 return (headX < 0) or (headY < 0) or (headX > 39) or (headY > 29)value or expression?2 end function
+def hasHitEdge name?(headX: int, headY: int parameter definitions?) -> bool Type?: # function 1 return (headX < 0) or (headY < 0) or (headX > 39) or (headY > 29)value or expression?2
+static bool Type? hasHitEdge name?(int headX, int headY parameter definitions?) { // function 1 return (headX < 0) || (headY < 0) || (headX > 39) || (headY > 29)value or expression?;2 } // function
+Function hasHitEdge name?(headX As Integer, headY As Integer parameter definitions?) As Boolean Type? 1 Return (headX < 0) Or (headY < 0) Or (headX > 39) Or (headY > 29)value or expression?2 End Function
public class Global {
+static bool Type? hasHitEdge name?(int headX, int headY parameter definitions?) { // function 1 return (headX < 0) || (headY < 0) || (headX > 39) || (headY > 29)value or expression?;2 } // function
}

It is called within the main routine as part of this instruction:

reassign gameOn variableName? to not hasHitEdge(head[0], head[1]) and not body.contains(head)value or expression?0
gameOn variableName? = not hasHitEdge(head[0], head[1]) and not body.contains(head)value or expression? # reassign variable 0
gameOn variableName? = !hasHitEdge(head[0], head[1]) && !body.contains(head)value or expression?; // reassign variable 0
gameOn variableName? = Not hasHitEdge(head[0], head[1]) And Not body.contains(head)value or expression? ' reassign variable 0
gameOn variableName? = !hasHitEdge(head[0], head[1]) && !body.contains(head)value or expression?; // reassign variable 0

From the Date Time demo. A function to determine whether a given year is a leap year or not:

+function leap name?(year as Int parameter definitions?) returns Boolean Type? 1 return (((year mod 4) is 0) and ((year mod 100) isnt 0)) or ((year mod 400) is 0)value or expression?2 end function
+def leap name?(year: int parameter definitions?) -> bool Type?: # function 1 return (((year % 4) == 0) and ((year % 100) != 0)) or ((year % 400) == 0)value or expression?2
+static bool Type? leap name?(int year parameter definitions?) { // function 1 return (((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0)value or expression?;2 } // function
+Function leap name?(year As Integer parameter definitions?) As Boolean Type? 1 Return (((year Mod 4) = 0) And ((year Mod 100) <> 0)) Or ((year Mod 400) = 0)value or expression?2 End Function
public class Global {
+static bool Type? leap name?(int year parameter definitions?) { // function 1 return (((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0)value or expression?;2 } // function
}

From the Life - procedural demo a function that finds the cell immediately to the north of the cell provided. Both the single parameter and return value are 2-tuples, where both elements are of type `IntintintIntegerint`:

+function north name?(cell as (Int, Int)parameter definitions?) returns (Int, Int)Type? 1 variable x name? set to cell.item_0 value or expression?2 variable y name? set to cell.item_1 value or expression?3 variable y2 name? set to y - 1 value or expression?4 +if y2 is -1 condition? then 5 reassign y2 variableName? to 29 value or expression?6 end if return (x, y2)value or expression?7 end function
+def north name?(cell: tuple[int, int]parameter definitions?) -> tuple[int, int]Type?: # function 1 x name? = cell.item_0 value or expression? # variable definition 2 y name? = cell.item_1 value or expression? # variable definition 3 y2 name? = y - 1 value or expression? # variable definition 4 +if y2 == -1 condition?: 5 y2 variableName? = 29 value or expression? # reassign variable 6 return (x, y2)value or expression?7
+static (int, int)Type? north name?((int, int) cell parameter definitions?) { // function 1 var x name? = cell.item_0 value or expression?;2 var y name? = cell.item_1 value or expression?;3 var y2 name? = y - 1 value or expression?;4 +if (y2 == -1 condition?) { 5 y2 variableName? = 29 value or expression?; // reassign variable 6 } // if return (x, y2)value or expression?;7 } // function
+Function north name?(cell As (Integer, Integer)parameter definitions?) As (Integer, Integer)Type? 1 Dim x name? = cell.item_0 value or expression? ' variable definition 2 Dim y name? = cell.item_1 value or expression? ' variable definition 3 Dim y2 name? = y - 1 value or expression? ' variable definition 4 +If y2 = -1 condition? Then 5 y2 variableName? = 29 value or expression? ' reassign variable 6 End If Return (x, y2)value or expression?7 End Function
public class Global {
+static (int, int)Type? north name?((int, int) cell parameter definitions?) { // function 1 var x name? = cell.item_0 value or expression?;2 var y name? = cell.item_1 value or expression?;3 var y2 name? = y - 1 value or expression?;4 +if (y2 == -1 condition?) { 5 y2 variableName? = 29 value or expression?; // reassign variable 6 } // if return (x, y2)value or expression?;7 } // function
}

A function to search a (pre-sorted) list of strings using the binary search algorithm:

+function binarySearch name?(li as List<of String>, item as String parameter definitions?) returns Boolean Type? 1 variable result name? set to false value or expression?2 +if li.length() > 0 condition? then 3 variable mid name? set to divAsInt(li.length(), 2)value or expression?4 variable value name? set to li[mid]value or expression?5 +if item.equals(value)condition? then 6 reassign result variableName? to true value or expression?7 elif item.isBefore(value)condition? then 8 reassign result variableName? to binarySearch(li.subList(0, mid), item)value or expression?9 else 10 reassign result variableName? to binarySearch(li.subList(mid + 1, li.length()), item)value or expression?11 end if end if return result value or expression?12 end function
+def binarySearch name?(li: list[str], item: str parameter definitions?) -> bool Type?: # function 1 result name? = False value or expression? # variable definition 2 +if li.length() > 0 condition?: 3 mid name? = divAsInt(li.length(), 2)value or expression? # variable definition 4 value name? = li[mid]value or expression? # variable definition 5 +if item.equals(value)condition?: 6 result variableName? = True value or expression? # reassign variable 7 elif item.isBefore(value)condition?: # else if 8 result variableName? = binarySearch(li.subList(0, mid), item)value or expression? # reassign variable 9 else:10 result variableName? = binarySearch(li.subList(mid + 1, li.length()), item)value or expression? # reassign variable 11 return result value or expression?12
+static bool Type? binarySearch name?(List<string> li, string item parameter definitions?) { // function 1 var result name? = false value or expression?;2 +if (li.length() > 0 condition?) { 3 var mid name? = divAsInt(li.length(), 2)value or expression?;4 var value name? = li[mid]value or expression?;5 +if (item.equals(value)condition?) { 6 result variableName? = true value or expression?; // reassign variable 7 } else if (item.isBefore(value)condition?) {8 result variableName? = binarySearch(li.subList(0, mid), item)value or expression?; // reassign variable 9 } else {10 result variableName? = binarySearch(li.subList(mid + 1, li.length()), item)value or expression?; // reassign variable 11 } // if } // if return result value or expression?;12 } // function
+Function binarySearch name?(li As List(Of String), item As String parameter definitions?) As Boolean Type? 1 Dim result name? = False value or expression? ' variable definition 2 +If li.length() > 0 condition? Then 3 Dim mid name? = divAsInt(li.length(), 2)value or expression? ' variable definition 4 Dim value name? = li[mid]value or expression? ' variable definition 5 +If item.equals(value)condition? Then 6 result variableName? = True value or expression? ' reassign variable 7 ElseIf item.isBefore(value)condition? Then 8 result variableName? = binarySearch(li.subList(0, mid), item)value or expression? ' reassign variable 9 Else 10 result variableName? = binarySearch(li.subList(mid + 1, li.length()), item)value or expression? ' reassign variable 11 End If End If Return result value or expression?12 End Function
public class Global {
+static bool Type? binarySearch name?(List<String> li, String item parameter definitions?) { // function 1 var result name? = false value or expression?;2 +if (li.length() > 0 condition?) { 3 var mid name? = divAsInt(li.length(), 2)value or expression?;4 var value name? = li[mid]value or expression?;5 +if (item.equals(value)condition?) { 6 result variableName? = true value or expression?; // reassign variable 7 } else if (item.isBefore(value)condition?) {8 result variableName? = binarySearch(li.subList(0, mid), item)value or expression?; // reassign variable 9 } else {10 result variableName? = binarySearch(li.subList(mid + 1, li.length()), item)value or expression?; // reassign variable 11 } // if } // if return result value or expression?;12 } // function
}

### What you need to know about functions

- A function defines a mechanism to transform input data (passed as parameters) into a 'returned' value.
- Because it generates a value, a function call is a kind of expression - it may define a complete expression, a part of a more complex expression (as above).
- The Elan library provides some ready-made functions such as sqrt.
- The function instruction allows you to define your own functions.
- A function is defined with a unique name, starting lower-case (hasHitEdge).
- It will usually define one or more parameters (two in the example above), comma-separated if more than one.
- Each parameter specifies a name starting lower-case (`headXheadXheadXheadXheadX` above) and a type (`IntintintIntegerint` above) using the syntax `headX as Int Code does not parse as Elan.headX as Int Code does not parse as Elan.headX as Int Code does not parse as Elan.headX as Int Code does not parse as Elan.headX as Int Code does not parse as Elan.`
- The function signature (top line) must also specify the type of value it will return (`returnsreturnsreturnsreturnsreturns` `BooleanboolboolBooleanbool` above).
- The returned value may be a simple value such as an `IntintintIntegerint`, or it may be a data structure such as a `List<of Float>list[float]List<double>List(Of Double)List<double>`.
- A function always has a `returnreturnreturnreturnreturn` statement as its last instruction, which specifies a value, or an expression to be evaluated. The value, or the result of evaluating the expression, must yield the same type as specified in the signature.
- Even though some languages would allow you to put the `returnreturnreturnreturnreturn` anywhere within the function, or even have more than one of them, Elan deliberately does not permit this - in any of the supported languages - because that would result in poorly-structured code.
- The body of a function may consist only of the return statement - with the expression following `returnreturnreturnreturnreturn` doing all the work needed.
- More generally, the return statement will be preceded by other statement instructions to determine the result in several steps.
- While many languages treat functions as a procedure that returns a value - this is unhelpful. Elan enforces - for each of the supported languages - that functions are kept 'pure', like all functions used in mathematics. Specifically:

- a function cannot undertake any input/output, or create any other 'side effect' (change to the system that can be observed outside the function).
- prohibited side-effects including changing any of the values passed in as parameters.
- the returned result must depend solely, and deterministically, on the values provided as parameters - just as `sqrt(2)sqrt(2)sqrt(2)sqrt(2)sqrt(2)` always produces the same result, irrespective of whatever else might be occurring in the program.

## Test

### Examples of tests

From the Date Time demo, testing the function that determines whether a given year is a leap year. Note that the comments distinguish between the 'normal' test cases and the 'boundary' (also known as 'edge') cases, where errors are more common:

+test test_leap test_name? 1 # normal cases comment? assert leap(2025)actual (computed) value? is false expected value? not run 2 assert leap(2024)actual (computed) value? is true expected value? not run 3 # boundary cases comment? assert leap(1900)actual (computed) value? is false expected value? not run 4 assert leap(2000)actual (computed) value? is true expected value? not run 5 end test
+def test_leap test_name?(self) -> None: 1 # normal cases comment? self.assertEqual(leap(2025)actual (computed) value?, False expected value?) not run 2 self.assertEqual(leap(2024)actual (computed) value?, True expected value?) not run 3 # boundary cases comment? self.assertEqual(leap(1900)actual (computed) value?, False expected value?) not run 4 self.assertEqual(leap(2000)actual (computed) value?, True expected value?) not run 5
+[TestMethod] static void test_leap test_name?() { 1 // normal cases comment? Assert.AreEqual(false expected value?, leap(2025)actual (computed) value?); not run 2 Assert.AreEqual(true expected value?, leap(2024)actual (computed) value?); not run 3 // boundary cases comment? Assert.AreEqual(false expected value?, leap(1900)actual (computed) value?); not run 4 Assert.AreEqual(true expected value?, leap(2000)actual (computed) value?); not run 5 } // test
+<TestMethod> Sub test_leap test_name?() 1 ' normal cases comment? Assert.AreEqual(False expected value?, leap(2025)actual (computed) value?) not run 2 Assert.AreEqual(True expected value?, leap(2024)actual (computed) value?) not run 3 ' boundary cases comment? Assert.AreEqual(False expected value?, leap(1900)actual (computed) value?) not run 4 Assert.AreEqual(True expected value?, leap(2000)actual (computed) value?) not run 5 End Sub
public class Global {
+@Test static void test_leap test_name?() { 1 // normal cases comment? assertEquals(false expected value?, leap(2025)actual (computed) value?); not run 2 assertEquals(true expected value?, leap(2024)actual (computed) value?); not run 3 // boundary cases comment? assertEquals(false expected value?, leap(1900)actual (computed) value?); not run 4 assertEquals(true expected value?, leap(2000)actual (computed) value?); not run 5 } // test
}

Example from the Life - procedural demo. It tests all valid combinations of parameter values - because the logic of this function is quite unusual:

+test test_willLive test_name? 1 assert willLive(white, 0)actual (computed) value? is false expected value? not run 2 assert willLive(white, 1)actual (computed) value? is false expected value? not run 3 assert willLive(white, 2)actual (computed) value? is false expected value? not run 4 assert willLive(white, 3)actual (computed) value? is true expected value? not run 5 assert willLive(white, 4)actual (computed) value? is false expected value? not run 6 assert willLive(white, 5)actual (computed) value? is false expected value? not run 7 assert willLive(white, 6)actual (computed) value? is false expected value? not run 8 assert willLive(white, 7)actual (computed) value? is false expected value? not run 9 assert willLive(white, 8)actual (computed) value? is false expected value? not run 10 assert willLive(black, 0)actual (computed) value? is false expected value? not run 11 assert willLive(black, 1)actual (computed) value? is false expected value? not run 12 assert willLive(black, 2)actual (computed) value? is true expected value? not run 13 assert willLive(black, 3)actual (computed) value? is true expected value? not run 14 assert willLive(black, 4)actual (computed) value? is false expected value? not run 15 assert willLive(black, 5)actual (computed) value? is false expected value? not run 16 assert willLive(black, 6)actual (computed) value? is false expected value? not run 17 assert willLive(black, 7)actual (computed) value? is false expected value? not run 18 assert willLive(black, 8)actual (computed) value? is false expected value? not run 19 end test
+def test_willLive test_name?(self) -> None: 1 self.assertEqual(willLive(white, 0)actual (computed) value?, False expected value?) not run 2 self.assertEqual(willLive(white, 1)actual (computed) value?, False expected value?) not run 3 self.assertEqual(willLive(white, 2)actual (computed) value?, False expected value?) not run 4 self.assertEqual(willLive(white, 3)actual (computed) value?, True expected value?) not run 5 self.assertEqual(willLive(white, 4)actual (computed) value?, False expected value?) not run 6 self.assertEqual(willLive(white, 5)actual (computed) value?, False expected value?) not run 7 self.assertEqual(willLive(white, 6)actual (computed) value?, False expected value?) not run 8 self.assertEqual(willLive(white, 7)actual (computed) value?, False expected value?) not run 9 self.assertEqual(willLive(white, 8)actual (computed) value?, False expected value?) not run 10 self.assertEqual(willLive(black, 0)actual (computed) value?, False expected value?) not run 11 self.assertEqual(willLive(black, 1)actual (computed) value?, False expected value?) not run 12 self.assertEqual(willLive(black, 2)actual (computed) value?, True expected value?) not run 13 self.assertEqual(willLive(black, 3)actual (computed) value?, True expected value?) not run 14 self.assertEqual(willLive(black, 4)actual (computed) value?, False expected value?) not run 15 self.assertEqual(willLive(black, 5)actual (computed) value?, False expected value?) not run 16 self.assertEqual(willLive(black, 6)actual (computed) value?, False expected value?) not run 17 self.assertEqual(willLive(black, 7)actual (computed) value?, False expected value?) not run 18 self.assertEqual(willLive(black, 8)actual (computed) value?, False expected value?) not run 19
+[TestMethod] static void test_willLive test_name?() { 1 Assert.AreEqual(false expected value?, willLive(white, 0)actual (computed) value?); not run 2 Assert.AreEqual(false expected value?, willLive(white, 1)actual (computed) value?); not run 3 Assert.AreEqual(false expected value?, willLive(white, 2)actual (computed) value?); not run 4 Assert.AreEqual(true expected value?, willLive(white, 3)actual (computed) value?); not run 5 Assert.AreEqual(false expected value?, willLive(white, 4)actual (computed) value?); not run 6 Assert.AreEqual(false expected value?, willLive(white, 5)actual (computed) value?); not run 7 Assert.AreEqual(false expected value?, willLive(white, 6)actual (computed) value?); not run 8 Assert.AreEqual(false expected value?, willLive(white, 7)actual (computed) value?); not run 9 Assert.AreEqual(false expected value?, willLive(white, 8)actual (computed) value?); not run 10 Assert.AreEqual(false expected value?, willLive(black, 0)actual (computed) value?); not run 11 Assert.AreEqual(false expected value?, willLive(black, 1)actual (computed) value?); not run 12 Assert.AreEqual(true expected value?, willLive(black, 2)actual (computed) value?); not run 13 Assert.AreEqual(true expected value?, willLive(black, 3)actual (computed) value?); not run 14 Assert.AreEqual(false expected value?, willLive(black, 4)actual (computed) value?); not run 15 Assert.AreEqual(false expected value?, willLive(black, 5)actual (computed) value?); not run 16 Assert.AreEqual(false expected value?, willLive(black, 6)actual (computed) value?); not run 17 Assert.AreEqual(false expected value?, willLive(black, 7)actual (computed) value?); not run 18 Assert.AreEqual(false expected value?, willLive(black, 8)actual (computed) value?); not run 19 } // test
+<TestMethod> Sub test_willLive test_name?() 1 Assert.AreEqual(False expected value?, willLive(white, 0)actual (computed) value?) not run 2 Assert.AreEqual(False expected value?, willLive(white, 1)actual (computed) value?) not run 3 Assert.AreEqual(False expected value?, willLive(white, 2)actual (computed) value?) not run 4 Assert.AreEqual(True expected value?, willLive(white, 3)actual (computed) value?) not run 5 Assert.AreEqual(False expected value?, willLive(white, 4)actual (computed) value?) not run 6 Assert.AreEqual(False expected value?, willLive(white, 5)actual (computed) value?) not run 7 Assert.AreEqual(False expected value?, willLive(white, 6)actual (computed) value?) not run 8 Assert.AreEqual(False expected value?, willLive(white, 7)actual (computed) value?) not run 9 Assert.AreEqual(False expected value?, willLive(white, 8)actual (computed) value?) not run 10 Assert.AreEqual(False expected value?, willLive(black, 0)actual (computed) value?) not run 11 Assert.AreEqual(False expected value?, willLive(black, 1)actual (computed) value?) not run 12 Assert.AreEqual(True expected value?, willLive(black, 2)actual (computed) value?) not run 13 Assert.AreEqual(True expected value?, willLive(black, 3)actual (computed) value?) not run 14 Assert.AreEqual(False expected value?, willLive(black, 4)actual (computed) value?) not run 15 Assert.AreEqual(False expected value?, willLive(black, 5)actual (computed) value?) not run 16 Assert.AreEqual(False expected value?, willLive(black, 6)actual (computed) value?) not run 17 Assert.AreEqual(False expected value?, willLive(black, 7)actual (computed) value?) not run 18 Assert.AreEqual(False expected value?, willLive(black, 8)actual (computed) value?) not run 19 End Sub
public class Global {
+@Test static void test_willLive test_name?() { 1 assertEquals(false expected value?, willLive(white, 0)actual (computed) value?); not run 2 assertEquals(false expected value?, willLive(white, 1)actual (computed) value?); not run 3 assertEquals(false expected value?, willLive(white, 2)actual (computed) value?); not run 4 assertEquals(true expected value?, willLive(white, 3)actual (computed) value?); not run 5 assertEquals(false expected value?, willLive(white, 4)actual (computed) value?); not run 6 assertEquals(false expected value?, willLive(white, 5)actual (computed) value?); not run 7 assertEquals(false expected value?, willLive(white, 6)actual (computed) value?); not run 8 assertEquals(false expected value?, willLive(white, 7)actual (computed) value?); not run 9 assertEquals(false expected value?, willLive(white, 8)actual (computed) value?); not run 10 assertEquals(false expected value?, willLive(black, 0)actual (computed) value?); not run 11 assertEquals(false expected value?, willLive(black, 1)actual (computed) value?); not run 12 assertEquals(true expected value?, willLive(black, 2)actual (computed) value?); not run 13 assertEquals(true expected value?, willLive(black, 3)actual (computed) value?); not run 14 assertEquals(false expected value?, willLive(black, 4)actual (computed) value?); not run 15 assertEquals(false expected value?, willLive(black, 5)actual (computed) value?); not run 16 assertEquals(false expected value?, willLive(black, 6)actual (computed) value?); not run 17 assertEquals(false expected value?, willLive(black, 7)actual (computed) value?); not run 18 assertEquals(false expected value?, willLive(black, 8)actual (computed) value?); not run 19 } // test
}

Example from the Snake - procedural demo, showing the use of a variable to create data to be used within multiple test cases (asserts):

+test test_getAdjacentSquare test_name? 1 variable sq name? set to [20, 15]value or expression?2 assert getAdjacentSquare(sq, Direction.up)actual (computed) value? is [20, 14]expected value? not run 3 assert getAdjacentSquare(sq, Direction.down)actual (computed) value? is [20, 16]expected value? not run 4 assert getAdjacentSquare(sq, Direction.left)actual (computed) value? is [19, 15]expected value? not run 5 assert getAdjacentSquare(sq, Direction.right)actual (computed) value? is [21, 15]expected value? not run 6 # boundary comment? assert getAdjacentSquare([0, 15], Direction.left)actual (computed) value? is [-1, 15]expected value? not run 7 end test
+def test_getAdjacentSquare test_name?(self) -> None: 1 sq name? = [20, 15]value or expression? # variable definition 2 self.assertEqual(getAdjacentSquare(sq, Direction.up)actual (computed) value?, [20, 14]expected value?) not run 3 self.assertEqual(getAdjacentSquare(sq, Direction.down)actual (computed) value?, [20, 16]expected value?) not run 4 self.assertEqual(getAdjacentSquare(sq, Direction.left)actual (computed) value?, [19, 15]expected value?) not run 5 self.assertEqual(getAdjacentSquare(sq, Direction.right)actual (computed) value?, [21, 15]expected value?) not run 6 # boundary comment? self.assertEqual(getAdjacentSquare([0, 15], Direction.left)actual (computed) value?, [-1, 15]expected value?) not run 7
+[TestMethod] static void test_getAdjacentSquare test_name?() { 1 var sq name? = [20, 15]value or expression?;2 Assert.AreEqual([20, 14]expected value?, getAdjacentSquare(sq, Direction.up)actual (computed) value?); not run 3 Assert.AreEqual([20, 16]expected value?, getAdjacentSquare(sq, Direction.down)actual (computed) value?); not run 4 Assert.AreEqual([19, 15]expected value?, getAdjacentSquare(sq, Direction.left)actual (computed) value?); not run 5 Assert.AreEqual([21, 15]expected value?, getAdjacentSquare(sq, Direction.right)actual (computed) value?); not run 6 // boundary comment? Assert.AreEqual([-1, 15]expected value?, getAdjacentSquare([0, 15], Direction.left)actual (computed) value?); not run 7 } // test
+<TestMethod> Sub test_getAdjacentSquare test_name?() 1 Dim sq name? = {20, 15}value or expression? ' variable definition 2 Assert.AreEqual({20, 14}expected value?, getAdjacentSquare(sq, Direction.up)actual (computed) value?) not run 3 Assert.AreEqual({20, 16}expected value?, getAdjacentSquare(sq, Direction.down)actual (computed) value?) not run 4 Assert.AreEqual({19, 15}expected value?, getAdjacentSquare(sq, Direction.left)actual (computed) value?) not run 5 Assert.AreEqual({21, 15}expected value?, getAdjacentSquare(sq, Direction.right)actual (computed) value?) not run 6 ' boundary comment? Assert.AreEqual({-1, 15}expected value?, getAdjacentSquare({0, 15}, Direction.left)actual (computed) value?) not run 7 End Sub
public class Global {
+@Test static void test_getAdjacentSquare test_name?() { 1 var sq name? = [20, 15]value or expression?;2 assertEquals([20, 14]expected value?, getAdjacentSquare(sq, Direction.up)actual (computed) value?); not run 3 assertEquals([20, 16]expected value?, getAdjacentSquare(sq, Direction.down)actual (computed) value?); not run 4 assertEquals([19, 15]expected value?, getAdjacentSquare(sq, Direction.left)actual (computed) value?); not run 5 assertEquals([21, 15]expected value?, getAdjacentSquare(sq, Direction.right)actual (computed) value?); not run 6 // boundary comment? assertEquals([-1, 15]expected value?, getAdjacentSquare([0, 15], Direction.left)actual (computed) value?); not run 7 } // test
}

### What you need to know about tests

- The form of automated testing provided by Elan (for all of the supported languages) are known as 'unit testing'.
- Some languages allow unit tests to be applied to procedures, but this dangerous since running the tests could result in unwanted damage to the system (such as writing to a database); Elan guarantees that tests are safe by restrict them to functions.
- A test method must be given a name that starts with the prefix `test_` (added automatically) and followed, typically, by the name of the function.
- Tests are always written at global level in Elan, but they may be anywhere within the file: you may write a test adjacent to the function being tested, or group all the tests at the end of the file perhaps.
- A test method may define variables for use in the test - for example to define a data value that will be used in several asserts.
- A test method must include one or more assert statements - with each one typically covering a different use-case.
- Each assert instruction has two fields that the programmer must complete: the actual (computed) result - which typically consists of a call to the function being tested, with specific arguments - and the expected result.
- The tests do not form part of the executable program: you cannot call a test from within other code.
- Instead, all tests in a program are run automatically, each time the code compiles.
- The result of each assert in each test is shown alongside the assert instruction, and the overall summary is shown in the status panel at the top centre of the Elan IDE.
- Writing tests for every function is good practice - confirming that your function implementations are correct: when you write them, every time you re-load the program from file.
- Tests also encourage you to 're-factor', improve, or extend the capability of your functions without fear that you have inadvertently made then incorrect for certain cases.

### More advanced techniques

#### Ghosting tests

To deliberately ensure that a test is not run, use `ghostingghostingghostingghostingghosting` .

Even when tests or assert equals are `ghostedghostedghostedghostedghosted`, all the tests will be run and their status shown, but the overall test status will show the status of only the unghosted tests (green pass, amber warning or red fail).

You can ghost an entire test:

+test test_overApple test_name? variable g1 name? set to new Game(new Random())value or expression? variable g2 name? set to g1.withApple(new Square(23, 15))value or expression? assert headOverApple(g2)actual (computed) value? is false expected value? not run variable g3 name? set to g2.withHead(new Square(23, 15))value or expression? assert headOverApple(g3)actual (computed) value? is true expected value? not run end test
+def test_overApple test_name?(self) -> None: g1 name? = Game(Random())value or expression? # variable definition g2 name? = g1.withApple(Square(23, 15))value or expression? # variable definition self.assertEqual(headOverApple(g2)actual (computed) value?, False expected value?) not run g3 name? = g2.withHead(Square(23, 15))value or expression? # variable definition self.assertEqual(headOverApple(g3)actual (computed) value?, True expected value?) not run
+[TestMethod] static void test_overApple test_name?() { var g1 name? = new Game(new Random())value or expression?; var g2 name? = g1.withApple(new Square(23, 15))value or expression?; Assert.AreEqual(false expected value?, headOverApple(g2)actual (computed) value?); not run var g3 name? = g2.withHead(new Square(23, 15))value or expression?; Assert.AreEqual(true expected value?, headOverApple(g3)actual (computed) value?); not run } // test
+<TestMethod> Sub test_overApple test_name?() Dim g1 name? = New Game(New Random())value or expression? ' variable definition Dim g2 name? = g1.withApple(New Square(23, 15))value or expression? ' variable definition Assert.AreEqual(False expected value?, headOverApple(g2)actual (computed) value?) not run Dim g3 name? = g2.withHead(New Square(23, 15))value or expression? ' variable definition Assert.AreEqual(True expected value?, headOverApple(g3)actual (computed) value?) not run End Sub
public class Global {
+@Test static void test_overApple test_name?() { var g1 name? = new Game(new Random())value or expression?; var g2 name? = g1.withApple(new Square(23, 15))value or expression?; assertEquals(false expected value?, headOverApple(g2)actual (computed) value?); not run var g3 name? = g2.withHead(new Square(23, 15))value or expression?; assertEquals(true expected value?, headOverApple(g3)actual (computed) value?); not run } // test
}

or you can ghost any individual assert(s):

+test test_overApple test_name? 1 variable g1 name? set to new Game(new Random())value or expression?2 variable g2 name? set to g1.withApple(new Square(23, 15))value or expression?3 assert headOverApple(g2)actual (computed) value? is true expected value? not run variable g3 name? set to g2.withHead(new Square(23, 15))value or expression?4 assert headOverApple(g3)actual (computed) value? is true expected value? not run 5 end test
+def test_overApple test_name?(self) -> None: 1 g1 name? = Game(Random())value or expression? # variable definition 2 g2 name? = g1.withApple(Square(23, 15))value or expression? # variable definition 3 self.assertEqual(headOverApple(g2)actual (computed) value?, True expected value?) not run g3 name? = g2.withHead(Square(23, 15))value or expression? # variable definition 4 self.assertEqual(headOverApple(g3)actual (computed) value?, True expected value?) not run 5
+[TestMethod] static void test_overApple test_name?() { 1 var g1 name? = new Game(new Random())value or expression?;2 var g2 name? = g1.withApple(new Square(23, 15))value or expression?;3 Assert.AreEqual(true expected value?, headOverApple(g2)actual (computed) value?); not run var g3 name? = g2.withHead(new Square(23, 15))value or expression?;4 Assert.AreEqual(true expected value?, headOverApple(g3)actual (computed) value?); not run 5 } // test
+<TestMethod> Sub test_overApple test_name?() 1 Dim g1 name? = New Game(New Random())value or expression? ' variable definition 2 Dim g2 name? = g1.withApple(New Square(23, 15))value or expression? ' variable definition 3 Assert.AreEqual(True expected value?, headOverApple(g2)actual (computed) value?) not run Dim g3 name? = g2.withHead(New Square(23, 15))value or expression? ' variable definition 4 Assert.AreEqual(True expected value?, headOverApple(g3)actual (computed) value?) not run 5 End Sub
public class Global {
+@Test static void test_overApple test_name?() { 1 var g1 name? = new Game(new Random())value or expression?;2 var g2 name? = g1.withApple(new Square(23, 15))value or expression?;3 assertEquals(true expected value?, headOverApple(g2)actual (computed) value?); not run var g3 name? = g2.withHead(new Square(23, 15))value or expression?;4 assertEquals(true expected value?, headOverApple(g3)actual (computed) value?); not run 5 } // test
}

#### Testing `FloatfloatdoubleDoubledouble` values

When testing `FloatfloatdoubleDoubledouble` values it is recommend that you use the round method to round the computed result to a fixed number of decimal places. This avoids rounding errors and is easier to read. For example:

+test test_round test_name? 1 assert sqrt(2).round(3)actual (computed) value? is 1.414 expected value? not run 2 end test
+def test_round test_name?(self) -> None: 1 self.assertEqual(sqrt(2).round(3)actual (computed) value?, 1.414 expected value?) not run 2
+[TestMethod] static void test_round test_name?() { 1 Assert.AreEqual(1.414 expected value?, sqrt(2).round(3)actual (computed) value?); not run 2 } // test
+<TestMethod> Sub test_round test_name?() 1 Assert.AreEqual(1.414 expected value?, sqrt(2).round(3)actual (computed) value?) not run 2 End Sub
public class Global {
+@Test static void test_round test_name?() { 1 assertEquals(1.414 expected value?, sqrt(2).round(3)actual (computed) value?); not run 2 } // test
}

#### Testing for runtime errors

If the expression you are testing would cause a runtime error then the error will be displayed in the red fail message:

If there are failures, mark the tests that you added since the last successful test as `ghostedghostedghostedghostedghosted`  and then remove their ghosted status one by one until the cause is identified and fixed.

+test test_list test_name? 1 variable a name? set to [5, 1, 7]value or expression?2 assert a[0]actual (computed) value? is 5 expected value? not run 3 assert a[2]actual (computed) value? is 7 expected value? not run 4 end test
+def test_list test_name?(self) -> None: 1 a name? = [5, 1, 7]value or expression? # variable definition 2 self.assertEqual(a[0]actual (computed) value?, 5 expected value?) not run 3 self.assertEqual(a[2]actual (computed) value?, 7 expected value?) not run 4
+[TestMethod] static void test_list test_name?() { 1 var a name? = [5, 1, 7]value or expression?;2 Assert.AreEqual(5 expected value?, a[0]actual (computed) value?); not run 3 Assert.AreEqual(7 expected value?, a[2]actual (computed) value?); not run 4 } // test
+<TestMethod> Sub test_list test_name?() 1 Dim a name? = {5, 1, 7}value or expression? ' variable definition 2 Assert.AreEqual(5 expected value?, a[0]actual (computed) value?) not run 3 Assert.AreEqual(7 expected value?, a[2]actual (computed) value?) not run 4 End Sub
public class Global {
+@Test static void test_list test_name?() { 1 var a name? = [5, 1, 7]value or expression?;2 assertEquals(5 expected value?, a[0]actual (computed) value?); not run 3 assertEquals(7 expected value?, a[2]actual (computed) value?); not run 4 } // test
}

This assert shows how to test for an expected error message:

+test test_message test_name? 1 variable a name? set to [5, 1, 7]value or expression?2 assert a[4]actual (computed) value? is 0 expected value? not run 3 assert a[4]actual (computed) value? is "Out of range index: 4 size: 3"expected value? not run 4 end test
+def test_message test_name?(self) -> None: 1 a name? = [5, 1, 7]value or expression? # variable definition 2 self.assertEqual(a[4]actual (computed) value?, 0 expected value?) not run 3 self.assertEqual(a[4]actual (computed) value?, "Out of range index: 4 size: 3"expected value?) not run 4
+[TestMethod] static void test_message test_name?() { 1 var a name? = [5, 1, 7]value or expression?;2 Assert.AreEqual(0 expected value?, a[4]actual (computed) value?); not run 3 Assert.AreEqual("Out of range index: 4 size: 3"expected value?, a[4]actual (computed) value?); not run 4 } // test
+<TestMethod> Sub test_message test_name?() 1 Dim a name? = {5, 1, 7}value or expression? ' variable definition 2 Assert.AreEqual(0 expected value?, a[4]actual (computed) value?) not run 3 Assert.AreEqual("Out of range index: 4 size: 3"expected value?, a[4]actual (computed) value?) not run 4 End Sub
public class Global {
+@Test static void test_message test_name?() { 1 var a name? = [5, 1, 7]value or expression?;2 assertEquals(0 expected value?, a[4]actual (computed) value?); not run 3 assertEquals("Out of range index: 4 size: 3"expected value?, a[4]actual (computed) value?); not run 4 } // test
}

#### Testing long strings

If you have a test that compares strings longer than 20 characters, any test failure message will be reduced to reporting the first character at which the actual (computed) and expected strings differ. In the following example, the programmer has accidentally missed out the `/` in the closing html tag:

+constant sGW name? set to "grid { display: flex; flex-direction: column; margin-top: 40px; width: 500px; } word { display: flex; flex-direction: row; margin: auto; }"literal value or data structure?1 +function setInStyle name?(s as String parameter definitions?) returns String Type? 2 return "<style>" + s + "<style>"value or expression?3 end function +test test_setInStyle test_name? 4 assert setInStyle(sGW)actual (computed) value? is "<style>" + sGW + "<style>"expected value? not run 5 # assert fail message will be "s found at [146] expected: )"comment? end test
+sGW name? = "grid { display: flex; flex-direction: column; margin-top: 40px; width: 500px; } word { display: flex; flex-direction: row; margin: auto; }"literal value or data structure? # constant 1 +def setInStyle name?(s: str parameter definitions?) -> str Type?: # function 2 return "<style>" + s + "<style>"value or expression?3 +def test_setInStyle test_name?(self) -> None: 4 self.assertEqual(setInStyle(sGW)actual (computed) value?, "<style>" + sGW + "<style>"expected value?) not run 5 # assert fail message will be "s found at [146] expected: )"comment?
+const String sGW name? = "grid { display: flex; flex-direction: column; margin-top: 40px; width: 500px; } word { display: flex; flex-direction: row; margin: auto; }"literal value or data structure?;1 +static string Type? setInStyle name?(string s parameter definitions?) { // function 2 return "<style>" + s + "<style>"value or expression?;3 } // function +[TestMethod] static void test_setInStyle test_name?() { 4 Assert.AreEqual("<style>" + sGW + "<style>"expected value?, setInStyle(sGW)actual (computed) value?); not run 5 // assert fail message will be "s found at [146] expected: )"comment? } // test
+Const sGW name? = "grid { display: flex; flex-direction: column; margin-top: 40px; width: 500px; } word { display: flex; flex-direction: row; margin: auto; }"literal value or data structure?1 +Function setInStyle name?(s As String parameter definitions?) As String Type? 2 Return "<style>" + s + "<style>"value or expression?3 End Function +<TestMethod> Sub test_setInStyle test_name?() 4 Assert.AreEqual("<style>" + sGW + "<style>"expected value?, setInStyle(sGW)actual (computed) value?) not run 5 ' assert fail message will be "s found at [146] expected: )"comment? End Sub
public class Global {
+final String sGW name? = "grid { display: flex; flex-direction: column; margin-top: 40px; width: 500px; } word { display: flex; flex-direction: row; margin: auto; }"literal value or data structure?; // constant 1 +static String Type? setInStyle name?(String s parameter definitions?) { // function 2 return "<style>" + s + "<style>"value or expression?;3 } // function +@Test static void test_setInStyle test_name?() { 4 assertEquals("<style>" + sGW + "<style>"expected value?, setInStyle(sGW)actual (computed) value?); not run 5 // assert fail message will be "s found at [146] expected: )"comment? } // test
}

#### Non-terminating loops and recursion

The principal reason for ghosting a test is when either the test code, or code in any function being called, does not terminate. This typically means that there is a loop (or a recursive call) with no exit condition, or where the exit condition is never met.

If you do create such code without realising it, then when the tests are executed the test runner will time out after a few seconds (most tests will pass in milliseconds), and an error message will appear. Your priority should then be to identify the cause of the timeout and attempt to fix it before then unghosting the `testtesttesttesttest`.

## Constant

### Examples of constants

From the Turtle Snowflake demo. The constant value `sidesidesidesideside` is defined here:

+constant side name? set to 100 literal value or data structure?1
+side name? = 100 literal value or data structure? # constant 1
+const Int side name? = 100 literal value or data structure?;1
+Const side name? = 100 literal value or data structure?1
public class Global {
+final Int side name? = 100 literal value or data structure?; // constant 1
}

and used within the main routine as an argument to pass into the drawSide procedure:

call drawSide procedureName?(side, t arguments?)0
drawSide procedureName?(side, t arguments?) # call procedure 0
drawSide procedureName?(side, t arguments?); // call procedure 0
drawSide procedureName?(side, t arguments?) ' call procedure 0
drawSide procedureName?(side, t arguments?); // call procedure 0
+constant maxHits name? set to 10 literal value or data structure?1 +constant turquoise name? set to 0x00ced1 literal value or data structure?2 +constant liveCell name? set to black literal value or data structure?3 +constant speedOfLight name? set to 299792.458 literal value or data structure?4 +constant gameOver name? set to true literal value or data structure?5 +constant euro name? set to 0x20ac literal value or data structure?6 +constant warningMsg name? set to "Limit reached"literal value or data structure?7
+maxHits name? = 10 literal value or data structure? # constant 1 +turquoise name? = 0x00ced1 literal value or data structure? # constant 2 +liveCell name? = black literal value or data structure? # constant 3 +speedOfLight name? = 299792.458 literal value or data structure? # constant 4 +gameOver name? = True literal value or data structure? # constant 5 +euro name? = 0x20ac literal value or data structure? # constant 6 +warningMsg name? = "Limit reached"literal value or data structure? # constant 7
+const Int maxHits name? = 10 literal value or data structure?;1 +const Int turquoise name? = 0x00ced1 literal value or data structure?;2 +const Int liveCell name? = black literal value or data structure?;3 +const Float speedOfLight name? = 299792.458 literal value or data structure?;4 +const Boolean gameOver name? = true literal value or data structure?;5 +const Int euro name? = 0x20ac literal value or data structure?;6 +const String warningMsg name? = "Limit reached"literal value or data structure?;7
+Const maxHits name? = 10 literal value or data structure?1 +Const turquoise name? = &H00ced1 literal value or data structure?2 +Const liveCell name? = black literal value or data structure?3 +Const speedOfLight name? = 299792.458 literal value or data structure?4 +Const gameOver name? = True literal value or data structure?5 +Const euro name? = &H20ac literal value or data structure?6 +Const warningMsg name? = "Limit reached"literal value or data structure?7
public class Global {
+final Int maxHits name? = 10 literal value or data structure?; // constant 1 +final Int turquoise name? = 0x00ced1 literal value or data structure?; // constant 2 +final Int liveCell name? = black literal value or data structure?; // constant 3 +final Float speedOfLight name? = 299792.458 literal value or data structure?; // constant 4 +final Boolean gameOver name? = true literal value or data structure?; // constant 5 +final Int euro name? = 0x20ac literal value or data structure?; // constant 6 +final String warningMsg name? = "Limit reached"literal value or data structure?; // constant 7
}

### What you need to know about constants

- A constant is a named value that never changes while a program is running.
- The Elan library defines a few constants including `pipipipipi` and a handful of simple colours e.g. `redredredredred`.
- The constant instruction allows you to define your own constant(s).
- Even though Python does not natively support the idea of a constant, when writing Python with Elan, having created a constant with constant instruction you will find that you cannot change it with a reassign instruction.
- When coding with Elan, a constant:
  - may be defined only at global (file) level.
  - must be given a unique name, starting lower-case (`sidesidesidesideside` above).
  - must be defined by a liter value, which must be a number, string, or Boolean (true/false).
- If you define your own constant with the same name as a library constant, you will not be able to access the library one within your program. If you need to do this: rename your own version.

### More advanced techniques

#### Constant data structures

To use a data structure that is to be a constant in your program, you define it as the value returned function that defines no parameters. This function can then be referenced from anywhere in the program, often from within an expression but you need to remember to and empty brackets after the name, when using it.

The following examples define a constant list of colours (using numerical hex values), and a constant dictionary that specifies the colour for each suit in a deck of cards:

+main 1 call print procedureName?($"{rainbow()[0]} is violet"arguments?)2 call print procedureName?($"{suitColours()["hearts"]} is red"arguments?)3 end main +function rainbow name?(parameter definitions parameter definitions?) returns List<of Int>Type? 4 return [0x9400D3, 0x4B0082, 0x0000CD, 0x008000, 0xFFFF00, 0xFFA500, 0xFF0000]value or expression?5 end function +function suitColours name?(parameter definitions parameter definitions?) returns Dictionary<of String, Int>Type? 6 return ["spades":black, "hearts":red, "diamonds":red, "clubs":black]value or expression?7 end function
+def main() -> None: 1 print procedureName?(f"{rainbow()[0]} is violet"arguments?)2 print procedureName?(f"{suitColours()["hearts"]} is red"arguments?)3 +def rainbow name?(parameter definitions parameter definitions?) -> list[int]Type?: # function 4 return [0x9400D3, 0x4B0082, 0x0000CD, 0x008000, 0xFFFF00, 0xFFA500, 0xFF0000]value or expression?5 +def suitColours name?(parameter definitions parameter definitions?) -> Dictionary[str, int]Type?: # function 6 return ["spades":black, "hearts":red, "diamonds":red, "clubs":black]value or expression?7 main()
+static void main() { 1 print procedureName?($"{rainbow()[0]} is violet"arguments?);2 print procedureName?($"{suitColours()["hearts"]} is red"arguments?);3 } // main +static List<int>Type? rainbow name?(parameter definitions parameter definitions?) { // function 4 return [0x9400D3, 0x4B0082, 0x0000CD, 0x008000, 0xFFFF00, 0xFFA500, 0xFF0000]value or expression?;5 } // function +static Dictionary<string, int>Type? suitColours name?(parameter definitions parameter definitions?) { // function 6 return ["spades":black, "hearts":red, "diamonds":red, "clubs":black]value or expression?;7 } // function
+Sub main() 1 print procedureName?($"{rainbow()[0]} is violet"arguments?)2 print procedureName?($"{suitColours()["hearts"]} is red"arguments?)3 End Sub +Function rainbow name?(parameter definitions parameter definitions?) As List(Of Integer)Type? 4 Return {&H9400D3, &H4B0082, &H0000CD, &H008000, &HFFFF00, &HFFA500, &HFF0000}value or expression?5 End Function +Function suitColours name?(parameter definitions parameter definitions?) As Dictionary(Of String, Integer)Type? 6 Return ["spades":black, "hearts":red, "diamonds":red, "clubs":black]value or expression?7 End Function
public class Global {
+static void main() { 1 print procedureName?(String.format("% is violet", rainbow()[0])arguments?);2 print procedureName?(String.format("% is red", suitColours()["hearts"])arguments?);3 } // main +static List<int>Type? rainbow name?(parameter definitions parameter definitions?) { // function 4 return [0x9400D3, 0x4B0082, 0x0000CD, 0x008000, 0xFFFF00, 0xFFA500, 0xFF0000]value or expression?;5 } // function +static Dictionary<String, int>Type? suitColours name?(parameter definitions parameter definitions?) { // function 6 return ["spades":black, "hearts":red, "diamonds":red, "clubs":black]value or expression?;7 } // function
}

## Enum

### Examples of enums

From the Snake - procedural demo, the enum is defined here:

enum Direction Name? up, down, left, right values?values?1
class Direction Name?(Enum):
up = 1
down = 2
left = 3
right = 4 values?1
enum Direction Name? {up, down, left, right values?values?}1
Enum Direction Name?
up = 0
down = 1
left = 2
right = 3
End Enum values?1
public class Global {
enum Direction Name? {up, down, left, right values?values?}1
}

and is used in several places in the code, for example:

+function getAdjacentSquare name?(sq as List<of Int>, dir as Direction parameter definitions?) returns List<of Int>Type? 1 variable newX name? set to sq[0]value or expression?2 variable newY name? set to sq[1]value or expression?3 +if dir is Direction.left condition? then 4 reassign newX variableName? to newX - 1 value or expression?5 elif dir is Direction.right condition? then 6 reassign newX variableName? to newX + 1 value or expression?7 elif dir is Direction.up condition? then 8 reassign newY variableName? to newY - 1 value or expression?9 elif dir is Direction.down condition? then 10 reassign newY variableName? to newY + 1 value or expression?11 end if return [newX, newY]value or expression?12 end function
+def getAdjacentSquare name?(sq: list[int], dir: Direction parameter definitions?) -> list[int]Type?: # function 1 newX name? = sq[0]value or expression? # variable definition 2 newY name? = sq[1]value or expression? # variable definition 3 +if dir == Direction.left condition?: 4 newX variableName? = newX - 1 value or expression? # reassign variable 5 elif dir == Direction.right condition?: # else if 6 newX variableName? = newX + 1 value or expression? # reassign variable 7 elif dir == Direction.up condition?: # else if 8 newY variableName? = newY - 1 value or expression? # reassign variable 9 elif dir == Direction.down condition?: # else if 10 newY variableName? = newY + 1 value or expression? # reassign variable 11 return [newX, newY]value or expression?12
+static List<int>Type? getAdjacentSquare name?(List<int> sq, Direction dir parameter definitions?) { // function 1 var newX name? = sq[0]value or expression?;2 var newY name? = sq[1]value or expression?;3 +if (dir == Direction.left condition?) { 4 newX variableName? = newX - 1 value or expression?; // reassign variable 5 } else if (dir == Direction.right condition?) {6 newX variableName? = newX + 1 value or expression?; // reassign variable 7 } else if (dir == Direction.up condition?) {8 newY variableName? = newY - 1 value or expression?; // reassign variable 9 } else if (dir == Direction.down condition?) {10 newY variableName? = newY + 1 value or expression?; // reassign variable 11 } // if return [newX, newY]value or expression?;12 } // function
+Function getAdjacentSquare name?(sq As List(Of Integer), dir As Direction parameter definitions?) As List(Of Integer)Type? 1 Dim newX name? = sq[0]value or expression? ' variable definition 2 Dim newY name? = sq[1]value or expression? ' variable definition 3 +If dir = Direction.left condition? Then 4 newX variableName? = newX - 1 value or expression? ' reassign variable 5 ElseIf dir = Direction.right condition? Then 6 newX variableName? = newX + 1 value or expression? ' reassign variable 7 ElseIf dir = Direction.up condition? Then 8 newY variableName? = newY - 1 value or expression? ' reassign variable 9 ElseIf dir = Direction.down condition? Then 10 newY variableName? = newY + 1 value or expression? ' reassign variable 11 End If Return {newX, newY}value or expression?12 End Function
public class Global {
+static List<int>Type? getAdjacentSquare name?(List<int> sq, Direction dir parameter definitions?) { // function 1 var newX name? = sq[0]value or expression?;2 var newY name? = sq[1]value or expression?;3 +if (dir == Direction.left condition?) { 4 newX variableName? = newX - 1 value or expression?; // reassign variable 5 } else if (dir == Direction.right condition?) {6 newX variableName? = newX + 1 value or expression?; // reassign variable 7 } else if (dir == Direction.up condition?) {8 newY variableName? = newY - 1 value or expression?; // reassign variable 9 } else if (dir == Direction.down condition?) {10 newY variableName? = newY + 1 value or expression?; // reassign variable 11 } // if return [newX, newY]value or expression?;12 } // function
}
From the Blackjack demo:
enum Suit Name? spades, hearts, diamonds, clubs values?values?1 enum Outcome Name? undecided, win, lose, draw, winDouble values?values?2
class Suit Name?(Enum):
spades = 1
hearts = 2
diamonds = 3
clubs = 4 values?1 class Outcome Name?(Enum):
undecided = 1
win = 2
lose = 3
draw = 4
winDouble = 5 values?2
enum Suit Name? {spades, hearts, diamonds, clubs values?values?}1 enum Outcome Name? {undecided, win, lose, draw, winDouble values?values?}2
Enum Suit Name?
spades = 0
hearts = 1
diamonds = 2
clubs = 3
End Enum values?1 Enum Outcome Name?
undecided = 0
win = 1
lose = 2
draw = 3
winDouble = 4
End Enum values?2
public class Global {
enum Suit Name? {spades, hearts, diamonds, clubs values?values?}1 enum Outcome Name? {undecided, win, lose, draw, winDouble values?values?}2
}

### What you need to know about enums

- An enum – short for 'enumeration' – is the simplest form of user-defined type.

- Because it is a type, the name given to the enum (`DirectionDirectionDirectionDirectionDirection` above must start with an upper-case letter.
- An enum forces any named value of that type to be one of a fixed number of named values, listed in the enum definition.
- The instruction `variable currentDirname? set to Direction.rightvalue or expression?0currentDirname? = Direction.rightvalue or expression? # variable definition0var currentDirname? = Direction.rightvalue or expression?;0Dim currentDirname? = Direction.rightvalue or expression? ' variable definition0var currentDirname? = Direction.rightvalue or expression?;0` initialises `currentDircurrentDircurrentDircurrentDircurrentDir` with the value `rightrightrightrightright` defined on the enum named `DirectionDirectionDirectionDirectionDirection`.
- Because the variable `currentDirectcurrentDirectcurrentDirectcurrentDirectcurrentDirect` has the type
Direction, it may only be reassigned to another of the named values defined on `new codenew codenew codenew code
public class Global {
new code
}`, it may only be reassigned to another of the named values defined on `currentDircurrentDircurrentDircurrentDircurrentDir`
- An enum value cannot be converted to anything else.
- The advantages of using enums are:
  - Readability
  - Safety. If the four directions were defined as strings, e.g. `"right""right""right""right""right"` a mis-spelling might not picked up until runtime; however, writing e.g. `Direction.rifhtDirection.rifhtDirection.rifhtDirection.rifhtDirection.rifht` would be a compile error.

## Comment

### Examples of comments

From the Snake - procedural demo, where a comment at global level describes how to use the program:

# Use the w,a,s,d keys to change snake's direction comment?
// Use the w,a,s,d keys to change snake's direction comment?
' Use the w,a,s,d keys to change snake's direction comment?
public class Global {
// Use the w,a,s,d keys to change snake's direction comment?
}

From the Bubbles demo, where comments explain specific blocks of instructions

+procedure moveGrowBurst name?(bubbles as List<of CircleVG>parameter definitions?) 1 +for b item? in bubbles source? 2 +if random() < 0.05 condition? then 3 # 5% chance bubble 'bursts' and starts again tiny at bottom comment? call b.setRadius procedureName?(0 arguments?)4 call b.setCentreY procedureName?(75 arguments?)5 else 6 # bubble rises and grows slightly comment? call b.setCentreY procedureName?(b.centreY - 1 arguments?)7 call b.setRadius procedureName?(b.radius + 0.2 arguments?)8 end if end for call displayVectorGraphics procedureName?(bubbles arguments?)9 call sleep_ms procedureName?(5 arguments?)10 end procedure
+def moveGrowBurst name?(bubbles: list[CircleVG]parameter definitions?) -> None: # procedure 1 +for b item? in bubbles source?: 2 +if random() < 0.05 condition?: 3 # 5% chance bubble 'bursts' and starts again tiny at bottom comment? b.setRadius procedureName?(0 arguments?) # call procedure 4 b.setCentreY procedureName?(75 arguments?) # call procedure 5 else:6 # bubble rises and grows slightly comment? b.setCentreY procedureName?(b.centreY - 1 arguments?) # call procedure 7 b.setRadius procedureName?(b.radius + 0.2 arguments?) # call procedure 8 displayVectorGraphics procedureName?(bubbles arguments?) # call procedure 9 sleep_ms procedureName?(5 arguments?) # call procedure 10
+static void moveGrowBurst name?(List<CircleVG> bubbles parameter definitions?) { // procedure 1 +foreach (b item? in bubbles source?) { 2 +if (random() < 0.05 condition?) { 3 // 5% chance bubble 'bursts' and starts again tiny at bottom comment? b.setRadius procedureName?(0 arguments?); // call procedure 4 b.setCentreY procedureName?(75 arguments?); // call procedure 5 } else {6 // bubble rises and grows slightly comment? b.setCentreY procedureName?(b.centreY - 1 arguments?); // call procedure 7 b.setRadius procedureName?(b.radius + 0.2 arguments?); // call procedure 8 } // if } // foreach displayVectorGraphics procedureName?(bubbles arguments?); // call procedure 9 sleep_ms procedureName?(5 arguments?); // call procedure 10 } // procedure
+Sub moveGrowBurst name?(bubbles As List(Of CircleVG)parameter definitions?) ' procedure 1 +For Each b item? In bubbles source? 2 +If random() < 0.05 condition? Then 3 ' 5% chance bubble 'bursts' and starts again tiny at bottom comment? b.setRadius procedureName?(0 arguments?) ' call procedure 4 b.setCentreY procedureName?(75 arguments?) ' call procedure 5 Else 6 ' bubble rises and grows slightly comment? b.setCentreY procedureName?(b.centreY - 1 arguments?) ' call procedure 7 b.setRadius procedureName?(b.radius + 0.2 arguments?) ' call procedure 8 End If Next b displayVectorGraphics procedureName?(bubbles arguments?) ' call procedure 9 sleep_ms procedureName?(5 arguments?) ' call procedure 10 End Sub
public class Global {
+static void moveGrowBurst name?(List<CircleVG> bubbles parameter definitions?) { // procedure 1 +foreach (b item? in bubbles source?) { 2 +if (random() < 0.05 condition?) { 3 // 5% chance bubble 'bursts' and starts again tiny at bottom comment? b.setRadius procedureName?(0 arguments?); // call procedure 4 b.setCentreY procedureName?(75 arguments?); // call procedure 5 } else {6 // bubble rises and grows slightly comment? b.setCentreY procedureName?(b.centreY - 1 arguments?); // call procedure 7 b.setRadius procedureName?(b.radius + 0.2 arguments?); // call procedure 8 } // if } // foreach displayVectorGraphics procedureName?(bubbles arguments?); // call procedure 9 sleep_ms procedureName?(5 arguments?); // call procedure 10 } // procedure
}

### What you need to know about comments

- A comment is not an instruction: it is ignored by the compiler and does not change how the program works.
- Rather, a comment contains information about the program, intended to be read by a person seeking to understand or modify the code.
- A comment may be entered at any new code prompt by typing the symbol `# Code does not parse as Elan.# Code does not parse as Elan.# Code does not parse as Elan.# Code does not parse as Elan.# Code does not parse as Elan.` which then provides a field in which you may enter text, or leave blank.
- Your text may contain any characters, except that it must not start with an open square bracket [.
- When coding with Elan, a comment added by the programmer always starts on a new line.
- Comments that you see written after an instruction are generated by the system and may not be edited or deleted.
- Every Elan program has a single comment at the top of the file, which is generated by the system and cannot be edited or deleted by the user; this comment is known as the 'file header'.

# Statement instructions

Statement instructions (sometimes referred to as 'statements') are the instructions used with in the methods of a program: the main routine, functions, and procedures.

## Print

#### Examples of print statements

From the Date Time demo, printing the time (as a number of seconds) and then the date by calling the function getDate inline within the print statement:

+main 1 variable reply name? set to ""value or expression?2 +while not reply.upperCase().equals("Q")condition? 3 reassign reply variableName? to input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression?4 +if reply.equals("")condition? then 5 variable now name? set to divAsInt(clock(), 1000)value or expression?6 print(now arguments?)7 print(getDate(now)arguments?)8 else 9 +try 10 variable td name? set to int(reply)value or expression?11 +if td >= 0 condition? then 12 call print procedureName?(getDate(td)arguments?)13 end if catch e variableName? as ElanRuntimeError type e.g. ElanRuntimeError or CustomError?14 end try end if end while end main
+def main() -> None: 1 reply name? = ""value or expression? # variable definition 2 +while not reply.upperCase().equals("Q")condition?: 3 reply variableName? = input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression? # reassign variable 4 +if reply.equals("")condition?: 5 now name? = divAsInt(clock(), 1000)value or expression? # variable definition 6 print(now arguments?)7 print(getDate(now)arguments?)8 else:9 +try: 10 td name? = int(reply)value or expression? # variable definition 11 +if td >= 0 condition?: 12 print procedureName?(getDate(td)arguments?)13 except ElanRuntimeError type e.g. ElanRuntimeError or CustomError? as e variableName?: # catch 14 main()
+static void main() { 1 var reply name? = ""value or expression?;2 +while (!reply.upperCase().equals("Q")condition?) { 3 reply variableName? = input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression?; // reassign variable 4 +if (reply.equals("")condition?) { 5 var now name? = divAsInt(clock(), 1000)value or expression?;6 Console.WriteLine(now arguments?); // print 7 Console.WriteLine(getDate(now)arguments?); // print 8 } else {9 +try { 10 var td name? = int(reply)value or expression?;11 +if (td >= 0 condition?) { 12 print procedureName?(getDate(td)arguments?);13 } // if } catch (ElanRuntimeError type e.g. ElanRuntimeError or CustomError? e variableName?) {14 } // try } // if } // while } // main
+Sub main() 1 Dim reply name? = ""value or expression? ' variable definition 2 +While Not reply.upperCase().equals("Q")condition? 3 reply variableName? = input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression? ' reassign variable 4 +If reply.equals("")condition? Then 5 Dim now name? = divAsInt(clock(), 1000)value or expression? ' variable definition 6 Console.WriteLine(now arguments?) ' print 7 Console.WriteLine(getDate(now)arguments?) ' print 8 Else 9 +Try 10 Dim td name? = int(reply)value or expression? ' variable definition 11 +If td >= 0 condition? Then 12 print procedureName?(getDate(td)arguments?)13 End If Catch e variableName? As ElanRuntimeError type e.g. ElanRuntimeError or CustomError?14 End Try End If End While End Sub
public class Global {
+static void main() { 1 var reply name? = ""value or expression?;2 +while (!reply.upperCase().equals("Q")condition?) { 3 reply variableName? = input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression?; // reassign variable 4 +if (reply.equals("")condition?) { 5 var now name? = divAsInt(clock(), 1000)value or expression?;6 System.out.println(now arguments?); // print 7 System.out.println(getDate(now)arguments?); // print 8 } else {9 +try { 10 var td name? = int(reply)value or expression?;11 +if (td >= 0 condition?) { 12 print procedureName?(getDate(td)arguments?);13 } // if } catch (ElanRuntimeError type e.g. ElanRuntimeError or CustomError? e variableName?) {14 } // try } // if } // while } // main
}

From the Ripple sort demo, printing a list:

+main 1 variable li name? set to [7, 1, 0, 4, 8, 3, 6]value or expression?2 print(li arguments?)3 call inPlaceRippleSort procedureName?(li arguments?)4 call print procedureName?(li arguments?)5 end main
+def main() -> None: 1 li name? = [7, 1, 0, 4, 8, 3, 6]value or expression? # variable definition 2 print(li arguments?)3 inPlaceRippleSort procedureName?(li arguments?) # call procedure 4 print procedureName?(li arguments?)5 main()
+static void main() { 1 var li name? = [7, 1, 0, 4, 8, 3, 6]value or expression?;2 Console.WriteLine(li arguments?); // print 3 inPlaceRippleSort procedureName?(li arguments?); // call procedure 4 print procedureName?(li arguments?);5 } // main
+Sub main() 1 Dim li name? = {7, 1, 0, 4, 8, 3, 6}value or expression? ' variable definition 2 Console.WriteLine(li arguments?) ' print 3 inPlaceRippleSort procedureName?(li arguments?) ' call procedure 4 print procedureName?(li arguments?)5 End Sub
public class Global {
+static void main() { 1 var li name? = [7, 1, 0, 4, 8, 3, 6]value or expression?;2 System.out.println(li arguments?); // print 3 inPlaceRippleSort procedureName?(li arguments?); // call procedure 4 print procedureName?(li arguments?);5 } // main
}

From the Snake - procedural demo, printing an interpolated string (last line of the main routine):

+main 1 variable blocks name? set to createBlockGraphics(white)value or expression?2 variable head name? set to [20, 15]value or expression?3 variable tail name? set to head value or expression?4 variable body name? set to [head]value or expression?5 variable currentDir name? set to Direction.right value or expression?6 variable gameOn name? set to true value or expression?7 variable apple name? set to [0, 0]value or expression?8 call setAppleToRandomPosition procedureName?(apple, body arguments?)9 +while gameOn condition? 10 call updateDisplay procedureName?(blocks, head, tail, body, apple arguments?)11 variable currentDirRef name? set to new AsRef<of Direction>(currentDir)value or expression?12 variable headRef name? set to new AsRef<of List<of Int>>(head)value or expression?13 variable tailRef name? set to new AsRef<of List<of Int>>(tail)value or expression?14 call updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?)15 reassign head variableName? to headRef.value()value or expression?16 reassign tail variableName? to tailRef.value()value or expression?17 reassign currentDir variableName? to currentDirRef.value()value or expression?18 reassign gameOn variableName? to not hasHitEdge(head[0], head[1]) and not body.contains(head)value or expression?19 +if head.equals(apple)condition? then 20 call setAppleToRandomPosition procedureName?(apple, body arguments?)21 else 22 call body.removeAt procedureName?(0 arguments?)23 end if call sleep_ms procedureName?(150 arguments?)24 end while call print procedureName?($"Game Over! Score: {body.length() - 1}"arguments?)25 end main
+def main() -> None: 1 blocks name? = createBlockGraphics(white)value or expression? # variable definition 2 head name? = [20, 15]value or expression? # variable definition 3 tail name? = head value or expression? # variable definition 4 body name? = [head]value or expression? # variable definition 5 currentDir name? = Direction.right value or expression? # variable definition 6 gameOn name? = True value or expression? # variable definition 7 apple name? = [0, 0]value or expression? # variable definition 8 setAppleToRandomPosition procedureName?(apple, body arguments?) # call procedure 9 +while gameOn condition?: 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?) # call procedure 11 currentDirRef name? = AsRef[Direction](currentDir)value or expression? # variable definition 12 headRef name? = AsRef[list[int]](head)value or expression? # variable definition 13 tailRef name? = AsRef[list[int]](tail)value or expression? # variable definition 14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?) # call procedure 15 head variableName? = headRef.value()value or expression? # reassign variable 16 tail variableName? = tailRef.value()value or expression? # reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression? # reassign variable 18 gameOn variableName? = not hasHitEdge(head[0], head[1]) and not body.contains(head)value or expression? # reassign variable 19 +if head.equals(apple)condition?: 20 setAppleToRandomPosition procedureName?(apple, body arguments?) # call procedure 21 else:22 body.removeAt procedureName?(0 arguments?) # call procedure 23 sleep_ms procedureName?(150 arguments?) # call procedure 24 print procedureName?(f"Game Over! Score: {body.length() - 1}"arguments?)25 main()
+static void main() { 1 var blocks name? = createBlockGraphics(white)value or expression?;2 var head name? = [20, 15]value or expression?;3 var tail name? = head value or expression?;4 var body name? = [head]value or expression?;5 var currentDir name? = Direction.right value or expression?;6 var gameOn name? = true value or expression?;7 var apple name? = [0, 0]value or expression?;8 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 9 +while (gameOn condition?) { 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?); // call procedure 11 var currentDirRef name? = new AsRef<Direction>(currentDir)value or expression?;12 var headRef name? = new AsRef<List<int>>(head)value or expression?;13 var tailRef name? = new AsRef<List<int>>(tail)value or expression?;14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?); // call procedure 15 head variableName? = headRef.value()value or expression?; // reassign variable 16 tail variableName? = tailRef.value()value or expression?; // reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression?; // reassign variable 18 gameOn variableName? = !hasHitEdge(head[0], head[1]) && !body.contains(head)value or expression?; // reassign variable 19 +if (head.equals(apple)condition?) { 20 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 21 } else {22 body.removeAt procedureName?(0 arguments?); // call procedure 23 } // if sleep_ms procedureName?(150 arguments?); // call procedure 24 } // while print procedureName?($"Game Over! Score: {body.length() - 1}"arguments?);25 } // main
+Sub main() 1 Dim blocks name? = createBlockGraphics(white)value or expression? ' variable definition 2 Dim head name? = {20, 15}value or expression? ' variable definition 3 Dim tail name? = head value or expression? ' variable definition 4 Dim body name? = {head}value or expression? ' variable definition 5 Dim currentDir name? = Direction.right value or expression? ' variable definition 6 Dim gameOn name? = True value or expression? ' variable definition 7 Dim apple name? = {0, 0}value or expression? ' variable definition 8 setAppleToRandomPosition procedureName?(apple, body arguments?) ' call procedure 9 +While gameOn condition? 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?) ' call procedure 11 Dim currentDirRef name? = New AsRef(Of Direction)(currentDir)value or expression? ' variable definition 12 Dim headRef name? = New AsRef(Of List(Of Integer))(head)value or expression? ' variable definition 13 Dim tailRef name? = New AsRef(Of List(Of Integer))(tail)value or expression? ' variable definition 14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?) ' call procedure 15 head variableName? = headRef.value()value or expression? ' reassign variable 16 tail variableName? = tailRef.value()value or expression? ' reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression? ' reassign variable 18 gameOn variableName? = Not hasHitEdge(head[0], head[1]) And Not body.contains(head)value or expression? ' reassign variable 19 +If head.equals(apple)condition? Then 20 setAppleToRandomPosition procedureName?(apple, body arguments?) ' call procedure 21 Else 22 body.removeAt procedureName?(0 arguments?) ' call procedure 23 End If sleep_ms procedureName?(150 arguments?) ' call procedure 24 End While print procedureName?($"Game Over! Score: {body.length() - 1}"arguments?)25 End Sub
public class Global {
+static void main() { 1 var blocks name? = createBlockGraphics(white)value or expression?;2 var head name? = [20, 15]value or expression?;3 var tail name? = head value or expression?;4 var body name? = [head]value or expression?;5 var currentDir name? = Direction.right value or expression?;6 var gameOn name? = true value or expression?;7 var apple name? = [0, 0]value or expression?;8 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 9 +while (gameOn condition?) { 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?); // call procedure 11 var currentDirRef name? = new AsRef<Direction>(currentDir)value or expression?;12 var headRef name? = new AsRef<List<int>>(head)value or expression?;13 var tailRef name? = new AsRef<List<int>>(tail)value or expression?;14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?); // call procedure 15 head variableName? = headRef.value()value or expression?; // reassign variable 16 tail variableName? = tailRef.value()value or expression?; // reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression?; // reassign variable 18 gameOn variableName? = !hasHitEdge(head[0], head[1]) && !body.contains(head)value or expression?; // reassign variable 19 +if (head.equals(apple)condition?) { 20 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 21 } else {22 body.removeAt procedureName?(0 arguments?); // call procedure 23 } // if sleep_ms procedureName?(150 arguments?); // call procedure 24 } // while print procedureName?(String.format("Game Over! Score: %", body.length() - 1)arguments?);25 } // main
}

### What you need to know about print statements

- The print instruction writes a value to display.
- It automatically prints a new line after the value.
- The value can be any expression.
- You must provide a value; if you just want to print a blank line, just set the value to `new codenew codenew codenew code
  public class Global {
  new code
  }`
  +main 1 variable reply name? set to ""value or expression?2 +while not reply.upperCase().equals("Q")condition? 3 reassign reply variableName? to input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression?4 +if reply.equals("")condition? then 5 variable now name? set to divAsInt(clock(), 1000)value or expression?6 print(now arguments?)7 print(getDate(now)arguments?)8 else 9 +try 10 variable td name? set to int(reply)value or expression?11 +if td >= 0 condition? then 12 call print procedureName?(getDate(td)arguments?)13 end if catch e variableName? as ElanRuntimeError type e.g. ElanRuntimeError or CustomError?14 end try end if end while end main
  +def main() -> None: 1 reply name? = ""value or expression? # variable definition 2 +while not reply.upperCase().equals("Q")condition?: 3 reply variableName? = input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression? # reassign variable 4 +if reply.equals("")condition?: 5 now name? = divAsInt(clock(), 1000)value or expression? # variable definition 6 print(now arguments?)7 print(getDate(now)arguments?)8 else:9 +try: 10 td name? = int(reply)value or expression? # variable definition 11 +if td >= 0 condition?: 12 print procedureName?(getDate(td)arguments?)13 except ElanRuntimeError type e.g. ElanRuntimeError or CustomError? as e variableName?: # catch 14 main()
  +static void main() { 1 var reply name? = ""value or expression?;2 +while (!reply.upperCase().equals("Q")condition?) { 3 reply variableName? = input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression?; // reassign variable 4 +if (reply.equals("")condition?) { 5 var now name? = divAsInt(clock(), 1000)value or expression?;6 Console.WriteLine(now arguments?); // print 7 Console.WriteLine(getDate(now)arguments?); // print 8 } else {9 +try { 10 var td name? = int(reply)value or expression?;11 +if (td >= 0 condition?) { 12 print procedureName?(getDate(td)arguments?);13 } // if } catch (ElanRuntimeError type e.g. ElanRuntimeError or CustomError? e variableName?) {14 } // try } // if } // while } // main
  +Sub main() 1 Dim reply name? = ""value or expression? ' variable definition 2 +While Not reply.upperCase().equals("Q")condition? 3 reply variableName? = input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression? ' reassign variable 4 +If reply.equals("")condition? Then 5 Dim now name? = divAsInt(clock(), 1000)value or expression? ' variable definition 6 Console.WriteLine(now arguments?) ' print 7 Console.WriteLine(getDate(now)arguments?) ' print 8 Else 9 +Try 10 Dim td name? = int(reply)value or expression? ' variable definition 11 +If td >= 0 condition? Then 12 print procedureName?(getDate(td)arguments?)13 End If Catch e variableName? As ElanRuntimeError type e.g. ElanRuntimeError or CustomError?14 End Try End If End While End Sub
  public class Global {
  +static void main() { 1 var reply name? = ""value or expression?;2 +while (!reply.upperCase().equals("Q")condition?) { 3 reply variableName? = input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression?; // reassign variable 4 +if (reply.equals("")condition?) { 5 var now name? = divAsInt(clock(), 1000)value or expression?;6 System.out.println(now arguments?); // print 7 System.out.println(getDate(now)arguments?); // print 8 } else {9 +try { 10 var td name? = int(reply)value or expression?;11 +if (td >= 0 condition?) { 12 print procedureName?(getDate(td)arguments?);13 } // if } catch (ElanRuntimeError type e.g. ElanRuntimeError or CustomError? e variableName?) {14 } // try } // if } // while } // main
  }

  From the Ripple sort demo, printing a list:

  +main 1 variable li name? set to [7, 1, 0, 4, 8, 3, 6]value or expression?2 print(li arguments?)3 call inPlaceRippleSort procedureName?(li arguments?)4 call print procedureName?(li arguments?)5 end main
  +def main() -> None: 1 li name? = [7, 1, 0, 4, 8, 3, 6]value or expression? # variable definition 2 print(li arguments?)3 inPlaceRippleSort procedureName?(li arguments?) # call procedure 4 print procedureName?(li arguments?)5 main()
  +static void main() { 1 var li name? = [7, 1, 0, 4, 8, 3, 6]value or expression?;2 Console.WriteLine(li arguments?); // print 3 inPlaceRippleSort procedureName?(li arguments?); // call procedure 4 print procedureName?(li arguments?);5 } // main
  +Sub main() 1 Dim li name? = {7, 1, 0, 4, 8, 3, 6}value or expression? ' variable definition 2 Console.WriteLine(li arguments?) ' print 3 inPlaceRippleSort procedureName?(li arguments?) ' call procedure 4 print procedureName?(li arguments?)5 End Sub
  public class Global {
  +static void main() { 1 var li name? = [7, 1, 0, 4, 8, 3, 6]value or expression?;2 System.out.println(li arguments?); // print 3 inPlaceRippleSort procedureName?(li arguments?); // call procedure 4 print procedureName?(li arguments?);5 } // main
  }

  From the Snake - procedural demo, printing an interpolated string (last line of the main routine):

  +main 1 variable blocks name? set to createBlockGraphics(white)value or expression?2 variable head name? set to [20, 15]value or expression?3 variable tail name? set to head value or expression?4 variable body name? set to [head]value or expression?5 variable currentDir name? set to Direction.right value or expression?6 variable gameOn name? set to true value or expression?7 variable apple name? set to [0, 0]value or expression?8 call setAppleToRandomPosition procedureName?(apple, body arguments?)9 +while gameOn condition? 10 call updateDisplay procedureName?(blocks, head, tail, body, apple arguments?)11 variable currentDirRef name? set to new AsRef<of Direction>(currentDir)value or expression?12 variable headRef name? set to new AsRef<of List<of Int>>(head)value or expression?13 variable tailRef name? set to new AsRef<of List<of Int>>(tail)value or expression?14 call updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?)15 reassign head variableName? to headRef.value()value or expression?16 reassign tail variableName? to tailRef.value()value or expression?17 reassign currentDir variableName? to currentDirRef.value()value or expression?18 reassign gameOn variableName? to not hasHitEdge(head[0], head[1]) and not body.contains(head)value or expression?19 +if head.equals(apple)condition? then 20 call setAppleToRandomPosition procedureName?(apple, body arguments?)21 else 22 call body.removeAt procedureName?(0 arguments?)23 end if call sleep_ms procedureName?(150 arguments?)24 end while call print procedureName?($"Game Over! Score: {body.length() - 1}"arguments?)25 end main
  +def main() -> None: 1 blocks name? = createBlockGraphics(white)value or expression? # variable definition 2 head name? = [20, 15]value or expression? # variable definition 3 tail name? = head value or expression? # variable definition 4 body name? = [head]value or expression? # variable definition 5 currentDir name? = Direction.right value or expression? # variable definition 6 gameOn name? = True value or expression? # variable definition 7 apple name? = [0, 0]value or expression? # variable definition 8 setAppleToRandomPosition procedureName?(apple, body arguments?) # call procedure 9 +while gameOn condition?: 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?) # call procedure 11 currentDirRef name? = AsRef[Direction](currentDir)value or expression? # variable definition 12 headRef name? = AsRef[list[int]](head)value or expression? # variable definition 13 tailRef name? = AsRef[list[int]](tail)value or expression? # variable definition 14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?) # call procedure 15 head variableName? = headRef.value()value or expression? # reassign variable 16 tail variableName? = tailRef.value()value or expression? # reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression? # reassign variable 18 gameOn variableName? = not hasHitEdge(head[0], head[1]) and not body.contains(head)value or expression? # reassign variable 19 +if head.equals(apple)condition?: 20 setAppleToRandomPosition procedureName?(apple, body arguments?) # call procedure 21 else:22 body.removeAt procedureName?(0 arguments?) # call procedure 23 sleep_ms procedureName?(150 arguments?) # call procedure 24 print procedureName?(f"Game Over! Score: {body.length() - 1}"arguments?)25 main()
  +static void main() { 1 var blocks name? = createBlockGraphics(white)value or expression?;2 var head name? = [20, 15]value or expression?;3 var tail name? = head value or expression?;4 var body name? = [head]value or expression?;5 var currentDir name? = Direction.right value or expression?;6 var gameOn name? = true value or expression?;7 var apple name? = [0, 0]value or expression?;8 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 9 +while (gameOn condition?) { 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?); // call procedure 11 var currentDirRef name? = new AsRef<Direction>(currentDir)value or expression?;12 var headRef name? = new AsRef<List<int>>(head)value or expression?;13 var tailRef name? = new AsRef<List<int>>(tail)value or expression?;14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?); // call procedure 15 head variableName? = headRef.value()value or expression?; // reassign variable 16 tail variableName? = tailRef.value()value or expression?; // reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression?; // reassign variable 18 gameOn variableName? = !hasHitEdge(head[0], head[1]) && !body.contains(head)value or expression?; // reassign variable 19 +if (head.equals(apple)condition?) { 20 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 21 } else {22 body.removeAt procedureName?(0 arguments?); // call procedure 23 } // if sleep_ms procedureName?(150 arguments?); // call procedure 24 } // while print procedureName?($"Game Over! Score: {body.length() - 1}"arguments?);25 } // main
  +Sub main() 1 Dim blocks name? = createBlockGraphics(white)value or expression? ' variable definition 2 Dim head name? = {20, 15}value or expression? ' variable definition 3 Dim tail name? = head value or expression? ' variable definition 4 Dim body name? = {head}value or expression? ' variable definition 5 Dim currentDir name? = Direction.right value or expression? ' variable definition 6 Dim gameOn name? = True value or expression? ' variable definition 7 Dim apple name? = {0, 0}value or expression? ' variable definition 8 setAppleToRandomPosition procedureName?(apple, body arguments?) ' call procedure 9 +While gameOn condition? 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?) ' call procedure 11 Dim currentDirRef name? = New AsRef(Of Direction)(currentDir)value or expression? ' variable definition 12 Dim headRef name? = New AsRef(Of List(Of Integer))(head)value or expression? ' variable definition 13 Dim tailRef name? = New AsRef(Of List(Of Integer))(tail)value or expression? ' variable definition 14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?) ' call procedure 15 head variableName? = headRef.value()value or expression? ' reassign variable 16 tail variableName? = tailRef.value()value or expression? ' reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression? ' reassign variable 18 gameOn variableName? = Not hasHitEdge(head[0], head[1]) And Not body.contains(head)value or expression? ' reassign variable 19 +If head.equals(apple)condition? Then 20 setAppleToRandomPosition procedureName?(apple, body arguments?) ' call procedure 21 Else 22 body.removeAt procedureName?(0 arguments?) ' call procedure 23 End If sleep_ms procedureName?(150 arguments?) ' call procedure 24 End While print procedureName?($"Game Over! Score: {body.length() - 1}"arguments?)25 End Sub
  public class Global {
  +static void main() { 1 var blocks name? = createBlockGraphics(white)value or expression?;2 var head name? = [20, 15]value or expression?;3 var tail name? = head value or expression?;4 var body name? = [head]value or expression?;5 var currentDir name? = Direction.right value or expression?;6 var gameOn name? = true value or expression?;7 var apple name? = [0, 0]value or expression?;8 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 9 +while (gameOn condition?) { 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?); // call procedure 11 var currentDirRef name? = new AsRef<Direction>(currentDir)value or expression?;12 var headRef name? = new AsRef<List<int>>(head)value or expression?;13 var tailRef name? = new AsRef<List<int>>(tail)value or expression?;14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?); // call procedure 15 head variableName? = headRef.value()value or expression?; // reassign variable 16 tail variableName? = tailRef.value()value or expression?; // reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression?; // reassign variable 18 gameOn variableName? = !hasHitEdge(head[0], head[1]) && !body.contains(head)value or expression?; // reassign variable 19 +if (head.equals(apple)condition?) { 20 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 21 } else {22 body.removeAt procedureName?(0 arguments?); // call procedure 23 } // if sleep_ms procedureName?(150 arguments?); // call procedure 24 } // while print procedureName?(String.format("Game Over! Score: %", body.length() - 1)arguments?);25 } // main
  }

### What you need to know about print statements

- The print instruction writes a value to display.
- It automatically prints a new line after the value.
- The value can be any expression.
- You must provide a value; if you just want to print a blank line, just set the value to `new codenew codenew codenew code
  public class Global {
  new code
  }`
  +main 1 variable li name? set to [7, 1, 0, 4, 8, 3, 6]value or expression?2 print(li arguments?)3 call inPlaceRippleSort procedureName?(li arguments?)4 call print procedureName?(li arguments?)5 end main
  +def main() -> None: 1 li name? = [7, 1, 0, 4, 8, 3, 6]value or expression? # variable definition 2 print(li arguments?)3 inPlaceRippleSort procedureName?(li arguments?) # call procedure 4 print procedureName?(li arguments?)5 main()
  +static void main() { 1 var li name? = [7, 1, 0, 4, 8, 3, 6]value or expression?;2 Console.WriteLine(li arguments?); // print 3 inPlaceRippleSort procedureName?(li arguments?); // call procedure 4 print procedureName?(li arguments?);5 } // main
  +Sub main() 1 Dim li name? = {7, 1, 0, 4, 8, 3, 6}value or expression? ' variable definition 2 Console.WriteLine(li arguments?) ' print 3 inPlaceRippleSort procedureName?(li arguments?) ' call procedure 4 print procedureName?(li arguments?)5 End Sub
  public class Global {
  +static void main() { 1 var li name? = [7, 1, 0, 4, 8, 3, 6]value or expression?;2 System.out.println(li arguments?); // print 3 inPlaceRippleSort procedureName?(li arguments?); // call procedure 4 print procedureName?(li arguments?);5 } // main
  }

  From the Snake - procedural demo, printing an interpolated string (last line of the main routine):

  +main 1 variable blocks name? set to createBlockGraphics(white)value or expression?2 variable head name? set to [20, 15]value or expression?3 variable tail name? set to head value or expression?4 variable body name? set to [head]value or expression?5 variable currentDir name? set to Direction.right value or expression?6 variable gameOn name? set to true value or expression?7 variable apple name? set to [0, 0]value or expression?8 call setAppleToRandomPosition procedureName?(apple, body arguments?)9 +while gameOn condition? 10 call updateDisplay procedureName?(blocks, head, tail, body, apple arguments?)11 variable currentDirRef name? set to new AsRef<of Direction>(currentDir)value or expression?12 variable headRef name? set to new AsRef<of List<of Int>>(head)value or expression?13 variable tailRef name? set to new AsRef<of List<of Int>>(tail)value or expression?14 call updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?)15 reassign head variableName? to headRef.value()value or expression?16 reassign tail variableName? to tailRef.value()value or expression?17 reassign currentDir variableName? to currentDirRef.value()value or expression?18 reassign gameOn variableName? to not hasHitEdge(head[0], head[1]) and not body.contains(head)value or expression?19 +if head.equals(apple)condition? then 20 call setAppleToRandomPosition procedureName?(apple, body arguments?)21 else 22 call body.removeAt procedureName?(0 arguments?)23 end if call sleep_ms procedureName?(150 arguments?)24 end while call print procedureName?($"Game Over! Score: {body.length() - 1}"arguments?)25 end main
  +def main() -> None: 1 blocks name? = createBlockGraphics(white)value or expression? # variable definition 2 head name? = [20, 15]value or expression? # variable definition 3 tail name? = head value or expression? # variable definition 4 body name? = [head]value or expression? # variable definition 5 currentDir name? = Direction.right value or expression? # variable definition 6 gameOn name? = True value or expression? # variable definition 7 apple name? = [0, 0]value or expression? # variable definition 8 setAppleToRandomPosition procedureName?(apple, body arguments?) # call procedure 9 +while gameOn condition?: 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?) # call procedure 11 currentDirRef name? = AsRef[Direction](currentDir)value or expression? # variable definition 12 headRef name? = AsRef[list[int]](head)value or expression? # variable definition 13 tailRef name? = AsRef[list[int]](tail)value or expression? # variable definition 14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?) # call procedure 15 head variableName? = headRef.value()value or expression? # reassign variable 16 tail variableName? = tailRef.value()value or expression? # reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression? # reassign variable 18 gameOn variableName? = not hasHitEdge(head[0], head[1]) and not body.contains(head)value or expression? # reassign variable 19 +if head.equals(apple)condition?: 20 setAppleToRandomPosition procedureName?(apple, body arguments?) # call procedure 21 else:22 body.removeAt procedureName?(0 arguments?) # call procedure 23 sleep_ms procedureName?(150 arguments?) # call procedure 24 print procedureName?(f"Game Over! Score: {body.length() - 1}"arguments?)25 main()
  +static void main() { 1 var blocks name? = createBlockGraphics(white)value or expression?;2 var head name? = [20, 15]value or expression?;3 var tail name? = head value or expression?;4 var body name? = [head]value or expression?;5 var currentDir name? = Direction.right value or expression?;6 var gameOn name? = true value or expression?;7 var apple name? = [0, 0]value or expression?;8 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 9 +while (gameOn condition?) { 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?); // call procedure 11 var currentDirRef name? = new AsRef<Direction>(currentDir)value or expression?;12 var headRef name? = new AsRef<List<int>>(head)value or expression?;13 var tailRef name? = new AsRef<List<int>>(tail)value or expression?;14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?); // call procedure 15 head variableName? = headRef.value()value or expression?; // reassign variable 16 tail variableName? = tailRef.value()value or expression?; // reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression?; // reassign variable 18 gameOn variableName? = !hasHitEdge(head[0], head[1]) && !body.contains(head)value or expression?; // reassign variable 19 +if (head.equals(apple)condition?) { 20 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 21 } else {22 body.removeAt procedureName?(0 arguments?); // call procedure 23 } // if sleep_ms procedureName?(150 arguments?); // call procedure 24 } // while print procedureName?($"Game Over! Score: {body.length() - 1}"arguments?);25 } // main
  +Sub main() 1 Dim blocks name? = createBlockGraphics(white)value or expression? ' variable definition 2 Dim head name? = {20, 15}value or expression? ' variable definition 3 Dim tail name? = head value or expression? ' variable definition 4 Dim body name? = {head}value or expression? ' variable definition 5 Dim currentDir name? = Direction.right value or expression? ' variable definition 6 Dim gameOn name? = True value or expression? ' variable definition 7 Dim apple name? = {0, 0}value or expression? ' variable definition 8 setAppleToRandomPosition procedureName?(apple, body arguments?) ' call procedure 9 +While gameOn condition? 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?) ' call procedure 11 Dim currentDirRef name? = New AsRef(Of Direction)(currentDir)value or expression? ' variable definition 12 Dim headRef name? = New AsRef(Of List(Of Integer))(head)value or expression? ' variable definition 13 Dim tailRef name? = New AsRef(Of List(Of Integer))(tail)value or expression? ' variable definition 14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?) ' call procedure 15 head variableName? = headRef.value()value or expression? ' reassign variable 16 tail variableName? = tailRef.value()value or expression? ' reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression? ' reassign variable 18 gameOn variableName? = Not hasHitEdge(head[0], head[1]) And Not body.contains(head)value or expression? ' reassign variable 19 +If head.equals(apple)condition? Then 20 setAppleToRandomPosition procedureName?(apple, body arguments?) ' call procedure 21 Else 22 body.removeAt procedureName?(0 arguments?) ' call procedure 23 End If sleep_ms procedureName?(150 arguments?) ' call procedure 24 End While print procedureName?($"Game Over! Score: {body.length() - 1}"arguments?)25 End Sub
  public class Global {
  +static void main() { 1 var blocks name? = createBlockGraphics(white)value or expression?;2 var head name? = [20, 15]value or expression?;3 var tail name? = head value or expression?;4 var body name? = [head]value or expression?;5 var currentDir name? = Direction.right value or expression?;6 var gameOn name? = true value or expression?;7 var apple name? = [0, 0]value or expression?;8 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 9 +while (gameOn condition?) { 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?); // call procedure 11 var currentDirRef name? = new AsRef<Direction>(currentDir)value or expression?;12 var headRef name? = new AsRef<List<int>>(head)value or expression?;13 var tailRef name? = new AsRef<List<int>>(tail)value or expression?;14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?); // call procedure 15 head variableName? = headRef.value()value or expression?; // reassign variable 16 tail variableName? = tailRef.value()value or expression?; // reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression?; // reassign variable 18 gameOn variableName? = !hasHitEdge(head[0], head[1]) && !body.contains(head)value or expression?; // reassign variable 19 +if (head.equals(apple)condition?) { 20 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 21 } else {22 body.removeAt procedureName?(0 arguments?); // call procedure 23 } // if sleep_ms procedureName?(150 arguments?); // call procedure 24 } // while print procedureName?(String.format("Game Over! Score: %", body.length() - 1)arguments?);25 } // main
  }

### What you need to know about print statements

- The print instruction writes a value to display.
- It automatically prints a new line after the value.
- The value can be any expression.
- You must provide a value; if you just want to print a blank line, just set the value to `new codenew codenew codenew code
  public class Global {
  new code
  }`
  +main 1 variable blocks name? set to createBlockGraphics(white)value or expression?2 variable head name? set to [20, 15]value or expression?3 variable tail name? set to head value or expression?4 variable body name? set to [head]value or expression?5 variable currentDir name? set to Direction.right value or expression?6 variable gameOn name? set to true value or expression?7 variable apple name? set to [0, 0]value or expression?8 call setAppleToRandomPosition procedureName?(apple, body arguments?)9 +while gameOn condition? 10 call updateDisplay procedureName?(blocks, head, tail, body, apple arguments?)11 variable currentDirRef name? set to new AsRef<of Direction>(currentDir)value or expression?12 variable headRef name? set to new AsRef<of List<of Int>>(head)value or expression?13 variable tailRef name? set to new AsRef<of List<of Int>>(tail)value or expression?14 call updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?)15 reassign head variableName? to headRef.value()value or expression?16 reassign tail variableName? to tailRef.value()value or expression?17 reassign currentDir variableName? to currentDirRef.value()value or expression?18 reassign gameOn variableName? to not hasHitEdge(head[0], head[1]) and not body.contains(head)value or expression?19 +if head.equals(apple)condition? then 20 call setAppleToRandomPosition procedureName?(apple, body arguments?)21 else 22 call body.removeAt procedureName?(0 arguments?)23 end if call sleep_ms procedureName?(150 arguments?)24 end while call print procedureName?($"Game Over! Score: {body.length() - 1}"arguments?)25 end main
  +def main() -> None: 1 blocks name? = createBlockGraphics(white)value or expression? # variable definition 2 head name? = [20, 15]value or expression? # variable definition 3 tail name? = head value or expression? # variable definition 4 body name? = [head]value or expression? # variable definition 5 currentDir name? = Direction.right value or expression? # variable definition 6 gameOn name? = True value or expression? # variable definition 7 apple name? = [0, 0]value or expression? # variable definition 8 setAppleToRandomPosition procedureName?(apple, body arguments?) # call procedure 9 +while gameOn condition?: 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?) # call procedure 11 currentDirRef name? = AsRef[Direction](currentDir)value or expression? # variable definition 12 headRef name? = AsRef[list[int]](head)value or expression? # variable definition 13 tailRef name? = AsRef[list[int]](tail)value or expression? # variable definition 14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?) # call procedure 15 head variableName? = headRef.value()value or expression? # reassign variable 16 tail variableName? = tailRef.value()value or expression? # reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression? # reassign variable 18 gameOn variableName? = not hasHitEdge(head[0], head[1]) and not body.contains(head)value or expression? # reassign variable 19 +if head.equals(apple)condition?: 20 setAppleToRandomPosition procedureName?(apple, body arguments?) # call procedure 21 else:22 body.removeAt procedureName?(0 arguments?) # call procedure 23 sleep_ms procedureName?(150 arguments?) # call procedure 24 print procedureName?(f"Game Over! Score: {body.length() - 1}"arguments?)25 main()
  +static void main() { 1 var blocks name? = createBlockGraphics(white)value or expression?;2 var head name? = [20, 15]value or expression?;3 var tail name? = head value or expression?;4 var body name? = [head]value or expression?;5 var currentDir name? = Direction.right value or expression?;6 var gameOn name? = true value or expression?;7 var apple name? = [0, 0]value or expression?;8 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 9 +while (gameOn condition?) { 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?); // call procedure 11 var currentDirRef name? = new AsRef<Direction>(currentDir)value or expression?;12 var headRef name? = new AsRef<List<int>>(head)value or expression?;13 var tailRef name? = new AsRef<List<int>>(tail)value or expression?;14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?); // call procedure 15 head variableName? = headRef.value()value or expression?; // reassign variable 16 tail variableName? = tailRef.value()value or expression?; // reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression?; // reassign variable 18 gameOn variableName? = !hasHitEdge(head[0], head[1]) && !body.contains(head)value or expression?; // reassign variable 19 +if (head.equals(apple)condition?) { 20 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 21 } else {22 body.removeAt procedureName?(0 arguments?); // call procedure 23 } // if sleep_ms procedureName?(150 arguments?); // call procedure 24 } // while print procedureName?($"Game Over! Score: {body.length() - 1}"arguments?);25 } // main
  +Sub main() 1 Dim blocks name? = createBlockGraphics(white)value or expression? ' variable definition 2 Dim head name? = {20, 15}value or expression? ' variable definition 3 Dim tail name? = head value or expression? ' variable definition 4 Dim body name? = {head}value or expression? ' variable definition 5 Dim currentDir name? = Direction.right value or expression? ' variable definition 6 Dim gameOn name? = True value or expression? ' variable definition 7 Dim apple name? = {0, 0}value or expression? ' variable definition 8 setAppleToRandomPosition procedureName?(apple, body arguments?) ' call procedure 9 +While gameOn condition? 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?) ' call procedure 11 Dim currentDirRef name? = New AsRef(Of Direction)(currentDir)value or expression? ' variable definition 12 Dim headRef name? = New AsRef(Of List(Of Integer))(head)value or expression? ' variable definition 13 Dim tailRef name? = New AsRef(Of List(Of Integer))(tail)value or expression? ' variable definition 14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?) ' call procedure 15 head variableName? = headRef.value()value or expression? ' reassign variable 16 tail variableName? = tailRef.value()value or expression? ' reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression? ' reassign variable 18 gameOn variableName? = Not hasHitEdge(head[0], head[1]) And Not body.contains(head)value or expression? ' reassign variable 19 +If head.equals(apple)condition? Then 20 setAppleToRandomPosition procedureName?(apple, body arguments?) ' call procedure 21 Else 22 body.removeAt procedureName?(0 arguments?) ' call procedure 23 End If sleep_ms procedureName?(150 arguments?) ' call procedure 24 End While print procedureName?($"Game Over! Score: {body.length() - 1}"arguments?)25 End Sub
  public class Global {
  +static void main() { 1 var blocks name? = createBlockGraphics(white)value or expression?;2 var head name? = [20, 15]value or expression?;3 var tail name? = head value or expression?;4 var body name? = [head]value or expression?;5 var currentDir name? = Direction.right value or expression?;6 var gameOn name? = true value or expression?;7 var apple name? = [0, 0]value or expression?;8 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 9 +while (gameOn condition?) { 10 updateDisplay procedureName?(blocks, head, tail, body, apple arguments?); // call procedure 11 var currentDirRef name? = new AsRef<Direction>(currentDir)value or expression?;12 var headRef name? = new AsRef<List<int>>(head)value or expression?;13 var tailRef name? = new AsRef<List<int>>(tail)value or expression?;14 updateSnake procedureName?(currentDirRef, tailRef, headRef, body arguments?); // call procedure 15 head variableName? = headRef.value()value or expression?; // reassign variable 16 tail variableName? = tailRef.value()value or expression?; // reassign variable 17 currentDir variableName? = currentDirRef.value()value or expression?; // reassign variable 18 gameOn variableName? = !hasHitEdge(head[0], head[1]) && !body.contains(head)value or expression?; // reassign variable 19 +if (head.equals(apple)condition?) { 20 setAppleToRandomPosition procedureName?(apple, body arguments?); // call procedure 21 } else {22 body.removeAt procedureName?(0 arguments?); // call procedure 23 } // if sleep_ms procedureName?(150 arguments?); // call procedure 24 } // while print procedureName?(String.format("Game Over! Score: %", body.length() - 1)arguments?);25 } // main
  }

### What you need to know about print statements

- The print instruction writes a value to display.
- It automatically prints a new line after the value.
- The value can be any expression.
- You must provide a value; if you just want to print a blank line, just set the value to `""""""""""`.
- The recommended way to print multiple values is to use an interpolated string (see third example above)

### More advanced techniques

As an alternative to using the print instruction you call one of these standard library procedures Using the call procedure instruction:

- printNoLine
- printWithTab

which offer more flexible options. These library methods work when running any of the supported languages within Elan but, unlike when using the normal the print instruction, the library procedures do not correspond directly to print methods in the native libraries for those languages.

### See also

Interpolated string

printNoLine

printTab

## Variable definition

### Examples of variable definitions

From the Burrow demo, where variables named `xxxxx` and `yyyyy` represent the current coordinates for the burrowing 'animal':

variable x name? set to 20 value or expression?0
x name? = 20 value or expression? # variable definition 0
var x name? = 20 value or expression?;0
Dim x name? = 20 value or expression? ' variable definition 0
var x name? = 20 value or expression?;0
variable y name? set to 15 value or expression?0
y name? = 15 value or expression? # variable definition 0
var y name? = 15 value or expression?;0
Dim y name? = 15 value or expression? ' variable definition 0
var y name? = 15 value or expression?;0

and the values of these variables are used in multiple places within the program, for example here:

reassign blocks[x][y]variableName? to red value or expression?0
blocks[x][y]variableName? = red value or expression? # reassign variable 0
blocks[x][y]variableName? = red value or expression?; // reassign variable 0
blocks[x][y]variableName? = red value or expression? ' reassign variable 0
blocks[x][y]variableName? = red value or expression?; // reassign variable 0

From the Life - procedural demo where a variable is initialised using an expression, in this case a function call:

variable grid name? set to createBlockGraphics(white)value or expression?0
grid name? = createBlockGraphics(white)value or expression? # variable definition 0
var grid name? = createBlockGraphics(white)value or expression?;0
Dim grid name? = createBlockGraphics(white)value or expression? ' variable definition 0
var grid name? = createBlockGraphics(white)value or expression?;0

Example from the Ripple Sort demo where a variable being initialised using a literal llist of integers:

variable li name? set to [7, 1, 0, 4, 8, 3, 6]value or expression?0
li name? = [7, 1, 0, 4, 8, 3, 6]value or expression? # variable definition 0
var li name? = [7, 1, 0, 4, 8, 3, 6]value or expression?;0
Dim li name? = {7, 1, 0, 4, 8, 3, 6}value or expression? ' variable definition 0
var li name? = [7, 1, 0, 4, 8, 3, 6]value or expression?;0

### What you need to know about variable definitions

- A variable is a named value, were the value may be changed during the course of running the program.
- The variable definition instruction allows you to define a new variable.
- The instructions require a name (e.g. `xxxxx`) and an initial value.
- The initial value may be specified using a literal value (such as `2020202020`, or `"apple""apple""apple""apple""apple"`) or by an expression.
- The type of the initial value determines the type of the variable, so if/when the variable is later changed to a new value, that new value must be of that same type./li>
- Variables may only be defined within a method (the main routine, a procedure, or function).
- Elan does not permit 'global variables' to be defined - even though, outside Elan, that would be allowed by all the languages - because it is considered a bad practice.

## Reassign variable

### Examples of variable reassignment

From the Ripple sort demo, where the `hasChangedhasChangedhasChangedhasChangedhasChanged` variable, having been defined higher up, is reassigned to `falseFalsefalseFalsefalse` at the start of the while loop, and then to `trueTruetrueTruetrue` if two values are swapped:

+procedure inPlaceRippleSort name?(li as List<of Int>parameter definitions?) 1 variable hasChanged name? set to true value or expression?2 variable lastComp name? set to li.length() - 2 value or expression?3 +while hasChanged is true condition? 4 reassign hasChanged variableName? to false value or expression?5 +for i item? in range(0, lastComp + 1)source? 6 +if li[i] > li[i + 1]condition? then 7 variable temp name? set to li[i]value or expression?8 reassign li[i]variableName? to li[i + 1]value or expression?9 reassign li[i + 1]variableName? to temp value or expression?10 reassign hasChanged variableName? to true value or expression?11 end if end for reassign lastComp variableName? to lastComp - 1 value or expression?12 end while end procedure
+def inPlaceRippleSort name?(li: list[int]parameter definitions?) -> None: # procedure 1 hasChanged name? = True value or expression? # variable definition 2 lastComp name? = li.length() - 2 value or expression? # variable definition 3 +while hasChanged == True condition?: 4 hasChanged variableName? = False value or expression? # reassign variable 5 +for i item? in range(0, lastComp + 1)source?: 6 +if li[i] > li[i + 1]condition?: 7 temp name? = li[i]value or expression? # variable definition 8 li[i]variableName? = li[i + 1]value or expression? # reassign variable 9 li[i + 1]variableName? = temp value or expression? # reassign variable 10 hasChanged variableName? = True value or expression? # reassign variable 11 lastComp variableName? = lastComp - 1 value or expression? # reassign variable 12
+static void inPlaceRippleSort name?(List<int> li parameter definitions?) { // procedure 1 var hasChanged name? = true value or expression?;2 var lastComp name? = li.length() - 2 value or expression?;3 +while (hasChanged == true condition?) { 4 hasChanged variableName? = false value or expression?; // reassign variable 5 +foreach (i item? in range(0, lastComp + 1)source?) { 6 +if (li[i] > li[i + 1]condition?) { 7 var temp name? = li[i]value or expression?;8 li[i]variableName? = li[i + 1]value or expression?; // reassign variable 9 li[i + 1]variableName? = temp value or expression?; // reassign variable 10 hasChanged variableName? = true value or expression?; // reassign variable 11 } // if } // foreach lastComp variableName? = lastComp - 1 value or expression?; // reassign variable 12 } // while } // procedure
+Sub inPlaceRippleSort name?(li As List(Of Integer)parameter definitions?) ' procedure 1 Dim hasChanged name? = True value or expression? ' variable definition 2 Dim lastComp name? = li.length() - 2 value or expression? ' variable definition 3 +While hasChanged = True condition? 4 hasChanged variableName? = False value or expression? ' reassign variable 5 +For Each i item? In range(0, lastComp + 1)source? 6 +If li[i] > li[i + 1]condition? Then 7 Dim temp name? = li[i]value or expression? ' variable definition 8 li[i]variableName? = li[i + 1]value or expression? ' reassign variable 9 li[i + 1]variableName? = temp value or expression? ' reassign variable 10 hasChanged variableName? = True value or expression? ' reassign variable 11 End If Next i lastComp variableName? = lastComp - 1 value or expression? ' reassign variable 12 End While End Sub
public class Global {
+static void inPlaceRippleSort name?(List<int> li parameter definitions?) { // procedure 1 var hasChanged name? = true value or expression?;2 var lastComp name? = li.length() - 2 value or expression?;3 +while (hasChanged == true condition?) { 4 hasChanged variableName? = false value or expression?; // reassign variable 5 +foreach (i item? in range(0, lastComp + 1)source?) { 6 +if (li[i] > li[i + 1]condition?) { 7 var temp name? = li[i]value or expression?;8 li[i]variableName? = li[i + 1]value or expression?; // reassign variable 9 li[i + 1]variableName? = temp value or expression?; // reassign variable 10 hasChanged variableName? = true value or expression?; // reassign variable 11 } // if } // foreach lastComp variableName? = lastComp - 1 value or expression?; // reassign variable 12 } // while } // procedure
}

From the Snake -procedural demo, where the variable `currentDefcurrentDefcurrentDefcurrentDefcurrentDef` is reassigned to a new value by calling the function directionByKey, which is passed a keypress that has been read from the keyboard using the getKey system method:

+procedure updateSnake name?(currentDirRef as AsRef<of Direction>, tailRef as AsRef<of List<of Int>>, headRef as AsRef<of List<of Int>>, body as List<of List<of Int>>parameter definitions?) 1 variable head name? set to headRef.value()value or expression?2 variable tail name? set to tailRef.value()value or expression?3 variable currentDir name? set to currentDirRef.value()value or expression?4 reassign currentDir variableName? to directionByKey(currentDir, getKey())value or expression?5 call tailRef.set procedureName?(body[0]arguments?)6 call body.append procedureName?(head arguments?)7 call headRef.set procedureName?(getAdjacentSquare(head, currentDir)arguments?)8 call currentDirRef.set procedureName?(currentDir arguments?)9 end procedure
+def updateSnake name?(currentDirRef: AsRef[Direction], tailRef: AsRef[list[int]], headRef: AsRef[list[int]], body: list[list[int]]parameter definitions?) -> None: # procedure 1 head name? = headRef.value()value or expression? # variable definition 2 tail name? = tailRef.value()value or expression? # variable definition 3 currentDir name? = currentDirRef.value()value or expression? # variable definition 4 currentDir variableName? = directionByKey(currentDir, getKey())value or expression? # reassign variable 5 tailRef.set procedureName?(body[0]arguments?) # call procedure 6 body.append procedureName?(head arguments?) # call procedure 7 headRef.set procedureName?(getAdjacentSquare(head, currentDir)arguments?) # call procedure 8 currentDirRef.set procedureName?(currentDir arguments?) # call procedure 9
+static void updateSnake name?(AsRef<Direction> currentDirRef, AsRef<List<int>> tailRef, AsRef<List<int>> headRef, List<List<int>> body parameter definitions?) { // procedure 1 var head name? = headRef.value()value or expression?;2 var tail name? = tailRef.value()value or expression?;3 var currentDir name? = currentDirRef.value()value or expression?;4 currentDir variableName? = directionByKey(currentDir, getKey())value or expression?; // reassign variable 5 tailRef.set procedureName?(body[0]arguments?); // call procedure 6 body.append procedureName?(head arguments?); // call procedure 7 headRef.set procedureName?(getAdjacentSquare(head, currentDir)arguments?); // call procedure 8 currentDirRef.set procedureName?(currentDir arguments?); // call procedure 9 } // procedure
+Sub updateSnake name?(currentDirRef As AsRef(Of Direction), tailRef As AsRef(Of List(Of Integer)), headRef As AsRef(Of List(Of Integer)), body As List(Of List(Of Integer))parameter definitions?) ' procedure 1 Dim head name? = headRef.value()value or expression? ' variable definition 2 Dim tail name? = tailRef.value()value or expression? ' variable definition 3 Dim currentDir name? = currentDirRef.value()value or expression? ' variable definition 4 currentDir variableName? = directionByKey(currentDir, getKey())value or expression? ' reassign variable 5 tailRef.set procedureName?(body[0]arguments?) ' call procedure 6 body.append procedureName?(head arguments?) ' call procedure 7 headRef.set procedureName?(getAdjacentSquare(head, currentDir)arguments?) ' call procedure 8 currentDirRef.set procedureName?(currentDir arguments?) ' call procedure 9 End Sub
public class Global {
+static void updateSnake name?(AsRef<Direction> currentDirRef, AsRef<List<int>> tailRef, AsRef<List<int>> headRef, List<List<int>> body parameter definitions?) { // procedure 1 var head name? = headRef.value()value or expression?;2 var tail name? = tailRef.value()value or expression?;3 var currentDir name? = currentDirRef.value()value or expression?;4 currentDir variableName? = directionByKey(currentDir, getKey())value or expression?; // reassign variable 5 tailRef.set procedureName?(body[0]arguments?); // call procedure 6 body.append procedureName?(head arguments?); // call procedure 7 headRef.set procedureName?(getAdjacentSquare(head, currentDir)arguments?); // call procedure 8 currentDirRef.set procedureName?(currentDir arguments?); // call procedure 9 } // procedure
}

### What you need to know about reassigning a variable

- The reassign variable instruction assigns a new value to a variable that has been defined earlier within the method.
- The new value to be assigned may be defined as a literal value, or as the result of evaluating an expression.
- The new value must be of the same type as the one that the variable was defined with.

## Input

#### Example of input instructions

From the Binary Search demo, showing an input instruction with a clear user-prompt:

input wanted name? set to inputString("What type of fruit do you want ('x' to exit)? "prompt message?)0
wanted name? = input("What type of fruit do you want ('x' to exit)? "prompt message?) # input 0
Console.WriteLine("What type of fruit do you want ('x' to exit)? "prompt message?);
var wanted name? = Console.ReadLine(); // input 0
Console.WriteLine("What type of fruit do you want ('x' to exit)? "prompt message?)
Dim wanted name? = Console.ReadLine() ' input 0
var wanted name? = Console.ReadLine("What type of fruit do you want ('x' to exit)? "prompt message?); // input 0

### What you need to know about input instructions

- The input instruction is the simplest way to read a string value typed in by the user (followed by Enter.
- You must specify a user-prompt string, though this may be an empty string - `""""""""""`.
- When working in Elan, the user entry will always be on the line below the displayed prompt.
- The entered value is put into a new variable - equivalent to if it was a variable definition.
- If you want to assign the input to an existing variable you can do this by adding a reassign variable instruction on the next line.
- Also in a separate instruction, you can parse the string into a numeric type by applying the `int()int()int()int()int()` or `float()float()float()float()float()` function to the input variable.
- See below for more advanced options for handling specific forms of user input.

### More advanced techniques

#### System methods for keyboard input

As an alternative to using the input instruction you may also use a range of system methods from the standard Elan library, which offer several advantages, including:

- Enforcing that a user input matches the requirement for an integer, or floating-point number, and then doing the conversion invisibly:
- Enforcing that either form of numeric input is within specified numeric bounds.
- Enforcing that a string input is within specified bounds for the number of characters.
- Enforcing that a string input matches one of a list of valid string responses.

In all these cases, if the user input does not match the specified rules, the user will be advised, and asked to input a value response.

See

Keyboard input for the full list of relevant system method.

## If statement

### Examples of if statements

From the Life - procedural demo, where the `resultresultresultresultresult` is changed from black to white if a given random value (expected to be in the range 0 to 1) is greater than 0.5:

+function blackOrWhite name?(random as Float parameter definitions?) returns Int Type? 1 variable result name? set to black value or expression?2 +if random > 0.5 condition? then 3 reassign result variableName? to white value or expression?4 end if return result value or expression?5 end function
+def blackOrWhite name?(random: float parameter definitions?) -> int Type?: # function 1 result name? = black value or expression? # variable definition 2 +if random > 0.5 condition?: 3 result variableName? = white value or expression? # reassign variable 4 return result value or expression?5
+static int Type? blackOrWhite name?(double random parameter definitions?) { // function 1 var result name? = black value or expression?;2 +if (random > 0.5 condition?) { 3 result variableName? = white value or expression?; // reassign variable 4 } // if return result value or expression?;5 } // function
+Function blackOrWhite name?(random As Double parameter definitions?) As Integer Type? 1 Dim result name? = black value or expression? ' variable definition 2 +If random > 0.5 condition? Then 3 result variableName? = white value or expression? ' reassign variable 4 End If Return result value or expression?5 End Function
public class Global {
+static int Type? blackOrWhite name?(double random parameter definitions?) { // function 1 var result name? = black value or expression?;2 +if (random > 0.5 condition?) { 3 result variableName? = white value or expression?; // reassign variable 4 } // if return result value or expression?;5 } // function
}

From the Bubbles demo where the if statement includes an else clause, so that one of two separate blocks of statements is always executed depending on the value of a randomly-generated number.

+if random() < 0.05 condition? then 0 # 5% chance bubble 'bursts' and starts again tiny at bottom comment? call b.setRadius procedureName?(0 arguments?)1 call b.setCentreY procedureName?(75 arguments?)2 else 3 # bubble rises and grows slightly comment? call b.setCentreY procedureName?(b.centreY - 1 arguments?)4 call b.setRadius procedureName?(b.radius + 0.2 arguments?)5 end if
+if random() < 0.05 condition?: 0 # 5% chance bubble 'bursts' and starts again tiny at bottom comment? b.setRadius procedureName?(0 arguments?) # call procedure 1 b.setCentreY procedureName?(75 arguments?) # call procedure 2 else:3 # bubble rises and grows slightly comment? b.setCentreY procedureName?(b.centreY - 1 arguments?) # call procedure 4 b.setRadius procedureName?(b.radius + 0.2 arguments?) # call procedure 5
+if (random() < 0.05 condition?) { 0 // 5% chance bubble 'bursts' and starts again tiny at bottom comment? b.setRadius procedureName?(0 arguments?); // call procedure 1 b.setCentreY procedureName?(75 arguments?); // call procedure 2 } else {3 // bubble rises and grows slightly comment? b.setCentreY procedureName?(b.centreY - 1 arguments?); // call procedure 4 b.setRadius procedureName?(b.radius + 0.2 arguments?); // call procedure 5 } // if
+If random() < 0.05 condition? Then 0 ' 5% chance bubble 'bursts' and starts again tiny at bottom comment? b.setRadius procedureName?(0 arguments?) ' call procedure 1 b.setCentreY procedureName?(75 arguments?) ' call procedure 2 Else 3 ' bubble rises and grows slightly comment? b.setCentreY procedureName?(b.centreY - 1 arguments?) ' call procedure 4 b.setRadius procedureName?(b.radius + 0.2 arguments?) ' call procedure 5 End If
+if (random() < 0.05 condition?) { 0 // 5% chance bubble 'bursts' and starts again tiny at bottom comment? b.setRadius procedureName?(0 arguments?); // call procedure 1 b.setCentreY procedureName?(75 arguments?); // call procedure 2 } else {3 // bubble rises and grows slightly comment? b.setCentreY procedureName?(b.centreY - 1 arguments?); // call procedure 4 b.setRadius procedureName?(b.radius + 0.2 arguments?); // call procedure 5 } // if

From the Burrow demo, where the if includes multiple else if (shortened to 'elif' in some languages) clauses, such that depending on the value of the `directiondirectiondirectiondirectiondirection` variable, one of four different statements is executed:

+if direction is 0 condition? then 0 reassign x variableName? to min([x + 1, 39])value or expression?1 elif direction is 1 condition? then 2 reassign x variableName? to max([x - 1, 0])value or expression?3 elif direction is 2 condition? then 4 reassign y variableName? to min([y + 1, 29])value or expression?5 elif direction is 3 condition? then 6 reassign y variableName? to max([y - 1, 0])value or expression?7 end if
+if direction == 0 condition?: 0 x variableName? = min([x + 1, 39])value or expression? # reassign variable 1 elif direction == 1 condition?: # else if 2 x variableName? = max([x - 1, 0])value or expression? # reassign variable 3 elif direction == 2 condition?: # else if 4 y variableName? = min([y + 1, 29])value or expression? # reassign variable 5 elif direction == 3 condition?: # else if 6 y variableName? = max([y - 1, 0])value or expression? # reassign variable 7
+if (direction == 0 condition?) { 0 x variableName? = min([x + 1, 39])value or expression?; // reassign variable 1 } else if (direction == 1 condition?) {2 x variableName? = max([x - 1, 0])value or expression?; // reassign variable 3 } else if (direction == 2 condition?) {4 y variableName? = min([y + 1, 29])value or expression?; // reassign variable 5 } else if (direction == 3 condition?) {6 y variableName? = max([y - 1, 0])value or expression?; // reassign variable 7 } // if
+If direction = 0 condition? Then 0 x variableName? = min({x + 1, 39})value or expression? ' reassign variable 1 ElseIf direction = 1 condition? Then 2 x variableName? = max({x - 1, 0})value or expression? ' reassign variable 3 ElseIf direction = 2 condition? Then 4 y variableName? = min({y + 1, 29})value or expression? ' reassign variable 5 ElseIf direction = 3 condition? Then 6 y variableName? = max({y - 1, 0})value or expression? ' reassign variable 7 End If
+if (direction == 0 condition?) { 0 x variableName? = min([x + 1, 39])value or expression?; // reassign variable 1 } else if (direction == 1 condition?) {2 x variableName? = max([x - 1, 0])value or expression?; // reassign variable 3 } else if (direction == 2 condition?) {4 y variableName? = min([y + 1, 29])value or expression?; // reassign variable 5 } else if (direction == 3 condition?) {6 y variableName? = max([y - 1, 0])value or expression?; // reassign variable 7 } // if

(Note: the last else if clause could have been written as an else clause, but writing it as an else if makes the intention clearer to a human reader).

### What you need to know about an if statement

- The if instruction specifies which of several blocks of instructions is to be executed next.
- It requires a condition to be specified, which must evaluate to a Boolean value - `trueTruetrueTruetrue` or `falseFalsefalseFalsefalse`.
- That expression might take any of the following forms:

- comparing two values using one of the Boolean operators e.g. `random() < 0.05random() < 0.05random() < 0.05random() < 0.05random() < 0.05` or `direction is 0direction == 0direction == 0direction = 0direction == 0`
- a single existing variable that is of Boolean type
- a function call, or any more complex expression, that evaluates to a Boolean value

- Within the body of an if expression you may add one or more else if clauses and/or a single else clause
- If you specify an else clause it must be the final clause within the if statement body

### See also

if expression. This is an alternative way to implement conditions. Although that is introduced as part of functional programming', you may use it within the procedural profile.

## While loop

### Examples of while loops

From the Ripple Sort demo, where the loop is executed until a pass right through the loop has left the `hasChangedhasChangedhasChangedhasChangedhasChanged` variable as `false (meaning that no more swaps have occurred): Code does not parse as Elan.false (meaning that no more swaps have occurred): Code does not parse as Elan.false (meaning that no more swaps have occurred): Code does not parse as Elan.false (meaning that no more swaps have occurred): Code does not parse as Elan.false (meaning that no more swaps have occurred): Code does not parse as Elan.`

+while hasChanged is true condition? 0 reassign hasChanged variableName? to false value or expression?1 +for i item? in range(0, lastComp + 1)source? 2 +if li[i] > li[i + 1]condition? then 3 variable temp name? set to li[i]value or expression?4 reassign li[i]variableName? to li[i + 1]value or expression?5 reassign li[i + 1]variableName? to temp value or expression?6 reassign hasChanged variableName? to true value or expression?7 end if end for reassign lastComp variableName? to lastComp - 1 value or expression?8 end while
+while hasChanged == True condition?: 0 hasChanged variableName? = False value or expression? # reassign variable 1 +for i item? in range(0, lastComp + 1)source?: 2 +if li[i] > li[i + 1]condition?: 3 temp name? = li[i]value or expression? # variable definition 4 li[i]variableName? = li[i + 1]value or expression? # reassign variable 5 li[i + 1]variableName? = temp value or expression? # reassign variable 6 hasChanged variableName? = True value or expression? # reassign variable 7 lastComp variableName? = lastComp - 1 value or expression? # reassign variable 8
+while (hasChanged == true condition?) { 0 hasChanged variableName? = false value or expression?; // reassign variable 1 +foreach (i item? in range(0, lastComp + 1)source?) { 2 +if (li[i] > li[i + 1]condition?) { 3 var temp name? = li[i]value or expression?;4 li[i]variableName? = li[i + 1]value or expression?; // reassign variable 5 li[i + 1]variableName? = temp value or expression?; // reassign variable 6 hasChanged variableName? = true value or expression?; // reassign variable 7 } // if } // foreach lastComp variableName? = lastComp - 1 value or expression?; // reassign variable 8 } // while
+While hasChanged = True condition? 0 hasChanged variableName? = False value or expression? ' reassign variable 1 +For Each i item? In range(0, lastComp + 1)source? 2 +If li[i] > li[i + 1]condition? Then 3 Dim temp name? = li[i]value or expression? ' variable definition 4 li[i]variableName? = li[i + 1]value or expression? ' reassign variable 5 li[i + 1]variableName? = temp value or expression? ' reassign variable 6 hasChanged variableName? = True value or expression? ' reassign variable 7 End If Next i lastComp variableName? = lastComp - 1 value or expression? ' reassign variable 8 End While
+while (hasChanged == true condition?) { 0 hasChanged variableName? = false value or expression?; // reassign variable 1 +foreach (i item? in range(0, lastComp + 1)source?) { 2 +if (li[i] > li[i + 1]condition?) { 3 var temp name? = li[i]value or expression?;4 li[i]variableName? = li[i + 1]value or expression?; // reassign variable 5 li[i + 1]variableName? = temp value or expression?; // reassign variable 6 hasChanged variableName? = true value or expression?; // reassign variable 7 } // if } // foreach lastComp variableName? = lastComp - 1 value or expression?; // reassign variable 8 } // while

From the Bubbles demo, where the condition is 'hard-wired' to `trueTruetrueTruetrue`, which means that the loop will executive indefinitely (until you stop the program manually with the stop button):

+while true condition? 0 call moveGrowBurst procedureName?(bubbles arguments?)1 end while
+while True condition?: 0 moveGrowBurst procedureName?(bubbles arguments?) # call procedure 1
+while (true condition?) { 0 moveGrowBurst procedureName?(bubbles arguments?); // call procedure 1 } // while
+While True condition? 0 moveGrowBurst procedureName?(bubbles arguments?) ' call procedure 1 End While
+while (true condition?) { 0 moveGrowBurst procedureName?(bubbles arguments?); // call procedure 1 } // while

From the Tower of Hanoi demo, which uses a more complicated expression - to exit the loop only when the third stack has all the discs on it:

+while stacks[2].length() isnt nDiscs condition? 0 +if (stacks[0].length() mod 2) is 0 condition? then 1 call moveBetween procedureName?(stacks, 0, 1 arguments?)2 call moveBetween procedureName?(stacks, 0, 2 arguments?)3 call moveBetween procedureName?(stacks, 1, 2 arguments?)4 else 5 call moveBetween procedureName?(stacks, 0, 2 arguments?)6 call moveBetween procedureName?(stacks, 0, 1 arguments?)7 call moveBetween procedureName?(stacks, 1, 2 arguments?)8 end if end while
+while stacks[2].length() != nDiscs condition?: 0 +if (stacks[0].length() % 2) == 0 condition?: 1 moveBetween procedureName?(stacks, 0, 1 arguments?) # call procedure 2 moveBetween procedureName?(stacks, 0, 2 arguments?) # call procedure 3 moveBetween procedureName?(stacks, 1, 2 arguments?) # call procedure 4 else:5 moveBetween procedureName?(stacks, 0, 2 arguments?) # call procedure 6 moveBetween procedureName?(stacks, 0, 1 arguments?) # call procedure 7 moveBetween procedureName?(stacks, 1, 2 arguments?) # call procedure 8
+while (stacks[2].length() != nDiscs condition?) { 0 +if ((stacks[0].length() % 2) == 0 condition?) { 1 moveBetween procedureName?(stacks, 0, 1 arguments?); // call procedure 2 moveBetween procedureName?(stacks, 0, 2 arguments?); // call procedure 3 moveBetween procedureName?(stacks, 1, 2 arguments?); // call procedure 4 } else {5 moveBetween procedureName?(stacks, 0, 2 arguments?); // call procedure 6 moveBetween procedureName?(stacks, 0, 1 arguments?); // call procedure 7 moveBetween procedureName?(stacks, 1, 2 arguments?); // call procedure 8 } // if } // while
+While stacks[2].length() <> nDiscs condition? 0 +If (stacks[0].length() Mod 2) = 0 condition? Then 1 moveBetween procedureName?(stacks, 0, 1 arguments?) ' call procedure 2 moveBetween procedureName?(stacks, 0, 2 arguments?) ' call procedure 3 moveBetween procedureName?(stacks, 1, 2 arguments?) ' call procedure 4 Else 5 moveBetween procedureName?(stacks, 0, 2 arguments?) ' call procedure 6 moveBetween procedureName?(stacks, 0, 1 arguments?) ' call procedure 7 moveBetween procedureName?(stacks, 1, 2 arguments?) ' call procedure 8 End If End While
+while (stacks[2].length() != nDiscs condition?) { 0 +if ((stacks[0].length() % 2) == 0 condition?) { 1 moveBetween procedureName?(stacks, 0, 1 arguments?); // call procedure 2 moveBetween procedureName?(stacks, 0, 2 arguments?); // call procedure 3 moveBetween procedureName?(stacks, 1, 2 arguments?); // call procedure 4 } else {5 moveBetween procedureName?(stacks, 0, 2 arguments?); // call procedure 6 moveBetween procedureName?(stacks, 0, 1 arguments?); // call procedure 7 moveBetween procedureName?(stacks, 1, 2 arguments?); // call procedure 8 } // if } // while

### What you need to know about a while loop

- The while loop specifies that a block of statements is to be repeated (or 'iterated') for as long as a specified condition is true.
- It should be used when you which to repeat something, but you don't know, in advance, how many times you need it to be repeated.
- As on an if statement, the condition in a while loop may be any expression that evaluates to a Boolean value.
- The condition is evaluated at the beginning of each pass through the loop.
- If the condition makes use of one or more variables (most do) then the variable(s) must be defined before the start of the loop.
- It is possible that the condition could evaluate to false even on the first pass, in which case the instructions within the loop are not executed at all.
- Conversely, if the condition always evaluates to true, then the loop will executive indefintely; this can be deliberate, but may also be an accidental and unwanted behaviour caused by specifying the condition inaccurately.

### See also

- For loop

## For loop

#### Examples of for loops

From the Bubbles demo, where the loop is designed to execute exactly 20 times (the upped bound of the range function being exclusive) to create 20 bubbles of the same size, but of different (randomised) colours, and spread evenly across the bottom of the display:

+for i item? in range(1, 21)source? 0 variable b name? set to (new CircleVG()).withCentreX(i*5 + 2).withCentreY(75).withRadius(0).withFillColour(transparent).withStrokeColour(randint(0, white))value or expression?1 call bubbles.append procedureName?(b arguments?)2 end for
+for i item? in range(1, 21)source?: 0 b name? = (CircleVG()).withCentreX(i*5 + 2).withCentreY(75).withRadius(0).withFillColour(transparent).withStrokeColour(randint(0, white))value or expression? # variable definition 1 bubbles.append procedureName?(b arguments?) # call procedure 2
+foreach (i item? in range(1, 21)source?) { 0 var b name? = (new CircleVG()).withCentreX(i*5 + 2).withCentreY(75).withRadius(0).withFillColour(transparent).withStrokeColour(randint(0, white))value or expression?;1 bubbles.append procedureName?(b arguments?); // call procedure 2 } // foreach
+For Each i item? In range(1, 21)source? 0 Dim b name? = (New CircleVG()).withCentreX(i*5 + 2).withCentreY(75).withRadius(0).withFillColour(transparent).withStrokeColour(randint(0, white))value or expression? ' variable definition 1 bubbles.append procedureName?(b arguments?) ' call procedure 2 Next i
+foreach (i item? in range(1, 21)source?) { 0 var b name? = (new CircleVG()).withCentreX(i*5 + 2).withCentreY(75).withRadius(0).withFillColour(transparent).withStrokeColour(randint(0, white))value or expression?;1 bubbles.append procedureName?(b arguments?); // call procedure 2 } // foreach

From the Turtle Dragon demo, where the number of times to execute the loop is calculated - based on the number of characters in the string variable named `turnsturnsturnsturnsturns`:

+procedure drawDragon name?(t as Turtle, order as Int, turns as String, side as Float, corner as Float parameter definitions?) 1 variable p name? set to (200.0/order).floor()value or expression?2 variable turnI name? set to 0 value or expression?3 +for turn item? in turns source? 4 reassign turnI variableName? to (if(turn.equals(left), 1, -1))value or expression?5 call t.turn procedureName?(-45*turnI arguments?)6 call t.move procedureName?(corner arguments?)7 call t.turn procedureName?(-45*turnI arguments?)8 call t.move procedureName?(side arguments?)9 call sleep_ms procedureName?(p arguments?)10 end for call t.penUp procedureName?(arguments?)11 call t.hide procedureName?(arguments?)12 end procedure
+def drawDragon name?(t: Turtle, order: int, turns: str, side: float, corner: float parameter definitions?) -> None: # procedure 1 p name? = (200.0/order).floor()value or expression? # variable definition 2 turnI name? = 0 value or expression? # variable definition 3 +for turn item? in turns source?: 4 turnI variableName? = (if(turn.equals(left), 1, -1))value or expression? # reassign variable 5 t.turn procedureName?(-45*turnI arguments?) # call procedure 6 t.move procedureName?(corner arguments?) # call procedure 7 t.turn procedureName?(-45*turnI arguments?) # call procedure 8 t.move procedureName?(side arguments?) # call procedure 9 sleep_ms procedureName?(p arguments?) # call procedure 10 t.penUp procedureName?(arguments?) # call procedure 11 t.hide procedureName?(arguments?) # call procedure 12
+static void drawDragon name?(Turtle t, int order, string turns, double side, double corner parameter definitions?) { // procedure 1 var p name? = (200.0/order).floor()value or expression?;2 var turnI name? = 0 value or expression?;3 +foreach (turn item? in turns source?) { 4 turnI variableName? = (if(turn.equals(left), 1, -1))value or expression?; // reassign variable 5 t.turn procedureName?(-45*turnI arguments?); // call procedure 6 t.move procedureName?(corner arguments?); // call procedure 7 t.turn procedureName?(-45*turnI arguments?); // call procedure 8 t.move procedureName?(side arguments?); // call procedure 9 sleep_ms procedureName?(p arguments?); // call procedure 10 } // foreach t.penUp procedureName?(arguments?); // call procedure 11 t.hide procedureName?(arguments?); // call procedure 12 } // procedure
+Sub drawDragon name?(t As Turtle, order As Integer, turns As String, side As Double, corner As Double parameter definitions?) ' procedure 1 Dim p name? = (200.0/order).floor()value or expression? ' variable definition 2 Dim turnI name? = 0 value or expression? ' variable definition 3 +For Each turn item? In turns source? 4 turnI variableName? = (if(turn.equals(left), 1, -1))value or expression? ' reassign variable 5 t.turn procedureName?(-45*turnI arguments?) ' call procedure 6 t.move procedureName?(corner arguments?) ' call procedure 7 t.turn procedureName?(-45*turnI arguments?) ' call procedure 8 t.move procedureName?(side arguments?) ' call procedure 9 sleep_ms procedureName?(p arguments?) ' call procedure 10 Next turn t.penUp procedureName?(arguments?) ' call procedure 11 t.hide procedureName?(arguments?) ' call procedure 12 End Sub
public class Global {
+static void drawDragon name?(Turtle t, int order, String turns, double side, double corner parameter definitions?) { // procedure 1 var p name? = (200.0/order).floor()value or expression?;2 var turnI name? = 0 value or expression?;3 +foreach (turn item? in turns source?) { 4 turnI variableName? = (if(turn.equals(left), 1, -1))value or expression?; // reassign variable 5 t.turn procedureName?(-45*turnI arguments?); // call procedure 6 t.move procedureName?(corner arguments?); // call procedure 7 t.turn procedureName?(-45*turnI arguments?); // call procedure 8 t.move procedureName?(side arguments?); // call procedure 9 sleep_ms procedureName?(p arguments?); // call procedure 10 } // foreach t.penUp procedureName?(arguments?); // call procedure 11 t.hide procedureName?(arguments?); // call procedure 12 } // procedure
}

From the Life - procedural demo, a 'nested' for loop (one inside another) to apply the two inner instructions to each cell in the 40 x 30 grid:

+for x item? in range(0, 40)source? 0 +for y item? in range(0, 30)source? 1 variable colour name? set to nextCellValue(grid, x, y)value or expression?2 reassign nextGen[x][y]variableName? to colour value or expression?3 end for end for
+for x item? in range(0, 40)source?: 0 +for y item? in range(0, 30)source?: 1 colour name? = nextCellValue(grid, x, y)value or expression? # variable definition 2 nextGen[x][y]variableName? = colour value or expression? # reassign variable 3
+foreach (x item? in range(0, 40)source?) { 0 +foreach (y item? in range(0, 30)source?) { 1 var colour name? = nextCellValue(grid, x, y)value or expression?;2 nextGen[x][y]variableName? = colour value or expression?; // reassign variable 3 } // foreach } // foreach
+For Each x item? In range(0, 40)source? 0 +For Each y item? In range(0, 30)source? 1 Dim colour name? = nextCellValue(grid, x, y)value or expression? ' variable definition 2 nextGen[x][y]variableName? = colour value or expression? ' reassign variable 3 Next y Next x
+foreach (x item? in range(0, 40)source?) { 0 +foreach (y item? in range(0, 30)source?) { 1 var colour name? = nextCellValue(grid, x, y)value or expression?;2 nextGen[x][y]variableName? = colour value or expression?; // reassign variable 3 } // foreach } // foreach

### What you need to know about for loops

- The Elan concept of a for loop is equivalent to a 'for each' loop in several languages.
- It should be used when you know (or can work out), in advance, how many times you need it to be repeated.
- The for loop specifies that a block of statements that is repeated, once for each value in a sequence.
- The value is held in a variable - which is defined in the first editable field when you create a new for instruction.
- The second field in the instruction specifies the sequence of values that will be assigned to the variable, successively.
- The sequence of values may be specified:

- as a literal list (of any kind), or a variable of type list
- as a string value, in which case each single character that makes up the string is assigned to the variable in succession
- as any expression that generates a List

- When a sequence of consecutive integer values is needed the most common way to do this is by calling one of these two functions

- range requires two arguments: the lower and upper bound; the upper bound is 'exclusive' so that `range(1, 11)range(1, 11)range(1, 11)range(1, 11)range(1, 11)` creates the sequence 1,2,3,4,5,6,7,8,9,10
- rangeInSteps requires three arguments: lower bound, upper bound (exclusive), and the 'step' or increment value, which can be negative provided that the upper bound is then less than the lower bound.

- The variable is updated each pass around the loop; you should not attempt to modify the variable defined in the loop's signature from within the loop.

### See also

- While loop

## Call procedure

#### Examples of procedure calls

From the Burrow demo: a call to the library procedured named displayBlocks, passing in the data structure held in variable `blocks: Code does not parse as Elan.blocks: Code does not parse as Elan.blocks: Code does not parse as Elan.blocks: Code does not parse as Elan.blocks: Code does not parse as Elan.`

call displayBlocks procedureName?(blocks arguments?)0
displayBlocks procedureName?(blocks arguments?) # call procedure 0
displayBlocks procedureName?(blocks arguments?); // call procedure 0
displayBlocks procedureName?(blocks arguments?) ' call procedure 0
displayBlocks procedureName?(blocks arguments?); // call procedure 0

From the Bubbles demo, a call from within the main routine to the procedure named moveGrowBurst procedure:

call moveGrowBurst procedureName?(bubbles arguments?)0
moveGrowBurst procedureName?(bubbles arguments?) # call procedure 0
moveGrowBurst procedureName?(bubbles arguments?); // call procedure 0
moveGrowBurst procedureName?(bubbles arguments?) ' call procedure 0
moveGrowBurst procedureName?(bubbles arguments?); // call procedure 0
which is defined immmediately below the main routine at the same (global) level.

From the Snake - procedural demo, a procedure that contains a sequence of four calls to other procedures:

+procedure updateSnake name?(currentDirRef as AsRef<of Direction>, tailRef as AsRef<of List<of Int>>, headRef as AsRef<of List<of Int>>, body as List<of List<of Int>>parameter definitions?) 1 variable head name? set to headRef.value()value or expression?2 variable tail name? set to tailRef.value()value or expression?3 variable currentDir name? set to currentDirRef.value()value or expression?4 reassign currentDir variableName? to directionByKey(currentDir, getKey())value or expression?5 call tailRef.set procedureName?(body[0]arguments?)6 call body.append procedureName?(head arguments?)7 call headRef.set procedureName?(getAdjacentSquare(head, currentDir)arguments?)8 call currentDirRef.set procedureName?(currentDir arguments?)9 end procedure
+def updateSnake name?(currentDirRef: AsRef[Direction], tailRef: AsRef[list[int]], headRef: AsRef[list[int]], body: list[list[int]]parameter definitions?) -> None: # procedure 1 head name? = headRef.value()value or expression? # variable definition 2 tail name? = tailRef.value()value or expression? # variable definition 3 currentDir name? = currentDirRef.value()value or expression? # variable definition 4 currentDir variableName? = directionByKey(currentDir, getKey())value or expression? # reassign variable 5 tailRef.set procedureName?(body[0]arguments?) # call procedure 6 body.append procedureName?(head arguments?) # call procedure 7 headRef.set procedureName?(getAdjacentSquare(head, currentDir)arguments?) # call procedure 8 currentDirRef.set procedureName?(currentDir arguments?) # call procedure 9
+static void updateSnake name?(AsRef<Direction> currentDirRef, AsRef<List<int>> tailRef, AsRef<List<int>> headRef, List<List<int>> body parameter definitions?) { // procedure 1 var head name? = headRef.value()value or expression?;2 var tail name? = tailRef.value()value or expression?;3 var currentDir name? = currentDirRef.value()value or expression?;4 currentDir variableName? = directionByKey(currentDir, getKey())value or expression?; // reassign variable 5 tailRef.set procedureName?(body[0]arguments?); // call procedure 6 body.append procedureName?(head arguments?); // call procedure 7 headRef.set procedureName?(getAdjacentSquare(head, currentDir)arguments?); // call procedure 8 currentDirRef.set procedureName?(currentDir arguments?); // call procedure 9 } // procedure
+Sub updateSnake name?(currentDirRef As AsRef(Of Direction), tailRef As AsRef(Of List(Of Integer)), headRef As AsRef(Of List(Of Integer)), body As List(Of List(Of Integer))parameter definitions?) ' procedure 1 Dim head name? = headRef.value()value or expression? ' variable definition 2 Dim tail name? = tailRef.value()value or expression? ' variable definition 3 Dim currentDir name? = currentDirRef.value()value or expression? ' variable definition 4 currentDir variableName? = directionByKey(currentDir, getKey())value or expression? ' reassign variable 5 tailRef.set procedureName?(body[0]arguments?) ' call procedure 6 body.append procedureName?(head arguments?) ' call procedure 7 headRef.set procedureName?(getAdjacentSquare(head, currentDir)arguments?) ' call procedure 8 currentDirRef.set procedureName?(currentDir arguments?) ' call procedure 9 End Sub
public class Global {
+static void updateSnake name?(AsRef<Direction> currentDirRef, AsRef<List<int>> tailRef, AsRef<List<int>> headRef, List<List<int>> body parameter definitions?) { // procedure 1 var head name? = headRef.value()value or expression?;2 var tail name? = tailRef.value()value or expression?;3 var currentDir name? = currentDirRef.value()value or expression?;4 currentDir variableName? = directionByKey(currentDir, getKey())value or expression?; // reassign variable 5 tailRef.set procedureName?(body[0]arguments?); // call procedure 6 body.append procedureName?(head arguments?); // call procedure 7 headRef.set procedureName?(getAdjacentSquare(head, currentDir)arguments?); // call procedure 8 currentDirRef.set procedureName?(currentDir arguments?); // call procedure 9 } // procedure
}

Note that in each of those calls, the name of the procedure being called is preceded by an variable name and dot. This is known as 'dot syntax' and is used when the procedure is defined as a procedure method on a specified type. For example, in the call to `body.append(head)body.append(head)body.append(head)body.append(head)body.append(head)`, append is a procedure method on the type `ListlistListListList`, which is the type of the `bodybodybodybodybody` variable.

### What you need to know about procedure calls

- The call procedure instruction is used when you want to run a procedure .

The arguments provided must match the number and type of the parameters specified in the definition of the procedure; if there are no parameters, leave the brackets empty.

Procedures may have side effects, for example input/output or changing a data value in an object. For this reason, procedures cannot be called from functions, which are not allowed to have side effects. To enforce this, call procedure instructions are not allowed in functions.

There is a limit to the complexity of a call procedure instruction. Only one dot is allowed in the procedure name field, or two dots if the first word is property. If you need anything more complicated, use a change variable instruction on the line above. See the error message explanation for 'procedureName' in a call instruction .

### More advanced techniques

TODO: write afresh descriptions of mutating a (mutable) parameter, and, separately passing by Ref.

## Try

#### Examples try statements

From the Date Time demo, where the input may be `"Q""Q""Q""Q""Q"` (to quit), an empty string (to get the current date/time), or may be a numeric value to be converted. The function call `int(reply)int(reply)int(reply)int(reply)int(reply)` attempts to read a string as an integer, but if it is not a valid integer will throw an exception. A try instruction is used to intercept (or 'catch') this exception and just ignore that input:

+main 1 variable reply name? set to ""value or expression?2 +while not reply.upperCase().equals("Q")condition? 3 reassign reply variableName? to input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression?4 +if reply.equals("")condition? then 5 variable now name? set to divAsInt(clock(), 1000)value or expression?6 print(now arguments?)7 print(getDate(now)arguments?)8 else 9 +try 10 variable td name? set to int(reply)value or expression?11 +if td >= 0 condition? then 12 print(getDate(td)arguments?)13 end if catch e variableName? as ElanRuntimeError type e.g. ElanRuntimeError or CustomError?14 end try end if end while end main
+def main() -> None: 1 reply name? = ""value or expression? # variable definition 2 +while not reply.upperCase().equals("Q")condition?: 3 reply variableName? = input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression? # reassign variable 4 +if reply.equals("")condition?: 5 now name? = divAsInt(clock(), 1000)value or expression? # variable definition 6 print(now arguments?)7 print(getDate(now)arguments?)8 else:9 +try: 10 td name? = int(reply)value or expression? # variable definition 11 +if td >= 0 condition?: 12 print(getDate(td)arguments?)13 except ElanRuntimeError type e.g. ElanRuntimeError or CustomError? as e variableName?: # catch 14 main()
+static void main() { 1 var reply name? = ""value or expression?;2 +while (!reply.upperCase().equals("Q")condition?) { 3 reply variableName? = input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression?; // reassign variable 4 +if (reply.equals("")condition?) { 5 var now name? = divAsInt(clock(), 1000)value or expression?;6 Console.WriteLine(now arguments?); // print 7 Console.WriteLine(getDate(now)arguments?); // print 8 } else {9 +try { 10 var td name? = int(reply)value or expression?;11 +if (td >= 0 condition?) { 12 Console.WriteLine(getDate(td)arguments?); // print 13 } // if } catch (ElanRuntimeError type e.g. ElanRuntimeError or CustomError? e variableName?) {14 } // try } // if } // while } // main
+Sub main() 1 Dim reply name? = ""value or expression? ' variable definition 2 +While Not reply.upperCase().equals("Q")condition? 3 reply variableName? = input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression? ' reassign variable 4 +If reply.equals("")condition? Then 5 Dim now name? = divAsInt(clock(), 1000)value or expression? ' variable definition 6 Console.WriteLine(now arguments?) ' print 7 Console.WriteLine(getDate(now)arguments?) ' print 8 Else 9 +Try 10 Dim td name? = int(reply)value or expression? ' variable definition 11 +If td >= 0 condition? Then 12 Console.WriteLine(getDate(td)arguments?) ' print 13 End If Catch e variableName? As ElanRuntimeError type e.g. ElanRuntimeError or CustomError?14 End Try End If End While End Sub
public class Global {
+static void main() { 1 var reply name? = ""value or expression?;2 +while (!reply.upperCase().equals("Q")condition?) { 3 reply variableName? = input("RETURN for time now or Unix time (positive integer) or Q to quit")value or expression?; // reassign variable 4 +if (reply.equals("")condition?) { 5 var now name? = divAsInt(clock(), 1000)value or expression?;6 System.out.println(now arguments?); // print 7 System.out.println(getDate(now)arguments?); // print 8 } else {9 +try { 10 var td name? = int(reply)value or expression?;11 +if (td >= 0 condition?) { 12 System.out.println(getDate(td)arguments?); // print 13 } // if } catch (ElanRuntimeError type e.g. ElanRuntimeError or CustomError? e variableName?) {14 } // try } // if } // while } // main
}

### What you need to know about try instructions

- The try instruction is a mechanism to execute code that might result in an 'exception' (called an 'error' in some languages), and to catch that exception without the program being automatically halted.
- The try instruction is often referred to as a `try-catch` - because it makes no sense to have a try statement without a 'catch' clause.
- When you add a try instruction in Elan, the 'catch' clause is automatically included in the instruction frame (template).
- 'except' is Python's word for 'catch'
- When you add a new try the instructions that you want to try to execute are specified immediately underneath the first line.
- Underneath the catch clause you may instructions to handle the exception, for example by advising the user to try again.
- The catch clause must specify the type of the exception to be caught. When working in Elan, only two types are permitted:

- `ElanRuntimeErrorElanRuntimeErrorElanRuntimeErrorElanRuntimeErrorElanRuntimeError` which covers all errors thrown by the Elan system, including, for example 'Out of range index ...'
- `CustomErrorCustomErrorCustomErrorCustomErrorCustomError` an exception explicitly thrown by code by a throw instruction in your own code (see below).

- Currently Elan permits only one catch clause to be associated with each try

You can enclose code in a try construction when you want it to be able, at execution, to throw an exception that you handle.

This might arise when calling a System method  that is dependent upon external conditions, such as when cancelling the writing of a text file, as in the example in Writing text files .

The try construction automatically provides a catch clause in which you provide a String for an message.

You can also use a test to check whether another piece of code might throw an exception by wrapping it in a try instruction.

## Throw

You can deliberately generate, or 'throw', an error exception when a specific circumstance is identified, using a throw instruction which defines an explanatory string.

For the program to retain control when an exception is raised, use the try  instruction.

#### Example of a throwing an exception

The following function to calculate factorials deliberately 'throws' an exception (error) if it is given a negative value for the argument:

+function factorial name?(n as Int parameter definitions?) returns Int Type? 1 variable result name? set to 1 value or expression?2 +if n > 1 condition? then 3 reassign result variableName? to n*factorial(n - 1)value or expression?4 elif n < 0 condition? then 5 throw CustomError exception type? "Factorial cannot be called with a negative argument"message?6 end if return result value or expression?7 end function
+def factorial name?(n: int parameter definitions?) -> int Type?: # function 1 result name? = 1 value or expression? # variable definition 2 +if n > 1 condition?: 3 result variableName? = n*factorial(n - 1)value or expression? # reassign variable 4 elif n < 0 condition?: # else if 5 raise CustomError exception type?("Factorial cannot be called with a negative argument"message?)6 return result value or expression?7
+static int Type? factorial name?(int n parameter definitions?) { // function 1 var result name? = 1 value or expression?;2 +if (n > 1 condition?) { 3 result variableName? = n*factorial(n - 1)value or expression?; // reassign variable 4 } else if (n < 0 condition?) {5 throw new CustomError exception type?("Factorial cannot be called with a negative argument"message?);6 } // if return result value or expression?;7 } // function
+Function factorial name?(n As Integer parameter definitions?) As Integer Type? 1 Dim result name? = 1 value or expression? ' variable definition 2 +If n > 1 condition? Then 3 result variableName? = n*factorial(n - 1)value or expression? ' reassign variable 4 ElseIf n < 0 condition? Then 5 Throw New CustomError exception type?("Factorial cannot be called with a negative argument"message?)6 End If Return result value or expression?7 End Function
public class Global {
+static int Type? factorial name?(int n parameter definitions?) { // function 1 var result name? = 1 value or expression?;2 +if (n > 1 condition?) { 3 result variableName? = n*factorial(n - 1)value or expression?; // reassign variable 4 } else if (n < 0 condition?) {5 throw new CustomError exception type?("Factorial cannot be called with a negative argument"message?);6 } // if return result value or expression?;7 } // function
}

#### What you need to know about throwing an exception

- The throw instruction will cause an 'exception' to be 'thrown' (or 'raised' in some languages).
- Unless the throw instruction is directly or indirectly within a Try instruction (see above), program execution will be halted and the message defined in the throw instruction printed on the display.
- Because of this drastic effect it is recommended not to throw exceptions only in rare circumstances.

## Assert

#### Examples of asserts

From the Date Time demo, showing asserts for normal and edge cases

new code
new code
new code
new code
public class Global {
new code
}
test test_leap # normal cases assert leap(2025) is false assert leap(2024) is true # boundary cases assert leap(1900) is false assert leap(2000) is true end test

From the Tower of Hanoi

demo, showing an assert for an error case:
new code
new code
new code
new code
public class Global {
new code
}

From the Tower of Hanoi

demo, showing an assert for an error case:
+test test_colour test_name? 1 # Normal cases comment? assert colour(5)actual (computed) value? is green expected value? not run 2 # Edge cases comment? assert colour(1)actual (computed) value? is red expected value? not run 3 assert colour(10)actual (computed) value? is 0xFF99CC expected value? not run 4 # Error cases comment? assert colour(11)actual (computed) value? is "Out of range index: 10 size: 10"expected value? not run 5 end test
+def test_colour test_name?(self) -> None: 1 # Normal cases comment? self.assertEqual(colour(5)actual (computed) value?, green expected value?) not run 2 # Edge cases comment? self.assertEqual(colour(1)actual (computed) value?, red expected value?) not run 3 self.assertEqual(colour(10)actual (computed) value?, 0xFF99CC expected value?) not run 4 # Error cases comment? self.assertEqual(colour(11)actual (computed) value?, "Out of range index: 10 size: 10"expected value?) not run 5
+[TestMethod] static void test_colour test_name?() { 1 // Normal cases comment? Assert.AreEqual(green expected value?, colour(5)actual (computed) value?); not run 2 // Edge cases comment? Assert.AreEqual(red expected value?, colour(1)actual (computed) value?); not run 3 Assert.AreEqual(0xFF99CC expected value?, colour(10)actual (computed) value?); not run 4 // Error cases comment? Assert.AreEqual("Out of range index: 10 size: 10"expected value?, colour(11)actual (computed) value?); not run 5 } // test
+<TestMethod> Sub test_colour test_name?() 1 ' Normal cases comment? Assert.AreEqual(green expected value?, colour(5)actual (computed) value?) not run 2 ' Edge cases comment? Assert.AreEqual(red expected value?, colour(1)actual (computed) value?) not run 3 Assert.AreEqual(&HFF99CC expected value?, colour(10)actual (computed) value?) not run 4 ' Error cases comment? Assert.AreEqual("Out of range index: 10 size: 10"expected value?, colour(11)actual (computed) value?) not run 5 End Sub
public class Global {
+@Test static void test_colour test_name?() { 1 // Normal cases comment? assertEquals(green expected value?, colour(5)actual (computed) value?); not run 2 // Edge cases comment? assertEquals(red expected value?, colour(1)actual (computed) value?); not run 3 assertEquals(0xFF99CC expected value?, colour(10)actual (computed) value?); not run 4 // Error cases comment? assertEquals("Out of range index: 10 size: 10"expected value?, colour(11)actual (computed) value?); not run 5 } // test
}

#### What you need to know about asserts

- An assert instruction is used to test an individual case within a test, or sometimes to test individual result values in a single case that returns a data structure.
- The assert defines two fields that the user must specify:

- The actual value as returned by a call to the function being tested.
- The expected value, which will typically be a literal value of the same type as the actual.
- When the tests are run (automatically whenever the code compiles) the result - pass or fail - will be shown alongside each assert.
- A fail indicates that the expected and actual values do not match.
- The expected value should be of the same type as the actual; if they are not that will be reported as a test failure, without showing the actual values.
- You can, however, test for an exception having been thrown, by setting the expected value to a the expected error message (as a string).
- Unlike on many systems, Elan does not stop at the first failure within each test - it will attempt to evaluate all the asserts.
- The required order of the actual and expected fields varies between the supported languages; Elan handles this automatically when translating between languages.

## Comment

See Comments

# Expressions

One of the most important constructs in programming is the expression. An expression evaluates and returns a value using the following elements:

- Literal value 
- Named value 
- Operator  (including round brackets)
- function reference 
- lambda 

## Literal value

A literal value is where a value is written 'literally' in the code, such as `3.1423.1423.1423.1423.142`, in contrast to a value that is referred to by a name.

Here is a table showing some example literal values. Follow the links for more information about each Type.

Type | Example of literal
--- | ---
Int  | `33333`
Float  | `2.02.02.02.02.0`
Boolean  | true
String  | `"Hello""Hello""Hello""Hello""Hello"`
Tuple  | `(3, "banana")(3, "banana")(3, "banana")(3, "banana")(3, "banana")`
List  | `["lemon", "lime", "orange"]["lemon", "lime", "orange"]["lemon", "lime", "orange"]{"lemon", "lime", "orange"}["lemon", "lime", "orange"]`
Dictionary  | `["a":3, "b":5]["a":3, "b":5]["a":3, "b":5]["a":3, "b":5]["a":3, "b":5]`

For more about List and Dictionary literals see the Standard data structures  table.

## Indexed values

If a named value is of an indexable type (`StringstrstringStringString` or `ListlistListListList`), then you can refer to a contiguous subset (or range) of its values using methods subString and subList respectively.

The upper index of a range is exclusive, so to define a range that picks items indexed from i to j, you would specify the range as `(i, j + 1)(i, j + 1)(i, j + 1)(i, j + 1)(i, j + 1)`.

If the two index values of a range are equal, or the second is smaller than the first, then an empty string or list is returned.

Indexes are used only for reading values. Writing a value to a specific index location in a list is done using method put .

Example using indexing on a string:

+main 1 variable a name? set to "Hello world!"value or expression?2 call print procedureName?(a[4]arguments?)3 call print procedureName?(a.subString(4, a.length())arguments?)4 call print procedureName?(a.subString(0, 7)arguments?)5 end main +def main() -> None: 1 a name? = "Hello world!"value or expression? # variable definition 2 print procedureName?(a[4]arguments?)3 print procedureName?(a.subString(4, a.length())arguments?)4 print procedureName?(a.subString(0, 7)arguments?)5 main() +static void main() { 1 var a name? = "Hello world!"value or expression?;2 print procedureName?(a[4]arguments?);3 print procedureName?(a.subString(4, a.length())arguments?);4 print procedureName?(a.subString(0, 7)arguments?);5 } // main +Sub main() 1 Dim a name? = "Hello world!"value or expression? ' variable definition 2 print procedureName?(a[4]arguments?)3 print procedureName?(a.subString(4, a.length())arguments?)4 print procedureName?(a.subString(0, 7)arguments?)5 End Sub public class Global { +static void main() { 1 var a name? = "Hello world!"value or expression?;2 print procedureName?(a[4]arguments?);3 print procedureName?(a.subString(4, a.length())arguments?);4 print procedureName?(a.subString(0, 7)arguments?);5 } // main } | ⟶ ⟶ ⟶ | o o world! Hello w (since the upper bound of a range is exclusive)

And on a list:

+main 1 variable li name? set to new List<of Int>()value or expression?2 reassign li variableName? to [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]value or expression?3 call print procedureName?(li[4]arguments?)4 call print procedureName?(li.subList(4, li.length())arguments?)5 call print procedureName?(li.subList(0, 7)arguments?)6 end main +def main() -> None: 1 li name? = list[int]()value or expression? # variable definition 2 li variableName? = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]value or expression? # reassign variable 3 print procedureName?(li[4]arguments?)4 print procedureName?(li.subList(4, li.length())arguments?)5 print procedureName?(li.subList(0, 7)arguments?)6 main() +static void main() { 1 var li name? = new List<int>()value or expression?;2 li variableName? = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]value or expression?; // reassign variable 3 print procedureName?(li[4]arguments?);4 print procedureName?(li.subList(4, li.length())arguments?);5 print procedureName?(li.subList(0, 7)arguments?);6 } // main +Sub main() 1 Dim li name? = New List(Of Integer)()value or expression? ' variable definition 2 li variableName? = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}value or expression? ' reassign variable 3 print procedureName?(li[4]arguments?)4 print procedureName?(li.subList(4, li.length())arguments?)5 print procedureName?(li.subList(0, 7)arguments?)6 End Sub public class Global { +static void main() { 1 var li name? = new List<int>()value or expression?;2 li variableName? = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]value or expression?; // reassign variable 3 print procedureName?(li[4]arguments?);4 print procedureName?(li.subList(4, li.length())arguments?);5 print procedureName?(li.subList(0, 7)arguments?);6 } // main } | ⟶ ⟶ ⟶ | 4 (the value of the list item) [4, 5, 6, 7, 8, 9, 10, 11] (a new list) [0, 1, 2, 3, 4, 5, 6] (since the upper bound of a range is exclusive)

## Operators

### Arithmetic operators

Arithmetic operators can be applied to `FloatfloatdoubleDoubledouble` or `IntintintIntegerint` arguments. The result may be a `FloatfloatdoubleDoubledouble` or an `IntintintIntegerint` depending on the arguments.

For the + − * operators, the result is a `FloatfloatdoubleDoubledouble` if either of the arguments is a `FloatfloatdoubleDoubledouble`, and an `IntintintIntegerint` if both arguments are `IntintintIntegerint`.

For the / operator, at least one of the values must be a `FloatfloatdoubleDoubledouble`, and the result is always a `FloatfloatdoubleDoubledouble`. It can be converted to an `IntintintIntegerint` using standalone function floor .

For raising one value to the power of another, use the syntax in these examples:

`call printprocedureName?(pow(4, 4)arguments?)0printprocedureName?(pow(4, 4)arguments?)0printprocedureName?(pow(4, 4)arguments?);0printprocedureName?(pow(4, 4)arguments?)0printprocedureName?(pow(4, 4)arguments?);0`
`variable cname? set to sqrt(pow(a, 2) + pow(b, 2))value or expression?0cname? = sqrt(pow(a, 2) + pow(b, 2))value or expression? # variable definition0var cname? = sqrt(pow(a, 2) + pow(b, 2))value or expression?;0Dim cname? = sqrt(pow(a, 2) + pow(b, 2))value or expression? ' variable definition0var cname? = sqrt(pow(a, 2) + pow(b, 2))value or expression?;0`

If, when including a power in an expression, it does not parse, try enclosing parts of the expression in brackets to remove potential ambiguity.

The operator mod (integer remainder) is applied only to `IntintintIntegerint` arguments, and the result is `IntintintIntegerint`.

`2/3.02/3.02/3.02/3.02/3.0` | ⟶ | 0.666..
`2*32*32*32*32*3` | ⟶ | 6
`2 + 32 + 32 + 32 + 32 + 3` | ⟶ | 5
`2 - 32 - 32 - 32 - 32 - 3` | ⟶ | −1
`11 mod 311 % 311 % 311 Mod 311 % 3` | ⟶ | 2

For integer division, either use method floor on a `FloatfloatdoubleDoubledouble` result, or use method divAsInt on `FloatfloatdoubleDoubledouble` arguments (which returns an `IntintintIntegerint`):

`(11.0/3.0).floor()(11.0/3.0).floor()(11.0/3.0).floor()(11.0/3.0).floor()(11.0/3.0).floor()` | ⟶ | 3
`(-11.0/3.0).floor()(-11.0/3.0).floor()(-11.0/3.0).floor()(-11.0/3.0).floor()(-11.0/3.0).floor()` | ⟶ | −4
`divAsInt(11.0, 3.0)divAsInt(11.0, 3.0)divAsInt(11.0, 3.0)divAsInt(11.0, 3.0)divAsInt(11.0, 3.0)` | ⟶ | 3

Note that rounding is always down.

Arithmetic operators follow the conventional rules for precedence i.e. 'BIDMAS' (or 'BODMAS').

When combining mod with other operators in an expression, insert round brackets to avoid ambiguity e.g.:

`(5 + 6) mod 3(5 + 6) % 3(5 + 6) % 3(5 + 6) Mod 3(5 + 6) % 3` | ⟶ | 2

Note that mod is more of a remainder operator than a modulus operator. The result takes the sign of the first argument. If both arguments are positive, there is no difference.

The minus sign may also be used as a unary operator, and this takes precedence over binary operators so:

`2*-32*-32*-32*-32*-3` | ⟶ | −6

The editor automatically puts spaces around the operators + and −, but not around / or *. This is just to visually reinforce the precedence.

### Logical operators

Logical operators are applied to `BooleanboolboolBooleanbool` arguments and return a `BooleanboolboolBooleanbool` result.

`andandandandand` and `ororororor` are binary operators
`notnotnotnotnot` is a unary operator.

The operator precedence is `notnotnotnotnot` → `andandandandand` → `ororororor`, so this example, which implements an 'exclusive or', need not use brackets and can rely on the operator precedence:

+function exOr name?(a as Boolean, b as Boolean parameter definitions?) returns Boolean Type? 1 return a and not b or b and not a value or expression?2 end function
+def exOr name?(a: bool, b: bool parameter definitions?) -> bool Type?: # function 1 return a and not b or b and not a value or expression?2
+static bool Type? exOr name?(bool a, bool b parameter definitions?) { // function 1 return a && !b || b && !a value or expression?;2 } // function
+Function exOr name?(a As Boolean, b As Boolean parameter definitions?) As Boolean Type? 1 Return a And Not b Or b And Not a value or expression?2 End Function
public class Global {
+static bool Type? exOr name?(bool a, bool b parameter definitions?) { // function 1 return a && !b || b && !a value or expression?;2 } // function
}

### String operator

The + operator is also used for concatenating `StringstrstringStringString` values.

### Equality testing

#### Testing equality of `IntintintIntegerint`, `FloatfloatdoubleDoubledouble` or `BooleanboolboolBooleanbool` values

Equality testing of these Value Types uses the is and isnt operators between two values and returns a `BooleanboolboolBooleanbool` result:

- isnt returns the opposite of is.
- `(a is b)(a == b)(a == b)(a = b)(a == b)` returns true, if a and b are both of the same type and their values are equal. The only exception is that if one argument is of type `FloatfloatdoubleDoubledouble` and the other is of type `IntintintIntegerint`, then is will return true (and isnt will return false) if their values are the same, i.e. they are the same whole number.
- It is also possible to use methods equals and notEqualTo described below.

#### Testing equality of `StringstrstringStringString` values and of all Reference Types

Equality testing of these Reference Types uses common dot methods  equals and notEqualTo:

- +if listA.equals(listB)condition? then 0 new code end if
  +if listA.equals(listB)condition?: 0 new code
  +if (listA.equals(listB)condition?) { 0 new code } // if
  +If listA.equals(listB)condition? Then 0 new code End If
  +if (listA.equals(listB)condition?) { 0 new code } // if
- `reassign differsvariableName? to set1.notEqualTo(set2)value or expression?0differsvariableName? = set1.notEqualTo(set2)value or expression? # reassign variable0differsvariableName? = set1.notEqualTo(set2)value or expression?; // reassign variable0differsvariableName? = set1.notEqualTo(set2)value or expression? ' reassign variable0differsvariableName? = set1.notEqualTo(set2)value or expression?; // reassign variable0`

The comparison is made sequentially through the characters or items in the structures to see if the objects are equal. Two Lists compare equal if they contain the same items in the same order. And two instances of the same class compare equal if the values of all their properties compare equal.

The compiler rejects any attempt to compare instances of different classes unless abstract classes and inheritance are involved. Two instances which are subclasses of the same abstract class compare equal only if they are of the same class (and have the same property values).

### Numeric comparison

The numeric comparison operators are:

> | for | greater than
< | for | less than
>= | for | greater than or equal to
<= | for | less than or equal to

Each may be applied between two values of type `FloatfloatdoubleDoubledouble`, but any named value or expression that evaluates to an `IntintintIntegerint` may always be used where a `FloatfloatdoubleDoubledouble` is expected.

These operators cannot be applied to strings. Use the dot methods isBefore and isAfter to compare strings alphabetically. See Dot methods on a String .

### Combining operators

You can combine operators of different kinds, e.g. combining numeric comparison with logical operators in a single expression. However the rules of precedence between operators of different kinds are complex. It is strongly recommend that you always use brackets to disambiguate such expressions, for example:

`reassign xvariableName? to (a > b) and (b < c)value or expression?0xvariableName? = (a > b) and (b < c)value or expression? # reassign variable0xvariableName? = (a > b) && (b < c)value or expression?; // reassign variable0xvariableName? = (a > b) And (b < c)value or expression? ' reassign variable0xvariableName? = (a > b) && (b < c)value or expression?; // reassign variable0`
`reassign xvariableName? to (a + b) > (c - d)value or expression?0xvariableName? = (a + b) > (c - d)value or expression? # reassign variable0xvariableName? = (a + b) > (c - d)value or expression?; // reassign variable0xvariableName? = (a + b) > (c - d)value or expression? ' reassign variable0xvariableName? = (a + b) > (c - d)value or expression?; // reassign variable0`

## Function reference

An expression may simply be a reference to a function, or it may include several function references within it. Examples:
+main 1 call print procedureName?(sin(radians(30))arguments?)2 variable x name? set to pow(sin(radians(30)), 2) + pow(cos(radians(30)), 2)value or expression?3 variable name name? set to input("Your name")value or expression?4 call print procedureName?(name.upperCase()arguments?)5 end main
+def main() -> None: 1 print procedureName?(sin(radians(30))arguments?)2 x name? = pow(sin(radians(30)), 2) + pow(cos(radians(30)), 2)value or expression? # variable definition 3 name name? = input("Your name")value or expression? # variable definition 4 print procedureName?(name.upperCase()arguments?)5 main()
+static void main() { 1 print procedureName?(sin(radians(30))arguments?);2 var x name? = pow(sin(radians(30)), 2) + pow(cos(radians(30)), 2)value or expression?;3 var name name? = input("Your name")value or expression?;4 print procedureName?(name.upperCase()arguments?);5 } // main
+Sub main() 1 print procedureName?(sin(radians(30))arguments?)2 Dim x name? = pow(sin(radians(30)), 2) + pow(cos(radians(30)), 2)value or expression? ' variable definition 3 Dim name name? = input("Your name")value or expression? ' variable definition 4 print procedureName?(name.upperCase()arguments?)5 End Sub
public class Global {
+static void main() { 1 print procedureName?(sin(radians(30))arguments?);2 var x name? = pow(sin(radians(30)), 2) + pow(cos(radians(30)), 2)value or expression?;3 var name name? = input("Your name")value or expression?;4 print procedureName?(name.upperCase()arguments?);5 } // main
}

#### Notes

- The third example above is not strictly a function call, but is a 'system method' call. System methods may be used only within the main routine or a procedure, because they have external dependencies or side effects.
- In the fourth example, `upperCaseupperCaseupperCaseupperCaseupperCase` is a dot method that may be applied to any instance (variable or literal) of type `StringstrstringStringString`. See Dot methods on a String .

## lambda

A lambda is a lightweight means of defining a function 'inline' and without a name (i.e. an anonymous function).

You can use a lambda only as an argument to a Higher-order Function .

You would typically define a lambda when the functionality it defines is needed in only one location, e.g. in a particular call to a Higher-order Function.

The syntax for a lambda is as follows:

- Start with the word lambda.
- Parameter definitions, comma-separated, follow the same form as parameter definitions in a function or procedure, but without surrounding brackets.
- The => symbol, which is usually articulated as 'returns', 'yields' or 'fat arrow'.
- An expression that makes use of the parameters, and may also make use of other variables that are in scope.

For examples of using lambda in Higher-order Functions, see Library functions that process Lists 

## if (expression)

The if expression returns one of two values or expressions dependent upon the evaulation of a Boolean value:

Its syntax is shown in this reassign variable instruction:

`variable isBiggername? set to if(a >= b, true, false)value or expression?0isBiggername? = if(a >= b, True, False)value or expression? # variable definition0var isBiggername? = if(a >= b, true, false)value or expression?;0Dim isBiggername? = if(a >= b, True, False)value or expression? ' variable definition0var isBiggername? = if(a >= b, true, false)value or expression?;0`

Similarly, but returning an evaluated expression:

`variable dname? set to if(c < 580, c - 40, c + 60)value or expression?0dname? = if(c < 580, c - 40, c + 60)value or expression? # variable definition0var dname? = if(c < 580, c - 40, c + 60)value or expression?;0Dim dname? = if(c < 580, c - 40, c + 60)value or expression? ' variable definition0var dname? = if(c < 580, c - 40, c + 60)value or expression?;0`

in which variable d takes the value of `c - 40c - 40c - 40c - 40c - 40` if `c < 580c < 580c < 580c < 580c < 580`, or `c + 60c + 60c + 60c + 60c + 60` otherwise.

An if expression may be used within an if expression but may be hard to read and understand.

#### Examples using if expression:

● Choice in a return instruction:

+function foo name?(parameter definitions parameter definitions?) returns Int Type? 1 return if(isGreen(attempt, target, n), setChar(attempt, n, "*"), attempt)value or expression?2 end function
+def foo name?(parameter definitions parameter definitions?) -> int Type?: # function 1 return if(isGreen(attempt, target, n), setChar(attempt, n, "*"), attempt)value or expression?2
+static int Type? foo name?(parameter definitions parameter definitions?) { // function 1 return if(isGreen(attempt, target, n), setChar(attempt, n, "*"), attempt)value or expression?;2 } // function
+Function foo name?(parameter definitions parameter definitions?) As Integer Type? 1 Return if(isGreen(attempt, target, n), setChar(attempt, n, "*"), attempt)value or expression?2 End Function
public class Global {
+static int Type? foo name?(parameter definitions parameter definitions?) { // function 1 return if(isGreen(attempt, target, n), setChar(attempt, n, "*"), attempt)value or expression?;2 } // function
}

● Using an if expression in a call procedure print:

+main 1 variable p name? set to unicode(0x03c0)value or expression?2 call testPi procedureName?(p, 3 arguments?)3 call testPi procedureName?(p, 4 arguments?)4 end main +procedure testPi name?(p as String, v as Float parameter definitions?) 5 call print procedureName?(if(pi > v, $"{p} > {v}", $"{p} < {v}")arguments?)6 end procedure +def main() -> None: 1 p name? = unicode(0x03c0)value or expression? # variable definition 2 testPi procedureName?(p, 3 arguments?) # call procedure 3 testPi procedureName?(p, 4 arguments?) # call procedure 4 +def testPi name?(p: str, v: float parameter definitions?) -> None: # procedure 5 print procedureName?(if(pi > v, f"{p} > {v}", f"{p} < {v}")arguments?)6 main() +static void main() { 1 var p name? = unicode(0x03c0)value or expression?;2 testPi procedureName?(p, 3 arguments?); // call procedure 3 testPi procedureName?(p, 4 arguments?); // call procedure 4 } // main +static void testPi name?(string p, double v parameter definitions?) { // procedure 5 print procedureName?(if(pi > v, $"{p} > {v}", $"{p} < {v}")arguments?);6 } // procedure +Sub main() 1 Dim p name? = unicode(&H03c0)value or expression? ' variable definition 2 testPi procedureName?(p, 3 arguments?) ' call procedure 3 testPi procedureName?(p, 4 arguments?) ' call procedure 4 End Sub +Sub testPi name?(p As String, v As Double parameter definitions?) ' procedure 5 print procedureName?(if(pi > v, $"{p} > {v}", $"{p} < {v}")arguments?)6 End Sub public class Global { +static void main() { 1 var p name? = unicode(0x03c0)value or expression?;2 testPi procedureName?(p, 3 arguments?); // call procedure 3 testPi procedureName?(p, 4 arguments?); // call procedure 4 } // main +static void testPi name?(String p, double v parameter definitions?) { // procedure 5 print procedureName?(arguments?);6 } // procedure } | ⟶ ⟶ | π > 3 π < 4

## new

A 'new instance' expression is used to create a new instance of a library data structure , or a user-defined class , either to assign to a named value, or as part of a more complex expression. Example of use from demo program snake_PP.elan:

`variable headRefname? set to new AsRef<of List<of Int>>(head)value or expression?0headRefname? = AsRef[list[int]](head)value or expression? # variable definition0var headRefname? = new AsRef<List<int>>(head)value or expression?;0Dim headRefname? = New AsRef(Of List(Of Integer))(head)value or expression? ' variable definition0var headRefname? = new AsRef<List<int>>(head)value or expression?;0`

# Miscellaneous

## Field help

### 'arguments' field in a call instruction

An argument list passed into a function or procedure call, must consist of one or more arguments separated by commas. Each argument may in general be any of:

- A literal value
- A named value
- An expression

In certain very specific contexts, however, some options are disallowed by the compiler.

### 'computed value' field in an assert instruction

The 'actual' field should be kept as simple as possible, preferably just a named value or a function evaluation. Generally, if you want to use a more complex expression, it is better to evaluate it in a preceding variable definition instruction and then use the named value in the 'actual' field of the assert equal instruction. Some more complex expressions are permissible, but these two restrictions apply:

- Any expression involving a binary operator such as +, isnt, etc., must have brackets around it.
- You may not use the is operator within the 'actual' field, because the parser will confuse this with the is keyword that is part of the assert equal instruction.

### 'variable name' field in a set instruction

The first field in a change variable instruction most commonly takes the name of an existing variable.

### 'comment' field

### literal value or data structure in a constant

The value of a constant must be a literal value of a type that is not mutable. This can be a simple value (e.g. a number or string), or an immutable List or Dictionary.

### 'values' field in an enum definition

enum values must each be a valid identifier, separated by commas.

### 'message' field in a throw instruction

An exception message must be either a literal string or a named value holding a string.

### expression field - used within multiple instructions

This field expects an expression. For the various forms of expression see Expressions .

### identifier field - used within multiple instructions

### 'if' field in an else clause

### 'inherits className' field in a class

An inheritance clause, if used, must consist of the keyword inherits followed by a space and then one or more type names separated by commas.

### 'name' field in a function or procedure definition

A method name must follow the rules for an identifier .

### 'parameter definitions' in a function or procedure definition

Each parameter definition takes the form:

name as Type

The name must follow the rules for an identifier .

The type must follow the rules for a Type .

If more than one parameter is defined, the definitions must be separated by commas.

### 'procedureName' in a call statement

Valid forms for a procedure call are

- call procedure procedureName()
- call procedure instanceName.procedureMethodName()
- call procedure property.propertyName.procedureMethodName()
- call procedure library.procedureName()

The last one is used only if there is a need to disambiguate between a library procedure and a user-defined (global) procedure with the same name.

### 'Type' field in a function or property definition

For certain Types the name may be followed by an of clause, for example:

`ListlistListListList`<of `IntintintIntegerint`>
`DictionaryDictionaryDictionaryDictionaryDictionary`<of `StringstrstringStringString`, `IntintintIntegerint`>

### 'Name' field in a class or enum definition

Type names always begin with a capital letter, optionally followed by letters of either case, numeric digits, or underscore symbols. Nothing else.

### 'name' field in a let or variable instruction

The definition for a variable instruction is most commonly a simple name. Less commonly, it may take the form of a deconstruction of a `ListlistListListList`  or Tuple .