Elan Language Reference
Named values
In most programming, the term variable describes a data entity in a program that contains a value and has a name by which you can read and write its value,
i.e. its value can be varied. In Elan, these data entities are called named values so that a distinction can be made between:
- mutable named values whose content can be assigned and reassigned, e.g. defined with a variable definition instruction and reassigned with a change variable instruction or,
for standard data structures, there are methods for their update.
- immutable named values whose content is assigned, e.g. with a constant instruction, or a let instruction in a function, and then cannot be reassigned.
There are, however, methods for copying an immutable named value into another (or even the same) named value with specified changes.
This distinction applies both to single values and to data structures (which contain multiple values) and, while it is most pertinent in Functional Programming,
it provides a useful discipline in any code. Preferring immutable named values can help avoid duplication, assist in the modularisation of code and reduce errors.
Both kinds of named value must be initialised with literals, expressions or initialisation methods. The counter variable in a for loop, however, may be used without having been initialised.
Data Types
There are two fundamentally different kinds of data Type, differing by how their values
are passed around in a running program:
- Value Types that contain a single value, and are passed around directly:
IntintintIntegerint, FloatfloatdoubleDoubledouble, BooleanboolboolBooleanbool
- Reference Types that contain a more complex structure of values, and are passed around by references to them:
StringstrstringStringString, ListlistListListList, etc. as well as
any concrete class pr abstract class.
This table lists the value Types and the standard data structure (reference) Types, each linking to its definition and further details:
Named values are statically typed: their Type, once defined, cannot be changed. A named value's type is:
- either automatically inferred from the value of the literal or expression defining a value Type,
- or specified in the definition of:
- data structures whose items have a particular Type, e.g.
List<of Int>list[int]List<int>List(Of Integer)List<int>
- parameters of functions and procedures
- return value of a function
- property of an abstract class or concrete class
Mutability of named values
The properties or contents of a named value that is of an immutable type may not be changed directly.
You can, however, create another instance that is a copy of the original
with all the same property values except for specific changes that you want to make.
The newly-minted copy (with changes) may be assigned either to a new named value, or as a re-definition of the original named value.
This table shows which named values can be reassigned and/or mutated depending on how they were defined:
| define named value | named value | notes |
| with | as mutable Type | as immutable Type | reassign with reassign | mutate | scope |
| constant | ✘ | ✔ | ✘ | ✘ | global |
values are assigned only at compile time |
| variable definition | ✔ | ✔ | ✔ | ✔ | local |
values are assigned during execution |
| parameter (by value) | ✔ | ✘ | ✘ | ✔ | local |
formal input argument of function, procedure or lambda |
| parameter (by reference) | ✔ | ✘ | ✘ | ✘ | local |
formal input and output argument of function, procedure or lambda |
Identifiers and type names
Named value identifier
The name given to every named value must follow the rules for an identifier:
- It must start with either a lowercase letter or an underscore, followed by any combination ot letters (upper- or lowercase), digits and underscore symbols.
- It must not contain spaces or symbols other than underscore.
- It cannot be the same as any language keyword, method or other reserved word. If you happen to choose such a name, an error message will tell you that it cannot be used for an identifier.
- Like all the language's keywords, it is case-sensitive.
- You cannot use two identifiers within the same scope that differ only in case, e.g.
varxvarxvarxvarxvarx and varXvarXvarXvarXvarX.
Type name
Every Type, whether system (e.g. ListlistListListList) or user-defined (e.g. classclassclassclassclass MyClass), is named like an identifier but
with one important difference: its first character must be an uppercase letter. Type names are also case-sensitive.
Scope and name qualification
'Scope' in the table above refers to where in your code a named value is accessible.
Global constants and enums , being the only values having global scope, can be referenced from anywhere in your program.
Every other kind of named value is local and restricted to the procedure or function within which it is defined.
Local named values can have the same name as a global constant, function, or procedure (which are all defined at global level or are in the standard library).
In such cases, when the name is used within the same method, then it will refer to the local definition.
Dot syntax
Reference to a named value is in many cases made with dot syntax, also referred to as applying a dot method. Here are its uses:
- To apply a function method to a named value, e.g. to obtain the length of String s using a library method:
variable nname? set to s.length()value or expression?0nname? = s.length()value or expression? # variable definition0var nname? = s.length()value or expression?;0Dim nname? = s.length()value or expression? ' variable definition0var nname? = s.length()value or expression?;0
- To apply a procedure to a named value, e.g. to initialise
ListlistListListList li using a library procedure:
call li.initialiseprocedureName?(10, 0arguments?)0li.initialiseprocedureName?(10, 0arguments?) # call procedure0li.initialiseprocedureName?(10, 0arguments?); // call procedure0li.initialiseprocedureName?(10, 0arguments?) ' call procedure0li.initialiseprocedureName?(10, 0arguments?); // call procedure0
- To refer to the property (body) of an instance (g) of class Game and, in this example, to get the length of the property's current string value, using
library methods:
variable bodyGLname? set to g.body.toString().length()value or expression?0bodyGLname? = g.body.toString().length()value or expression? # variable definition0var bodyGLname? = g.body.toString().length()value or expression?;0Dim bodyGLname? = g.body.toString().length()value or expression? ' variable definition0var bodyGLname? = g.body.toString().length()value or expression?;0
- To extract an item from a Tuple using its special properties item_N, e.g. to get the first value from a 2-Tuple:
variable pointname? set to (3, 7)value or expression?0pointname? = (3, 7)value or expression? # variable definition0var pointname? = (3, 7)value or expression?;0Dim pointname? = (3, 7)value or expression? ' variable definition0var pointname? = (3, 7)value or expression?;0
variable xname? set to point.item_0value or expression?0xname? = point.item_0value or expression? # variable definition0var xname? = point.item_0value or expression?;0Dim xname? = point.item_0value or expression? ' variable definition0var xname? = point.item_0value or expression?;0
- To refer to a 'value' in an enum, e.g.to pick one of the identifiers in the enum
SuitSuitSuitSuitSuit:
enum SuitName? spades, hearts, diamonds, clubsvalues?values?1class SuitName?(Enum):
spades = 1
hearts = 2
diamonds = 3
clubs = 4values?1enum SuitName? {spades, hearts, diamonds, clubsvalues?values?}1Enum SuitName?
spades = 0
hearts = 1
diamonds = 2
clubs = 3
End Enumvalues?1public class Global {
enum SuitName? {spades, hearts, diamonds, clubsvalues?values?}1
}
variable suitname? set to Suit.spadesvalue or expression?0suitname? = Suit.spadesvalue or expression? # variable definition0var suitname? = Suit.spadesvalue or expression?;0Dim suitname? = Suit.spadesvalue or expression? ' variable definition0var suitname? = Suit.spadesvalue or expression?;0
You cannot use dot syntax with functions and procedures that you define at the global level,
nor with some system functions (e.g. abs) and procedures (e.g. clearPrintedText).
Global instructions
Global instructions (also referred to as globals) are located directly in your code at the highest level.
They are never indented from the left-hand edge, nor may they be located within other instructions. They are:
main ,
procedure ,
function ,
test ,
concrete class ,
abstract class ,
constant and
enum .
- main, procedure and function are described as methods and these are defined by one or more statement instructions within them.
- test also contains instructions, in particular the assert equal instruction for testing functions during development of your program.
- concrete class and abstract class define data structures and these always contain members .
- constant and enum do not contain any further instructions: only names and values.
- The sequence of global instructions in your code is immaterial, with two exceptions:
- If one constant is used in the definition of another constant, the first must be declared above the second.
- An abstract class must be declared above any concrete class that inherits from it.
main
A program must have a main method, sometimes called its main routine, if it is intended to be run as a program. You may, however, develop and test code that does not have a main method, either as a coding exercise or for subsequent use within another program.
The main method defines the start point of a program when it is run (executed).
It does not have to be at the top of the file, but this is a good convention to follow.
It may delegate work to one or more procedures or functions .
There may not be more than one main in a program file, and the Global prompt will not show main as an option when one already exists in the file.
Example of a main method
● A main method
+main
1
variable liname? set to [3, 6, 1, 0, 99, 4, 67]value or expression?2
call inPlaceRippleSortprocedureName?(liarguments?)3
print(liarguments?)4
end main
+def main() -> None:
1
liname? = [3, 6, 1, 0, 99, 4, 67]value or expression? # variable definition2
inPlaceRippleSortprocedureName?(liarguments?) # call procedure3
print(liarguments?)4
main()
+static void main() {
1
var liname? = [3, 6, 1, 0, 99, 4, 67]value or expression?;2
inPlaceRippleSortprocedureName?(liarguments?); // call procedure3
Console.WriteLine(liarguments?); // print4
} // main
+Sub main()
1
Dim liname? = {3, 6, 1, 0, 99, 4, 67}value or expression? ' variable definition2
inPlaceRippleSortprocedureName?(liarguments?) ' call procedure3
Console.WriteLine(liarguments?) ' print4
End Sub
public class Global {
+static void main() {
1
var liname? = [3, 6, 1, 0, 99, 4, 67]value or expression?;2
inPlaceRippleSortprocedureName?(liarguments?); // call procedure3
System.out.println(liarguments?); // print4
} // main
}
procedure
A procedure is a named piece of code that may have parameters that are given inputs via arguments in a call procedure instruction.
Its name must follow the rules for an identifier .
Unlike a function:
- a procedure can have side effects: indeed it should have side effects, otherwise there would be no point in calling it.
- a procedure does not return a value.
- a procedure's parameter named values (that are mutable) may be changed inside the procedure, but they do not affect the value of arguments in the call procedure instruction outside the procedure.
- to pass a changed parameter back to its calling argument, it must have been called by reference .
The instructions within a procedure can therefore:
- include calls to other procedures, or to itself if recursion is required.
- include data input methods and other system functions such as for random number generation.
Procedure calls are of two kinds:
- to execute an action:
print(aListarguments?)0print(aListarguments?)0Console.WriteLine(aListarguments?); // print0Console.WriteLine(aListarguments?) ' print0System.out.println(aListarguments?); // print0
- to apply a procedure to a value using dot syntax :
call aList.removeAtprocedureName?(4arguments?)0aList.removeAtprocedureName?(4arguments?) # call procedure0aList.removeAtprocedureName?(4arguments?); // call procedure0aList.removeAtprocedureName?(4arguments?) ' call procedure0aList.removeAtprocedureName?(4arguments?); // call procedure0
These calls are to library procedures, but the same options are applicable to the procedures you write.
Example of a procedure
● Procedure to order a list of integers:
+procedure inPlaceRippleSortname?(li as List<of Int>parameter definitions?)
1
variable hasChangedname? set to truevalue or expression?2
variable lastCompname? set to li.length() - 2value or expression?3
+while hasChanged is truecondition?
4
reassign hasChangedvariableName? to falsevalue or expression?5
+for iitem? in range(0, lastComp + 1)source?
6
+if li[i] > li[i + 1]condition? then
7
variable tempname? 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 tempvalue or expression?10
reassign hasChangedvariableName? to truevalue or expression?11
end if
end for
reassign lastCompvariableName? to lastComp - 1value or expression?12
end while
end procedure
+def inPlaceRippleSortname?(li: list[int]parameter definitions?) -> None:
# procedure1
hasChangedname? = Truevalue or expression? # variable definition2
lastCompname? = li.length() - 2value or expression? # variable definition3
+while hasChanged == Truecondition?:
4
hasChangedvariableName? = Falsevalue or expression? # reassign variable5
+for iitem? in range(0, lastComp + 1)source?:
6
+if li[i] > li[i + 1]condition?:
7
tempname? = li[i]value or expression? # variable definition8
li[i]variableName? = li[i + 1]value or expression? # reassign variable9
li[i + 1]variableName? = tempvalue or expression? # reassign variable10
hasChangedvariableName? = Truevalue or expression? # reassign variable11
lastCompvariableName? = lastComp - 1value or expression? # reassign variable12
+static void inPlaceRippleSortname?(List<int> liparameter definitions?) {
// procedure1
var hasChangedname? = truevalue or expression?;2
var lastCompname? = li.length() - 2value or expression?;3
+while (hasChanged == truecondition?) {
4
hasChangedvariableName? = falsevalue or expression?; // reassign variable5
+foreach (iitem? in range(0, lastComp + 1)source?) {
6
+if (li[i] > li[i + 1]condition?) {
7
var tempname? = li[i]value or expression?;8
li[i]variableName? = li[i + 1]value or expression?; // reassign variable9
li[i + 1]variableName? = tempvalue or expression?; // reassign variable10
hasChangedvariableName? = truevalue or expression?; // reassign variable11
} // if
} // foreach
lastCompvariableName? = lastComp - 1value or expression?; // reassign variable12
} // while
} // procedure
+Sub inPlaceRippleSortname?(li As List(Of Integer)parameter definitions?)
' procedure1
Dim hasChangedname? = Truevalue or expression? ' variable definition2
Dim lastCompname? = li.length() - 2value or expression? ' variable definition3
+While hasChanged = Truecondition?
4
hasChangedvariableName? = Falsevalue or expression? ' reassign variable5
+For Each iitem? In range(0, lastComp + 1)source?
6
+If li[i] > li[i + 1]condition? Then
7
Dim tempname? = li[i]value or expression? ' variable definition8
li[i]variableName? = li[i + 1]value or expression? ' reassign variable9
li[i + 1]variableName? = tempvalue or expression? ' reassign variable10
hasChangedvariableName? = Truevalue or expression? ' reassign variable11
End If
Next i
lastCompvariableName? = lastComp - 1value or expression? ' reassign variable12
End While
End Sub
public class Global {
+static void inPlaceRippleSortname?(List<int> liparameter definitions?) {
// procedure1
var hasChangedname? = truevalue or expression?;2
var lastCompname? = li.length() - 2value or expression?;3
+while (hasChanged == truecondition?) {
4
hasChangedvariableName? = falsevalue or expression?; // reassign variable5
+foreach (iitem? in range(0, lastComp + 1)source?) {
6
+if (li[i] > li[i + 1]condition?) {
7
var tempname? = li[i]value or expression?;8
li[i]variableName? = li[i + 1]value or expression?; // reassign variable9
li[i + 1]variableName? = tempvalue or expression?; // reassign variable10
hasChangedvariableName? = truevalue or expression?; // reassign variable11
} // if
} // foreach
lastCompvariableName? = lastComp - 1value or expression?; // reassign variable12
} // while
} // procedure
}
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:
Example of a call by reference
● argRef is a pointer to variable arg in main,
so that arg can be accessed elsewhere by reference:
+main
1
variable argname? set to "abc"value or expression?2
variable argRefname? set to new AsRef<of String>(arg)value or expression?3
call changeArgprocedureName?(argRefarguments?)4
print(argRef.value()arguments?)5
end main
+procedure changeArgname?(pointer as AsRef<of String>parameter definitions?)
6
variable rname? set to pointer.value()value or expression?7
call pointer.setprocedureName?(r.upperCase()arguments?)8
end procedure
+def main() -> None:
1
argname? = "abc"value or expression? # variable definition2
argRefname? = AsRef[str](arg)value or expression? # variable definition3
changeArgprocedureName?(argRefarguments?) # call procedure4
print(argRef.value()arguments?)5
+def changeArgname?(pointer: AsRef[str]parameter definitions?) -> None:
# procedure6
rname? = pointer.value()value or expression? # variable definition7
pointer.setprocedureName?(r.upperCase()arguments?) # call procedure8
main()
+static void main() {
1
var argname? = "abc"value or expression?;2
var argRefname? = new AsRef<string>(arg)value or expression?;3
changeArgprocedureName?(argRefarguments?); // call procedure4
Console.WriteLine(argRef.value()arguments?); // print5
} // main
+static void changeArgname?(AsRef<string> pointerparameter definitions?) {
// procedure6
var rname? = pointer.value()value or expression?;7
pointer.setprocedureName?(r.upperCase()arguments?); // call procedure8
} // procedure
+Sub main()
1
Dim argname? = "abc"value or expression? ' variable definition2
Dim argRefname? = New AsRef(Of String)(arg)value or expression? ' variable definition3
changeArgprocedureName?(argRefarguments?) ' call procedure4
Console.WriteLine(argRef.value()arguments?) ' print5
End Sub
+Sub changeArgname?(pointer As AsRef(Of String)parameter definitions?)
' procedure6
Dim rname? = pointer.value()value or expression? ' variable definition7
pointer.setprocedureName?(r.upperCase()arguments?) ' call procedure8
End Sub
public class Global {
+static void main() {
1
var argname? = "abc"value or expression?;2
var argRefname? = new AsRef<String>(arg)value or expression?;3
changeArgprocedureName?(argRefarguments?); // call procedure4
System.out.println(argRef.value()arguments?); // print5
} // main
+static void changeArgname?(AsRef<String> pointerparameter definitions?) {
// procedure6
var rname? = pointer.value()value or expression?;7
pointer.setprocedureName?(r.upperCase()arguments?); // call procedure8
} // procedure
}
function
A function is a named piece of code that can define parameters which are given inputs via arguments when reference to the function occurs in an instruction or expression. Its name must follow the rules for an identifier .
Unlike a procedure :
- a function always returns a value.
- a function can have no side effects (i.e. no references outside its code) and cannot depend on any System methods .
- a function's execution cannot be interrupted by any external event, though a a non-terminating loop in a function may be detected with tests that time out .
A function definition is comprised of its unique name and, in brackets, its input parameters with their Types, followed by returnsreturnsreturnsreturnsreturns,
and the type of the value that will be returned.
A return instruction is automatically added as the last instruction of a function (since a function must return a value),
and there can be only one return instruction in a function.
You follow the return instruction with the value to be returned by the function.
This may be an expression that will be evaluated before returning.
Examples of functions
● Function to search a list of strings:
+function binarySearchname?(li as List<of String>, item as Stringparameter definitions?) returns BooleanType?
1
variable resultname? set to falsevalue or expression?2
+if li.length() > 0condition? then
3
variable midname? set to divAsInt(li.length(), 2)value or expression?4
variable valuename? set to li[mid]value or expression?5
+if item.equals(value)condition? then
6
reassign resultvariableName? to truevalue or expression?7
elif item.isBefore(value)condition? then8
reassign resultvariableName? to binarySearch(li.subList(0, mid), item)value or expression?9
else10
reassign resultvariableName? to binarySearch(li.subList(mid + 1, li.length()), item)value or expression?11
end if
end if
return resultvalue or expression?12
end function
+def binarySearchname?(li: list[str], item: strparameter definitions?) -> boolType?:
# function1
resultname? = Falsevalue or expression? # variable definition2
+if li.length() > 0condition?:
3
midname? = divAsInt(li.length(), 2)value or expression? # variable definition4
valuename? = li[mid]value or expression? # variable definition5
+if item.equals(value)condition?:
6
resultvariableName? = Truevalue or expression? # reassign variable7
elif item.isBefore(value)condition?: # else if8
resultvariableName? = binarySearch(li.subList(0, mid), item)value or expression? # reassign variable9
else:10
resultvariableName? = binarySearch(li.subList(mid + 1, li.length()), item)value or expression? # reassign variable11
return resultvalue or expression?12
+static boolType? binarySearchname?(List<string> li, string itemparameter definitions?) {
// function1
var resultname? = falsevalue or expression?;2
+if (li.length() > 0condition?) {
3
var midname? = divAsInt(li.length(), 2)value or expression?;4
var valuename? = li[mid]value or expression?;5
+if (item.equals(value)condition?) {
6
resultvariableName? = truevalue or expression?; // reassign variable7
} else if (item.isBefore(value)condition?) {8
resultvariableName? = binarySearch(li.subList(0, mid), item)value or expression?; // reassign variable9
} else {10
resultvariableName? = binarySearch(li.subList(mid + 1, li.length()), item)value or expression?; // reassign variable11
} // if
} // if
return resultvalue or expression?;12
} // function
+Function binarySearchname?(li As List(Of String), item As Stringparameter definitions?) As BooleanType?
1
Dim resultname? = Falsevalue or expression? ' variable definition2
+If li.length() > 0condition? Then
3
Dim midname? = divAsInt(li.length(), 2)value or expression? ' variable definition4
Dim valuename? = li[mid]value or expression? ' variable definition5
+If item.equals(value)condition? Then
6
resultvariableName? = Truevalue or expression? ' reassign variable7
ElseIf item.isBefore(value)condition? Then8
resultvariableName? = binarySearch(li.subList(0, mid), item)value or expression? ' reassign variable9
Else10
resultvariableName? = binarySearch(li.subList(mid + 1, li.length()), item)value or expression? ' reassign variable11
End If
End If
Return resultvalue or expression?12
End Function
public class Global {
+static boolType? binarySearchname?(List<String> li, String itemparameter definitions?) {
// function1
var resultname? = falsevalue or expression?;2
+if (li.length() > 0condition?) {
3
var midname? = divAsInt(li.length(), 2)value or expression?;4
var valuename? = li[mid]value or expression?;5
+if (item.equals(value)condition?) {
6
resultvariableName? = truevalue or expression?; // reassign variable7
} else if (item.isBefore(value)condition?) {8
resultvariableName? = binarySearch(li.subList(0, mid), item)value or expression?; // reassign variable9
} else {10
resultvariableName? = binarySearch(li.subList(mid + 1, li.length()), item)value or expression?; // reassign variable11
} // if
} // if
return resultvalue or expression?;12
} // function
}
● A function definition and reference to it:
+function scorename?(g as Gameparameter definitions?) returns IntType?
1
return g.body.length() - 2value or expression?2
end function
+main
3
variable gname? set to new Game()value or expression?4
print(score(g)arguments?)5
end main
+def scorename?(g: Gameparameter definitions?) -> intType?:
# function1
return g.body.length() - 2value or expression?2
+def main() -> None:
3
gname? = Game()value or expression? # variable definition4
print(score(g)arguments?)5
main()
+static intType? scorename?(Game gparameter definitions?) {
// function1
return g.body.length() - 2value or expression?;2
} // function
+static void main() {
3
var gname? = new Game()value or expression?;4
Console.WriteLine(score(g)arguments?); // print5
} // main
+Function scorename?(g As Gameparameter definitions?) As IntegerType?
1
Return g.body.length() - 2value or expression?2
End Function
+Sub main()
3
Dim gname? = New Game()value or expression? ' variable definition4
Console.WriteLine(score(g)arguments?) ' print5
End Sub
public class Global {
+static intType? scorename?(Game gparameter definitions?) {
// function1
return g.body.length() - 2value or expression?;2
} // function
+static void main() {
3
var gname? = new Game()value or expression?;4
System.out.println(score(g)arguments?); // print5
} // main
}
Recursion
Procedures and functions may be called or referenced recursively, as in this simple factorial calculation:
+function factorialname?(n as Intparameter definitions?) returns IntType?
1
return (if(n > 1, n*factorial(n - 1), 1))value or expression?2
end function
+def factorialname?(n: intparameter definitions?) -> intType?:
# function1
return (if(n > 1, n*factorial(n - 1), 1))value or expression?2
+static intType? factorialname?(int nparameter definitions?) {
// function1
return (if(n > 1, n*factorial(n - 1), 1))value or expression?;2
} // function
+Function factorialname?(n As Integerparameter definitions?) As IntegerType?
1
Return (if(n > 1, n*factorial(n - 1), 1))value or expression?2
End Function
public class Global {
+static intType? factorialname?(int nparameter definitions?) {
// function1
return (if(n > 1, n*factorial(n - 1), 1))value or expression?;2
} // function
}
test
A test instruction is at the global level, and consists of a set of assertions about the outputs of functions.
Without having to run your program, the assert equal instructions show whether your assertions pass or fail.
Example of a set of assert equal instructions that test a function
● Test function binarySearch on four test lists
+test test_binarySearchtest_name?
1
variable li1name? set to ["lemon", "lime", "orange"]value or expression?2
assert binarySearch(li1, "lemon")actual (computed) value? is trueexpected value? not run3
assert binarySearch(li1, "lime")actual (computed) value? is trueexpected value? not run4
assert binarySearch(li1, "orange")actual (computed) value? is trueexpected value? not run5
assert binarySearch(li1, "pear")actual (computed) value? is falseexpected value? not run6
variable li2name? set to ["lemon", "orange"]value or expression?7
assert binarySearch(li2, "lemon")actual (computed) value? is trueexpected value? not run8
assert binarySearch(li2, "orange")actual (computed) value? is trueexpected value? not run9
assert binarySearch(li2, "pear")actual (computed) value? is falseexpected value? not run10
variable li3name? set to ["lemon"]value or expression?11
assert binarySearch(li3, "lemon")actual (computed) value? is trueexpected value? not run12
assert binarySearch(li3, "lime")actual (computed) value? is falseexpected value? not run13
variable li4name? set to new List<of String>()value or expression?14
assert binarySearch(li4, "pear")actual (computed) value? is falseexpected value? not run15
end test
+def test_binarySearchtest_name?(self) -> None:
1
li1name? = ["lemon", "lime", "orange"]value or expression? # variable definition2
self.assertEqual(binarySearch(li1, "lemon")actual (computed) value?, Trueexpected value?) not run3
self.assertEqual(binarySearch(li1, "lime")actual (computed) value?, Trueexpected value?) not run4
self.assertEqual(binarySearch(li1, "orange")actual (computed) value?, Trueexpected value?) not run5
self.assertEqual(binarySearch(li1, "pear")actual (computed) value?, Falseexpected value?) not run6
li2name? = ["lemon", "orange"]value or expression? # variable definition7
self.assertEqual(binarySearch(li2, "lemon")actual (computed) value?, Trueexpected value?) not run8
self.assertEqual(binarySearch(li2, "orange")actual (computed) value?, Trueexpected value?) not run9
self.assertEqual(binarySearch(li2, "pear")actual (computed) value?, Falseexpected value?) not run10
li3name? = ["lemon"]value or expression? # variable definition11
self.assertEqual(binarySearch(li3, "lemon")actual (computed) value?, Trueexpected value?) not run12
self.assertEqual(binarySearch(li3, "lime")actual (computed) value?, Falseexpected value?) not run13
li4name? = list[str]()value or expression? # variable definition14
self.assertEqual(binarySearch(li4, "pear")actual (computed) value?, Falseexpected value?) not run15
+[TestMethod] static void test_binarySearchtest_name?() {
1
var li1name? = ["lemon", "lime", "orange"]value or expression?;2
Assert.AreEqual(trueexpected value?, binarySearch(li1, "lemon")actual (computed) value?); not run3
Assert.AreEqual(trueexpected value?, binarySearch(li1, "lime")actual (computed) value?); not run4
Assert.AreEqual(trueexpected value?, binarySearch(li1, "orange")actual (computed) value?); not run5
Assert.AreEqual(falseexpected value?, binarySearch(li1, "pear")actual (computed) value?); not run6
var li2name? = ["lemon", "orange"]value or expression?;7
Assert.AreEqual(trueexpected value?, binarySearch(li2, "lemon")actual (computed) value?); not run8
Assert.AreEqual(trueexpected value?, binarySearch(li2, "orange")actual (computed) value?); not run9
Assert.AreEqual(falseexpected value?, binarySearch(li2, "pear")actual (computed) value?); not run10
var li3name? = ["lemon"]value or expression?;11
Assert.AreEqual(trueexpected value?, binarySearch(li3, "lemon")actual (computed) value?); not run12
Assert.AreEqual(falseexpected value?, binarySearch(li3, "lime")actual (computed) value?); not run13
var li4name? = new List<string>()value or expression?;14
Assert.AreEqual(falseexpected value?, binarySearch(li4, "pear")actual (computed) value?); not run15
} // test
+<TestMethod> Sub test_binarySearchtest_name?()
1
Dim li1name? = {"lemon", "lime", "orange"}value or expression? ' variable definition2
Assert.AreEqual(Trueexpected value?, binarySearch(li1, "lemon")actual (computed) value?) not run3
Assert.AreEqual(Trueexpected value?, binarySearch(li1, "lime")actual (computed) value?) not run4
Assert.AreEqual(Trueexpected value?, binarySearch(li1, "orange")actual (computed) value?) not run5
Assert.AreEqual(Falseexpected value?, binarySearch(li1, "pear")actual (computed) value?) not run6
Dim li2name? = {"lemon", "orange"}value or expression? ' variable definition7
Assert.AreEqual(Trueexpected value?, binarySearch(li2, "lemon")actual (computed) value?) not run8
Assert.AreEqual(Trueexpected value?, binarySearch(li2, "orange")actual (computed) value?) not run9
Assert.AreEqual(Falseexpected value?, binarySearch(li2, "pear")actual (computed) value?) not run10
Dim li3name? = {"lemon"}value or expression? ' variable definition11
Assert.AreEqual(Trueexpected value?, binarySearch(li3, "lemon")actual (computed) value?) not run12
Assert.AreEqual(Falseexpected value?, binarySearch(li3, "lime")actual (computed) value?) not run13
Dim li4name? = New List(Of String)()value or expression? ' variable definition14
Assert.AreEqual(Falseexpected value?, binarySearch(li4, "pear")actual (computed) value?) not run15
End Sub
public class Global {
+@Test static void test_binarySearchtest_name?() {
1
var li1name? = ["lemon", "lime", "orange"]value or expression?;2
assertEquals(trueexpected value?, binarySearch(li1, "lemon")actual (computed) value?); not run3
assertEquals(trueexpected value?, binarySearch(li1, "lime")actual (computed) value?); not run4
assertEquals(trueexpected value?, binarySearch(li1, "orange")actual (computed) value?); not run5
assertEquals(falseexpected value?, binarySearch(li1, "pear")actual (computed) value?); not run6
var li2name? = ["lemon", "orange"]value or expression?;7
assertEquals(trueexpected value?, binarySearch(li2, "lemon")actual (computed) value?); not run8
assertEquals(trueexpected value?, binarySearch(li2, "orange")actual (computed) value?); not run9
assertEquals(falseexpected value?, binarySearch(li2, "pear")actual (computed) value?); not run10
var li3name? = ["lemon"]value or expression?;11
assertEquals(trueexpected value?, binarySearch(li3, "lemon")actual (computed) value?); not run12
assertEquals(falseexpected value?, binarySearch(li3, "lime")actual (computed) value?); not run13
var li4name? = new List<String>()value or expression?;14
assertEquals(falseexpected value?, binarySearch(li4, "pear")actual (computed) value?); not run15
} // test
}
Notes
- Elan tests are designed to test functions only. It is not possible to call a procedure or main routine within a test.
Nor is it possible to use any System method (the same rule as for a function).
- A test may optionally be given a name or description in free-form text, just like a comment, which plays no role in the execution of the test.
You might give the test the same name as a function that it is testing, or you might describe a particular scenario that is being tested.
- test instructions may be written anywhere in the code, provided they are at the global level.
- A test instruction may contain any number of assert equal instructions. The test runner is part of the IDE and it automatically attempts to run all assert equal instructions showing each one's pass or fail outcome alongside. However, if the test hits a runtime error (as distinct from an assert equal failure) then execution of the test will stop and remaining assert equals will be shown as 'not run'.
- In addition to assert equal instructions, a test may contain any other instructions that may be added into a function.
- All assert equal statements should be at the top level within the test instruction; none may be put into a loop structure.
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_roundtest_name?
1
assert sqrt(2).round(3)actual (computed) value? is 1.414expected value? not run2
end test
+def test_roundtest_name?(self) -> None:
1
self.assertEqual(sqrt(2).round(3)actual (computed) value?, 1.414expected value?) not run2
+[TestMethod] static void test_roundtest_name?() {
1
Assert.AreEqual(1.414expected value?, sqrt(2).round(3)actual (computed) value?); not run2
} // test
+<TestMethod> Sub test_roundtest_name?()
1
Assert.AreEqual(1.414expected value?, sqrt(2).round(3)actual (computed) value?) not run2
End Sub
public class Global {
+@Test static void test_roundtest_name?() {
1
assertEquals(1.414expected value?, sqrt(2).round(3)actual (computed) value?); not run2
} // 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_listtest_name?
1
variable aname? set to [5, 1, 7]value or expression?2
assert a[0]actual (computed) value? is 5expected value? not run3
assert a[2]actual (computed) value? is 7expected value? not run4
end test
+def test_listtest_name?(self) -> None:
1
aname? = [5, 1, 7]value or expression? # variable definition2
self.assertEqual(a[0]actual (computed) value?, 5expected value?) not run3
self.assertEqual(a[2]actual (computed) value?, 7expected value?) not run4
+[TestMethod] static void test_listtest_name?() {
1
var aname? = [5, 1, 7]value or expression?;2
Assert.AreEqual(5expected value?, a[0]actual (computed) value?); not run3
Assert.AreEqual(7expected value?, a[2]actual (computed) value?); not run4
} // test
+<TestMethod> Sub test_listtest_name?()
1
Dim aname? = {5, 1, 7}value or expression? ' variable definition2
Assert.AreEqual(5expected value?, a[0]actual (computed) value?) not run3
Assert.AreEqual(7expected value?, a[2]actual (computed) value?) not run4
End Sub
public class Global {
+@Test static void test_listtest_name?() {
1
var aname? = [5, 1, 7]value or expression?;2
assertEquals(5expected value?, a[0]actual (computed) value?); not run3
assertEquals(7expected value?, a[2]actual (computed) value?); not run4
} // test
}
This assert shows how testing can also be done against an expected error message:
+test test_messagetest_name?
1
variable aname? set to [5, 1, 7]value or expression?2
assert a[4]actual (computed) value? is 0expected value? not run3
assert a[4]actual (computed) value? is "Out of range index: 4 size: 3"expected value? not run4
end test
+def test_messagetest_name?(self) -> None:
1
aname? = [5, 1, 7]value or expression? # variable definition2
self.assertEqual(a[4]actual (computed) value?, 0expected value?) not run3
self.assertEqual(a[4]actual (computed) value?, "Out of range index: 4 size: 3"expected value?) not run4
+[TestMethod] static void test_messagetest_name?() {
1
var aname? = [5, 1, 7]value or expression?;2
Assert.AreEqual(0expected value?, a[4]actual (computed) value?); not run3
Assert.AreEqual("Out of range index: 4 size: 3"expected value?, a[4]actual (computed) value?); not run4
} // test
+<TestMethod> Sub test_messagetest_name?()
1
Dim aname? = {5, 1, 7}value or expression? ' variable definition2
Assert.AreEqual(0expected value?, a[4]actual (computed) value?) not run3
Assert.AreEqual("Out of range index: 4 size: 3"expected value?, a[4]actual (computed) value?) not run4
End Sub
public class Global {
+@Test static void test_messagetest_name?() {
1
var aname? = [5, 1, 7]value or expression?;2
assertEquals(0expected value?, a[4]actual (computed) value?); not run3
assertEquals("Out of range index: 4 size: 3"expected value?, a[4]actual (computed) value?); not run4
} // 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.
Example of testing long strings
● Reporting the first character at which the actual (computed) and expected strings differ:
+constant sGWname? 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 setInStylename?(s as Stringparameter definitions?) returns StringType?
2
return "<style>" + s + "<style>"value or expression?3
end function
+test test_setInStyletest_name?
4
assert setInStyle(sGW)actual (computed) value? is "<style>" + sGW + "<style>"expected value? not run5
#
end test
+sGWname? = "grid { display: flex; flex-direction: column; margin-top: 40px; width: 500px; } word { display: flex; flex-direction: row; margin: auto; }"literal value or data structure? # constant1
+def setInStylename?(s: strparameter definitions?) -> strType?:
# function2
return "<style>" + s + "<style>"value or expression?3
+def test_setInStyletest_name?(self) -> None:
4
self.assertEqual(setInStyle(sGW)actual (computed) value?, "<style>" + sGW + "<style>"expected value?) not run5
#
+const String sGWname? = "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 stringType? setInStylename?(string sparameter definitions?) {
// function2
return "<style>" + s + "<style>"value or expression?;3
} // function
+[TestMethod] static void test_setInStyletest_name?() {
4
Assert.AreEqual("<style>" + sGW + "<style>"expected value?, setInStyle(sGW)actual (computed) value?); not run5
//
} // test
+Const sGWname? = "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 setInStylename?(s As Stringparameter definitions?) As StringType?
2
Return "<style>" + s + "<style>"value or expression?3
End Function
+<TestMethod> Sub test_setInStyletest_name?()
4
Assert.AreEqual("<style>" + sGW + "<style>"expected value?, setInStyle(sGW)actual (computed) value?) not run5
'
End Sub
public class Global {
+final String sGWname? = "grid { display: flex; flex-direction: column; margin-top: 40px; width: 500px; } word { display: flex; flex-direction: row; margin: auto; }"literal value or data structure?; // constant1
+static StringType? setInStylename?(String sparameter definitions?) {
// function2
return "<style>" + s + "<style>"value or expression?;3
} // function
+@Test static void test_setInStyletest_name?() {
4
assertEquals("<style>" + sGW + "<style>"expected value?, setInStyle(sGW)actual (computed) value?); not run5
//
} // test
}
Ignoring tests
To ignore tests, 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).
Examples of ghosting tests
● Ghosting an entire test:
+test test_overAppletest_name?
variable g1name? set to new Game(new Random())value or expression?
variable g2name? set to g1.withApple(new Square(23, 15))value or expression?
assert headOverApple(g2)actual (computed) value? is falseexpected value? not run
variable g3name? set to g2.withHead(new Square(23, 15))value or expression?
assert headOverApple(g3)actual (computed) value? is trueexpected value? not run
end test
+def test_overAppletest_name?(self) -> None:
g1name? = Game(Random())value or expression? # variable definition
g2name? = g1.withApple(Square(23, 15))value or expression? # variable definition
self.assertEqual(headOverApple(g2)actual (computed) value?, Falseexpected value?) not run
g3name? = g2.withHead(Square(23, 15))value or expression? # variable definition
self.assertEqual(headOverApple(g3)actual (computed) value?, Trueexpected value?) not run
+[TestMethod] static void test_overAppletest_name?() {
var g1name? = new Game(new Random())value or expression?;
var g2name? = g1.withApple(new Square(23, 15))value or expression?;
Assert.AreEqual(falseexpected value?, headOverApple(g2)actual (computed) value?); not run
var g3name? = g2.withHead(new Square(23, 15))value or expression?;
Assert.AreEqual(trueexpected value?, headOverApple(g3)actual (computed) value?); not run
} // test
+<TestMethod> Sub test_overAppletest_name?()
Dim g1name? = New Game(New Random())value or expression? ' variable definition
Dim g2name? = g1.withApple(New Square(23, 15))value or expression? ' variable definition
Assert.AreEqual(Falseexpected value?, headOverApple(g2)actual (computed) value?) not run
Dim g3name? = g2.withHead(New Square(23, 15))value or expression? ' variable definition
Assert.AreEqual(Trueexpected value?, headOverApple(g3)actual (computed) value?) not run
End Sub
public class Global {
+@Test static void test_overAppletest_name?() {
var g1name? = new Game(new Random())value or expression?;
var g2name? = g1.withApple(new Square(23, 15))value or expression?;
assertEquals(falseexpected value?, headOverApple(g2)actual (computed) value?); not run
var g3name? = g2.withHead(new Square(23, 15))value or expression?;
assertEquals(trueexpected value?, headOverApple(g3)actual (computed) value?); not run
} // test
}
● Ghosting an assert:
+test test_overAppletest_name?
1
variable g1name? set to new Game(new Random())value or expression?2
variable g2name? set to g1.withApple(new Square(23, 15))value or expression?3
assert headOverApple(g2)actual (computed) value? is trueexpected value? not run
variable g3name? set to g2.withHead(new Square(23, 15))value or expression?4
assert headOverApple(g3)actual (computed) value? is trueexpected value? not run5
end test
+def test_overAppletest_name?(self) -> None:
1
g1name? = Game(Random())value or expression? # variable definition2
g2name? = g1.withApple(Square(23, 15))value or expression? # variable definition3
self.assertEqual(headOverApple(g2)actual (computed) value?, Trueexpected value?) not run
g3name? = g2.withHead(Square(23, 15))value or expression? # variable definition4
self.assertEqual(headOverApple(g3)actual (computed) value?, Trueexpected value?) not run5
+[TestMethod] static void test_overAppletest_name?() {
1
var g1name? = new Game(new Random())value or expression?;2
var g2name? = g1.withApple(new Square(23, 15))value or expression?;3
Assert.AreEqual(trueexpected value?, headOverApple(g2)actual (computed) value?); not run
var g3name? = g2.withHead(new Square(23, 15))value or expression?;4
Assert.AreEqual(trueexpected value?, headOverApple(g3)actual (computed) value?); not run5
} // test
+<TestMethod> Sub test_overAppletest_name?()
1
Dim g1name? = New Game(New Random())value or expression? ' variable definition2
Dim g2name? = g1.withApple(New Square(23, 15))value or expression? ' variable definition3
Assert.AreEqual(Trueexpected value?, headOverApple(g2)actual (computed) value?) not run
Dim g3name? = g2.withHead(New Square(23, 15))value or expression? ' variable definition4
Assert.AreEqual(Trueexpected value?, headOverApple(g3)actual (computed) value?) not run5
End Sub
public class Global {
+@Test static void test_overAppletest_name?() {
1
var g1name? = new Game(new Random())value or expression?;2
var g2name? = g1.withApple(new Square(23, 15))value or expression?;3
assertEquals(trueexpected value?, headOverApple(g2)actual (computed) value?); not run
var g3name? = g2.withHead(new Square(23, 15))value or expression?;4
assertEquals(trueexpected value?, headOverApple(g3)actual (computed) value?); not run5
} // 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.
concrete class
A concrete class is a user-defined type offering richer capability than an enum .
Like any other type its name must begin with an uppercase letter.
Defining a concrete class
A concrete class is instantiated using the concrete class instruction followed by the class name, and optional inherits to refer to a menu option class or abstract class defined above in the program.
A class definition must include properties, a constructor and at least one method called toString.
Its properties must all be initialised in the constructor.
It may contain functions and procedure methods.
The constructor may optionally define parameters to force the calling code to provide initial values.
Code in the constructor may make use of any functions, and follows the same constraints as a function (i.e. it may not call any procedure, whether defined in the class or outside).
A simple demonstration of a concrete class is:
+main
1
variable xname? set to new Thing()value or expression?2
print(xarguments?)3
print(x.names.toString()arguments?)4
end main
+class ThingName? inheritance?5
property namesname? as List<of String>Type?6
+constructor(parameter definitionsparameter definitions?)
7
reassign this.namesvariableName? to createList(6, "X")value or expression?8
end constructor
+function toStringname?(parameter definitionsparameter definitions?) returns StringType?
9
return "instance of class Thing"value or expression?10
end function
end class
+def main() -> None:
1
xname? = Thing()value or expression? # variable definition2
print(xarguments?)3
print(x.names.toString()arguments?)4
+class ThingName? inheritance? # concrete class5
namesname?: list[str]Type? # property6
+def __init__(self: Thing) -> None:
7
self.namesvariableName? = createList(6, "X")value or expression? # reassign variable8
+def toStringname?(self: Thing) -> strType?:
# function method9
return "instance of class Thing"value or expression?10
main()
+static void main() {
1
var xname? = new Thing()value or expression?;2
Console.WriteLine(xarguments?); // print3
Console.WriteLine(x.names.toString()arguments?); // print4
} // main
+class ThingName? inheritance? {5
public List<string>Type? namesname? {get; private set;} // property6
+public Thing(parameter definitionsparameter definitions?) {
7
this.namesvariableName? = createList(6, "X")value or expression?; // reassign variable8
} // constructor
+public stringType? toStringname?(parameter definitionsparameter definitions?) {
// function method9
return "instance of class Thing"value or expression?;10
} // function method
} // class
+Sub main()
1
Dim xname? = New Thing()value or expression? ' variable definition2
Console.WriteLine(xarguments?) ' print3
Console.WriteLine(x.names.toString()arguments?) ' print4
End Sub
+Class ThingName? inheritance?5
Property namesname? As List(Of String)Type?6
+Sub New(parameter definitionsparameter definitions?)
7
Me.namesvariableName? = createList(6, "X")value or expression? ' reassign variable8
End Sub
+Function toStringname?(parameter definitionsparameter definitions?) As StringType?
9
Return "instance of class Thing"value or expression?10
End Function
End Class
public class Global {
+static void main() {
1
var xname? = new Thing()value or expression?;2
System.out.println(xarguments?); // print3
System.out.println(x.names.toString()arguments?); // print4
} // main
+class ThingName? inheritance? {5
public List<String>Type? namesname?; // property6
+public Thing(parameter definitionsparameter definitions?) {
7
this.namesvariableName? = createList(6, "X")value or expression?; // reassign variable8
} // constructor
+public StringType? toStringname?(parameter definitionsparameter definitions?) {
// function method9
return "instance of class Thing"value or expression?;10
} // function method
} // class
}
Here is an example of concrete class definition taken from demo program snake - object-oriented:
Example definition of a concrete class
● Apple:
+class AppleName? inheritance?1
+constructor(parameter definitionsparameter definitions?)
2
reassign this.locationvariableName? to new Square(0, 0)value or expression?3
end constructor
+function toStringname?(parameter definitionsparameter definitions?) returns StringType?
4
return ""value or expression?5
end function
property locationname? as SquareType?6
+procedure newRandomPositionname?(snake as Snakeparameter definitions?)
7
variable changePositionname? set to truevalue or expression?8
+while changePositioncondition?
9
variable ranXname? set to randint(0, 39)value or expression?10
variable ranYname? set to randint(0, 29)value or expression?11
reassign this.locationvariableName? to new Square(ranX, ranY)value or expression?12
+if not snake.bodyCovers(this.location)condition? then
13
reassign changePositionvariableName? to falsevalue or expression?14
end if
end while
end procedure
+procedure updateBlocksname?(blocks as List<of List<of Int>>parameter definitions?)
15
reassign blocks[this.location.x][this.location.y]variableName? to redvalue or expression?16
end procedure
end class
+class AppleName? inheritance? # concrete class1
+def __init__(self: Apple) -> None:
2
self.locationvariableName? = Square(0, 0)value or expression? # reassign variable3
+def toStringname?(self: Apple) -> strType?:
# function method4
return ""value or expression?5
locationname?: SquareType? # property6
+def newRandomPositionname?(self: Apple, snake: Snakeparameter definitions?) -> None:
# procedure method7
changePositionname? = Truevalue or expression? # variable definition8
+while changePositioncondition?:
9
ranXname? = randint(0, 39)value or expression? # variable definition10
ranYname? = randint(0, 29)value or expression? # variable definition11
self.locationvariableName? = Square(ranX, ranY)value or expression? # reassign variable12
+if not snake.bodyCovers(self.location)condition?:
13
changePositionvariableName? = Falsevalue or expression? # reassign variable14
+def updateBlocksname?(self: Apple, blocks: list[list[int]]parameter definitions?) -> None:
# procedure method15
blocks[self.location.x][self.location.y]variableName? = redvalue or expression? # reassign variable16
+class AppleName? inheritance? {1
+public Apple(parameter definitionsparameter definitions?) {
2
this.locationvariableName? = new Square(0, 0)value or expression?; // reassign variable3
} // constructor
+public stringType? toStringname?(parameter definitionsparameter definitions?) {
// function method4
return ""value or expression?;5
} // function method
public SquareType? locationname? {get; private set;} // property6
+public void newRandomPositionname?(Snake snakeparameter definitions?) {
// procedure method7
var changePositionname? = truevalue or expression?;8
+while (changePositioncondition?) {
9
var ranXname? = randint(0, 39)value or expression?;10
var ranYname? = randint(0, 29)value or expression?;11
this.locationvariableName? = new Square(ranX, ranY)value or expression?; // reassign variable12
+if (!snake.bodyCovers(this.location)condition?) {
13
changePositionvariableName? = falsevalue or expression?; // reassign variable14
} // if
} // while
} // procedure method
+public void updateBlocksname?(List<List<int>> blocksparameter definitions?) {
// procedure method15
blocks[this.location.x][this.location.y]variableName? = redvalue or expression?; // reassign variable16
} // procedure method
} // class
+Class AppleName? inheritance?1
+Sub New(parameter definitionsparameter definitions?)
2
Me.locationvariableName? = New Square(0, 0)value or expression? ' reassign variable3
End Sub
+Function toStringname?(parameter definitionsparameter definitions?) As StringType?
4
Return ""value or expression?5
End Function
Property locationname? As SquareType?6
+Sub newRandomPositionname?(snake As Snakeparameter definitions?)
' procedure method7
Dim changePositionname? = Truevalue or expression? ' variable definition8
+While changePositioncondition?
9
Dim ranXname? = randint(0, 39)value or expression? ' variable definition10
Dim ranYname? = randint(0, 29)value or expression? ' variable definition11
Me.locationvariableName? = New Square(ranX, ranY)value or expression? ' reassign variable12
+If Not snake.bodyCovers(Me.location)condition? Then
13
changePositionvariableName? = Falsevalue or expression? ' reassign variable14
End If
End While
End Sub
+Sub updateBlocksname?(blocks As List(Of List(Of Integer))parameter definitions?)
' procedure method15
blocks[Me.location.x][Me.location.y]variableName? = redvalue or expression? ' reassign variable16
End Sub
End Class
public class Global {
+class AppleName? inheritance? {1
+public Apple(parameter definitionsparameter definitions?) {
2
this.locationvariableName? = new Square(0, 0)value or expression?; // reassign variable3
} // constructor
+public StringType? toStringname?(parameter definitionsparameter definitions?) {
// function method4
return ""value or expression?;5
} // function method
public SquareType? locationname?; // property6
+public void newRandomPositionname?(Snake snakeparameter definitions?) {
// procedure method7
var changePositionname? = truevalue or expression?;8
+while (changePositioncondition?) {
9
var ranXname? = randint(0, 39)value or expression?;10
var ranYname? = randint(0, 29)value or expression?;11
this.locationvariableName? = new Square(ranX, ranY)value or expression?; // reassign variable12
+if (!snake.bodyCovers(this.location)condition?) {
13
changePositionvariableName? = falsevalue or expression?; // reassign variable14
} // if
} // while
} // procedure method
+public void updateBlocksname?(List<List<int>> blocksparameter definitions?) {
// procedure method15
blocks[this.location.x][this.location.y]variableName? = redvalue or expression?; // reassign variable16
} // procedure method
} // class
}
this
If in the code of classclassclassclassclass A you want to invoke a method in classclassclassclassclass S and pass to it the current instance of A,
you can refer to this instance with thisthisthisthisthis, as shown by this line in demo program Snake - object-oriented:
call apple.newRandomPositionprocedureName?(thisarguments?)0apple.newRandomPositionprocedureName?(selfarguments?) # call procedure0apple.newRandomPositionprocedureName?(thisarguments?); // call procedure0apple.newRandomPositionprocedureName?(Mearguments?) ' call procedure0apple.newRandomPositionprocedureName?(thisarguments?); // call procedure0
Here, method newRandomPosition is defined on class AppleAppleAppleAppleApple which needs to be passed an instance of class SnakeSnakeSnakeSnakeSnake,
apple being an instance of class AppleAppleAppleAppleApple.
inherits
A concrete class (often referred to simply as a class)
may optionally inherit from just one abstract class.
The concrete class must define for itself a concrete implementation of every abstract member defined in the abstract class that it inherits from, directly or indirectly.
Notes
- An abstract class must be declared in the code above any class that inherits from it.
- You cannot override any concrete member defined in an abstract class.
- Inheritance hierarchies must form a tree, that is you must avoid creating a circular dependency where, for example, type A inherits from type B, which inherits from type
CCCCC, which inherits from type AAAAA.
abstract class
An abstract class may not be instantiated (and hence may not define a constructor). It may define these concrete members:
- a property
- a function
- a procedure
As with a concrete class, any of these members may be made privateprivateprivateprivateprivate, after the corresponding instruction has been added, by selecting that member instruction and keying Ctrl+p.
These concrete members are automatically inherited by any subclass, but they may not be overridden (re-defined) by the subclass. Therefore you should define concrete members only if they are intended to work identically on every subclass.
You may also define abstract methods on an abstract class, i.e. abstract property, abstract function, abstract procedure. Such methods define only the signature of the method, not the implementation (body), therefore they have no endendendendend instruction. For example:
+function calculateDiscountname?(a as Float, d as Floatparameter definitions?) returns FloatType?
1
let discountname? be a*dvalue or expression?2
return discountvalue or expression?3
end function
+def calculateDiscountname?(a: float, d: floatparameter definitions?) -> floatType?:
# function1
discountname? = a*dvalue or expression? # let2
return discountvalue or expression?3
+static doubleType? calculateDiscountname?(double a, double dparameter definitions?) {
// function1
var discountname? = a*dvalue or expression?; // let2
return discountvalue or expression?;3
} // function
+Function calculateDiscountname?(a As Double, d As Doubleparameter definitions?) As DoubleType?
1
Dim discountname? = a*dvalue or expression? ' let2
Return discountvalue or expression?3
End Function
public class Global {
+static doubleType? calculateDiscountname?(double a, double dparameter definitions?) {
// function1
var discountname? = a*dvalue or expression?; // let2
return discountvalue or expression?;3
} // function
}
If you wish to have several subclasses of an abstract class that share a common implementation for a method, but require that some of the subclasses can define a different implementation, then you should:
- Define the method as abstract on the superclass.
- Define a concrete implementation on the superclass with a similar, but slightly different, name e.g. by adding a prefix such as:
defaultdefaultdefaultdefaultdefault.
- Each subclass must then define its implementation of the abstract method, but the ones needing a common implementation can be just one line, delegating responsibility up to the 'default' method on the superclass.
constant
A constant instruction defines a named value that is defined at the global level in a program, is global in scope and cannot be changed.
Its name follows the rules for an identifier .
A constant is defined by a literal of a value Type, namely IntintintIntegerint, FloatfloatdoubleDoubledouble, BooleanboolboolBooleanbool or
StringstrstringStringString.
Constants are created at compile time, so cannot be defined with reference to any function, nor can they use any operators in an expression.
A constant can be defined by reference to a previously defined constant or to a system constant,
but take care not to re-define a system constant such as pi or blue without good reason.
A 'constant' data structure can be defined by using a function which is then referenced from wherever needed.
See Constant data structures .
Examples of literal definitions of the valid Types of constant:
+constant maxHitsname? set to 10literal value or data structure?1
+constant turquoisename? set to 0x00ced1literal value or data structure?2
+constant liveCellname? set to blackliteral value or data structure?3
+constant speedOfLightname? set to 299792.458literal value or data structure?4
+constant gameOvername? set to trueliteral value or data structure?5
+constant euroname? set to 0x20acliteral value or data structure?6
+constant warningMsgname? set to "Limit reached"literal value or data structure?7
+maxHitsname? = 10literal value or data structure? # constant1
+turquoisename? = 0x00ced1literal value or data structure? # constant2
+liveCellname? = blackliteral value or data structure? # constant3
+speedOfLightname? = 299792.458literal value or data structure? # constant4
+gameOvername? = Trueliteral value or data structure? # constant5
+euroname? = 0x20acliteral value or data structure? # constant6
+warningMsgname? = "Limit reached"literal value or data structure? # constant7
+const Int maxHitsname? = 10literal value or data structure?;1
+const Int turquoisename? = 0x00ced1literal value or data structure?;2
+const Int liveCellname? = blackliteral value or data structure?;3
+const Float speedOfLightname? = 299792.458literal value or data structure?;4
+const Boolean gameOvername? = trueliteral value or data structure?;5
+const Int euroname? = 0x20acliteral value or data structure?;6
+const String warningMsgname? = "Limit reached"literal value or data structure?;7
+Const maxHitsname? = 10literal value or data structure?1
+Const turquoisename? = &H00ced1literal value or data structure?2
+Const liveCellname? = blackliteral value or data structure?3
+Const speedOfLightname? = 299792.458literal value or data structure?4
+Const gameOvername? = Trueliteral value or data structure?5
+Const euroname? = &H20acliteral value or data structure?6
+Const warningMsgname? = "Limit reached"literal value or data structure?7
public class Global {
+final Int maxHitsname? = 10literal value or data structure?; // constant1
+final Int turquoisename? = 0x00ced1literal value or data structure?; // constant2
+final Int liveCellname? = blackliteral value or data structure?; // constant3
+final Float speedOfLightname? = 299792.458literal value or data structure?; // constant4
+final Boolean gameOvername? = trueliteral value or data structure?; // constant5
+final Int euroname? = 0x20acliteral value or data structure?; // constant6
+final String warningMsgname? = "Limit reached"literal value or data structure?; // constant7
}
Constant data structures
To use a data structure that is to be a constant in your program, you define it as the value of a function
which cam then be referenced from anywhere in the program, often from within an expression.
These examples define a constant ListlistListListList and a constant DictionaryDictionaryDictionaryDictionaryDictionary of colours which
are indexable:
+main
1
call printprocedureName?($"{rainbow()[0]} is violet"arguments?)2
call printprocedureName?($"{suitColours()["hearts"]} is red"arguments?)3
end main
+function rainbowname?(parameter definitionsparameter definitions?) returns List<of Int>Type?
4
return [0x9400D3, 0x4B0082, 0x0000CD, 0x008000, 0xFFFF00, 0xFFA500, 0xFF0000]value or expression?5
end function
+function suitColoursname?(parameter definitionsparameter 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
printprocedureName?(f"{rainbow()[0]} is violet"arguments?)2
printprocedureName?(f"{suitColours()["hearts"]} is red"arguments?)3
+def rainbowname?(parameter definitionsparameter definitions?) -> list[int]Type?:
# function4
return [0x9400D3, 0x4B0082, 0x0000CD, 0x008000, 0xFFFF00, 0xFFA500, 0xFF0000]value or expression?5
+def suitColoursname?(parameter definitionsparameter definitions?) -> Dictionary[str, int]Type?:
# function6
return ["spades":black, "hearts":red, "diamonds":red, "clubs":black]value or expression?7
main()
+static void main() {
1
printprocedureName?($"{rainbow()[0]} is violet"arguments?);2
printprocedureName?($"{suitColours()["hearts"]} is red"arguments?);3
} // main
+static List<int>Type? rainbowname?(parameter definitionsparameter definitions?) {
// function4
return [0x9400D3, 0x4B0082, 0x0000CD, 0x008000, 0xFFFF00, 0xFFA500, 0xFF0000]value or expression?;5
} // function
+static Dictionary<string, int>Type? suitColoursname?(parameter definitionsparameter definitions?) {
// function6
return ["spades":black, "hearts":red, "diamonds":red, "clubs":black]value or expression?;7
} // function
+Sub main()
1
printprocedureName?($"{rainbow()[0]} is violet"arguments?)2
printprocedureName?($"{suitColours()["hearts"]} is red"arguments?)3
End Sub
+Function rainbowname?(parameter definitionsparameter definitions?) As List(Of Integer)Type?
4
Return {&H9400D3, &H4B0082, &H0000CD, &H008000, &HFFFF00, &HFFA500, &HFF0000}value or expression?5
End Function
+Function suitColoursname?(parameter definitionsparameter 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
printprocedureName?(String.format("% is violet", rainbow()[0])arguments?);2
printprocedureName?(String.format("% is red", suitColours()["hearts"])arguments?);3
} // main
+static List<int>Type? rainbowname?(parameter definitionsparameter definitions?) {
// function4
return [0x9400D3, 0x4B0082, 0x0000CD, 0x008000, 0xFFFF00, 0xFFA500, 0xFF0000]value or expression?;5
} // function
+static Dictionary<String, int>Type? suitColoursname?(parameter definitionsparameter definitions?) {
// function6
return ["spades":black, "hearts":red, "diamonds":red, "clubs":black]value or expression?;7
} // function
}
System constants
Some useful constants are provided: see System constants
enum
An enum – short for 'enumeration' – provides for the simplest form of user-defined Type.
It is used to provide a fixed set of options that are self-explanatory, and the references to its
those options (its 'values') are checked at compile time.
You define an enum with a type name (so starting with an uppercase letter) followed by a
number of 'values' (separated by commas) which must all be valid identifiers .
A reference to an enum by its type name necessarily holds one of the 'values'.
Reference to the value in an enum is made by using dot syntax with method enumValue.
An enum is read-only: once it has been defined it is not possible to add, remove, or update its values.
Examples of enum definitions:
enum SuitName? spades, hearts, diamonds, clubsvalues?values?1
enum OutcomeName? undecided, win, lose, draw, winDoublevalues?values?2
class SuitName?(Enum):
spades = 1
hearts = 2
diamonds = 3
clubs = 4values?1
class OutcomeName?(Enum):
undecided = 1
win = 2
lose = 3
draw = 4
winDouble = 5values?2
enum SuitName? {spades, hearts, diamonds, clubsvalues?values?}1
enum OutcomeName? {undecided, win, lose, draw, winDoublevalues?values?}2
Enum SuitName?
spades = 0
hearts = 1
diamonds = 2
clubs = 3
End Enumvalues?1
Enum OutcomeName?
undecided = 0
win = 1
lose = 2
draw = 3
winDouble = 4
End Enumvalues?2
public class Global {
enum SuitName? {spades, hearts, diamonds, clubsvalues?values?}1
enum OutcomeName? {undecided, win, lose, draw, winDoublevalues?values?}2
}
Examples using enum
● To retrieve a valid 'value':
enum StatusName? pending, playing, standing, blackjack, bustvalues?values?1
+main
2
variable statename? set to Status.pendingvalue or expression?3
end main
class StatusName?(Enum):
pending = 1
playing = 2
standing = 3
blackjack = 4
bust = 5values?1
+def main() -> None:
2
statename? = Status.pendingvalue or expression? # variable definition3
main()
enum StatusName? {pending, playing, standing, blackjack, bustvalues?values?}1
+static void main() {
2
var statename? = Status.pendingvalue or expression?;3
} // main
Enum StatusName?
pending = 0
playing = 1
standing = 2
blackjack = 3
bust = 4
End Enumvalues?1
+Sub main()
2
Dim statename? = Status.pendingvalue or expression? ' variable definition3
End Sub
public class Global {
enum StatusName? {pending, playing, standing, blackjack, bustvalues?values?}1
+static void main() {
2
var statename? = Status.pendingvalue or expression?;3
} // main
}
● To get a valid option from an abbreviation (in demo program pathfinder.elan):
enum AlgorithmName? dijkstra, aStar, heuristicvalues?values?1
+function getAlgFromLettername?(letter as Stringparameter definitions?) returns AlgorithmType?
2
variable algsname? set to ["a":Algorithm.aStar, "d":Algorithm.dijkstra, "h":Algorithm.heuristic]value or expression?3
return algs[letter]value or expression?4
end function
class AlgorithmName?(Enum):
dijkstra = 1
aStar = 2
heuristic = 3values?1
+def getAlgFromLettername?(letter: strparameter definitions?) -> AlgorithmType?:
# function2
algsname? = ["a":Algorithm.aStar, "d":Algorithm.dijkstra, "h":Algorithm.heuristic]value or expression? # variable definition3
return algs[letter]value or expression?4
enum AlgorithmName? {dijkstra, aStar, heuristicvalues?values?}1
+static AlgorithmType? getAlgFromLettername?(string letterparameter definitions?) {
// function2
var algsname? = ["a":Algorithm.aStar, "d":Algorithm.dijkstra, "h":Algorithm.heuristic]value or expression?;3
return algs[letter]value or expression?;4
} // function
Enum AlgorithmName?
dijkstra = 0
aStar = 1
heuristic = 2
End Enumvalues?1
+Function getAlgFromLettername?(letter As Stringparameter definitions?) As AlgorithmType?
2
Dim algsname? = ["a":Algorithm.aStar, "d":Algorithm.dijkstra, "h":Algorithm.heuristic]value or expression? ' variable definition3
Return algs[letter]value or expression?4
End Function
public class Global {
enum AlgorithmName? {dijkstra, aStar, heuristicvalues?values?}1
+static AlgorithmType? getAlgFromLettername?(String letterparameter definitions?) {
// function2
var algsname? = ["a":Algorithm.aStar, "d":Algorithm.dijkstra, "h":Algorithm.heuristic]value or expression?;3
return algs[letter]value or expression?;4
} // function
}
● A function to turn directions held in an enum through 90° clockwise:
enum CompassName? north, east, south, westvalues?values?1
+main
2
variable dirname? set to Compass.southvalue or expression?3
print(enumValue(clockwise(dir))arguments?)4
end main
+function clockwisename?(d as Compassparameter definitions?) returns CompassType?
5
variable newDirname? set to Compass.northvalue or expression?6
+if d.equals(Compass.north)condition? then
7
reassign newDirvariableName? to Compass.eastvalue or expression?8
elif d.equals(Compass.east)condition? then9
reassign newDirvariableName? to Compass.southvalue or expression?10
elif d.equals(Compass.south)condition? then11
reassign newDirvariableName? to Compass.westvalue or expression?12
end if
return newDirvalue or expression?13
end function
class CompassName?(Enum):
north = 1
east = 2
south = 3
west = 4values?1
+def main() -> None:
2
dirname? = Compass.southvalue or expression? # variable definition3
print(enumValue(clockwise(dir))arguments?)4
+def clockwisename?(d: Compassparameter definitions?) -> CompassType?:
# function5
newDirname? = Compass.northvalue or expression? # variable definition6
+if d.equals(Compass.north)condition?:
7
newDirvariableName? = Compass.eastvalue or expression? # reassign variable8
elif d.equals(Compass.east)condition?: # else if9
newDirvariableName? = Compass.southvalue or expression? # reassign variable10
elif d.equals(Compass.south)condition?: # else if11
newDirvariableName? = Compass.westvalue or expression? # reassign variable12
return newDirvalue or expression?13
main()
enum CompassName? {north, east, south, westvalues?values?}1
+static void main() {
2
var dirname? = Compass.southvalue or expression?;3
Console.WriteLine(enumValue(clockwise(dir))arguments?); // print4
} // main
+static CompassType? clockwisename?(Compass dparameter definitions?) {
// function5
var newDirname? = Compass.northvalue or expression?;6
+if (d.equals(Compass.north)condition?) {
7
newDirvariableName? = Compass.eastvalue or expression?; // reassign variable8
} else if (d.equals(Compass.east)condition?) {9
newDirvariableName? = Compass.southvalue or expression?; // reassign variable10
} else if (d.equals(Compass.south)condition?) {11
newDirvariableName? = Compass.westvalue or expression?; // reassign variable12
} // if
return newDirvalue or expression?;13
} // function
Enum CompassName?
north = 0
east = 1
south = 2
west = 3
End Enumvalues?1
+Sub main()
2
Dim dirname? = Compass.southvalue or expression? ' variable definition3
Console.WriteLine(enumValue(clockwise(dir))arguments?) ' print4
End Sub
+Function clockwisename?(d As Compassparameter definitions?) As CompassType?
5
Dim newDirname? = Compass.northvalue or expression? ' variable definition6
+If d.equals(Compass.north)condition? Then
7
newDirvariableName? = Compass.eastvalue or expression? ' reassign variable8
ElseIf d.equals(Compass.east)condition? Then9
newDirvariableName? = Compass.southvalue or expression? ' reassign variable10
ElseIf d.equals(Compass.south)condition? Then11
newDirvariableName? = Compass.westvalue or expression? ' reassign variable12
End If
Return newDirvalue or expression?13
End Function
public class Global {
enum CompassName? {north, east, south, westvalues?values?}1
+static void main() {
2
var dirname? = Compass.southvalue or expression?;3
System.out.println(enumValue(clockwise(dir))arguments?); // print4
} // main
+static CompassType? clockwisename?(Compass dparameter definitions?) {
// function5
var newDirname? = Compass.northvalue or expression?;6
+if (d.equals(Compass.north)condition?) {
7
newDirvariableName? = Compass.eastvalue or expression?; // reassign variable8
} else if (d.equals(Compass.east)condition?) {9
newDirvariableName? = Compass.southvalue or expression?; // reassign variable10
} else if (d.equals(Compass.south)condition?) {11
newDirvariableName? = Compass.westvalue or expression?; // reassign variable12
} // if
return newDirvalue or expression?;13
} // function
}
Member instructions
Member instructions (also referred to simply as 'members') are located within an abstract class or concrete class.
The new code prompt offers a context appropriate subset of the following member instructions:
abstract property ,
abstract function ,
abstract procedure ,
property ,
function method ,
procedure method and
constructor ,
together with these 'private' versions:
private property ,
private function and
private procedure .
This table shows which kinds of property, function, procedure and constructor are applicable to the various kinds of class.
constructor
A concrete class may have an optional constructor so as to:
- initialise properties with fixed values
- define parameters which are used to initialise properties
If a concrete class's constructor defines parameters then, when the class is instantiated (using new), the values of
the correct type must be provided. For example, if the class SquareSquareSquareSquareSquare has this constructor:
+class SquareName? inheritance?1
+constructor(x as Int, y as Intparameter definitions?)
2
reassign this.xvariableName? to xvalue or expression?3
reassign this.yvariableName? to yvalue or expression?4
end constructor
+function toStringname?(parameter definitions?) returns StringType?
5
return "undefined"value or expression?6
end function
end class
+class SquareName? inheritance? # concrete class1
+def __init__(self: Square, x: int, y: intparameter definitions?) -> None:
2
self.xvariableName? = xvalue or expression? # reassign variable3
self.yvariableName? = yvalue or expression? # reassign variable4
+def toStringname?(self: Square) -> strType?:
# function method5
return "undefined"value or expression?6
+class SquareName? inheritance? {1
+public Square(int x, int yparameter definitions?) {
2
this.xvariableName? = xvalue or expression?; // reassign variable3
this.yvariableName? = yvalue or expression?; // reassign variable4
} // constructor
+public stringType? toStringname?(parameter definitions?) {
// function method5
return "undefined"value or expression?;6
} // function method
} // class
+Class SquareName? inheritance?1
+Sub New(x As Integer, y As Integerparameter definitions?)
2
Me.xvariableName? = xvalue or expression? ' reassign variable3
Me.yvariableName? = yvalue or expression? ' reassign variable4
End Sub
+Function toStringname?(parameter definitions?) As StringType?
5
Return "undefined"value or expression?6
End Function
End Class
public class Global {
+class SquareName? inheritance? {1
+public Square(int x, int yparameter definitions?) {
2
this.xvariableName? = xvalue or expression?; // reassign variable3
this.yvariableName? = yvalue or expression?; // reassign variable4
} // constructor
+public StringType? toStringname?(parameter definitions?) {
// function method5
return "undefined"value or expression?;6
} // function method
} // class
}
then it may be instantiated like this:
variable tailname? set to new Square(20, 15)value or expression?0tailname? = Square(20, 15)value or expression? # variable definition0var tailname? = new Square(20, 15)value or expression?;0Dim tailname? = New Square(20, 15)value or expression? ' variable definition0var tailname? = new Square(20, 15)value or expression?;0
property
A property is a named value defined on a concrete class with a name conforming to the rules for an identifier ,
and a type (which may be another class name).
It may be read, but not written to: properties may be modified only from outside the class by means of a procedure method .
It may be given an initial value within a constructor, for example:
+class GameName? inheritance?1
property heightname? as IntType?2
property boardname? as BoardType?3
property headname? as SquareType?4
property bodyname? as List<of Square>Type?5
+constructor(parameter definitionsparameter definitions?)
6
new code
end constructor
+function toStringname?(parameter definitionsparameter definitions?) returns StringType?
7
return "undefined"value or expression?8
end function
end class
+class GameName? inheritance? # concrete class1
heightname?: intType? # property2
boardname?: BoardType? # property3
headname?: SquareType? # property4
bodyname?: list[Square]Type? # property5
+def __init__(self: Game) -> None:
6
new code
+def toStringname?(self: Game) -> strType?:
# function method7
return "undefined"value or expression?8
+class GameName? inheritance? {1
public intType? heightname? {get; private set;} // property2
public BoardType? boardname? {get; private set;} // property3
public SquareType? headname? {get; private set;} // property4
public List<Square>Type? bodyname? {get; private set;} // property5
+public Game(parameter definitionsparameter definitions?) {
6
new code
} // constructor
+public stringType? toStringname?(parameter definitionsparameter definitions?) {
// function method7
return "undefined"value or expression?;8
} // function method
} // class
+Class GameName? inheritance?1
Property heightname? As IntegerType?2
Property boardname? As BoardType?3
Property headname? As SquareType?4
Property bodyname? As List(Of Square)Type?5
+Sub New(parameter definitionsparameter definitions?)
6
new code
End Sub
+Function toStringname?(parameter definitionsparameter definitions?) As StringType?
7
Return "undefined"value or expression?8
End Function
End Class
public class Global {
+class GameName? inheritance? {1
public intType? heightname?; // property2
public BoardType? boardname?; // property3
public SquareType? headname?; // property4
public List<Square>Type? bodyname?; // property5
+public Game(parameter definitionsparameter definitions?) {
6
new code
} // constructor
+public StringType? toStringname?(parameter definitionsparameter definitions?) {
// function method7
return "undefined"value or expression?;8
} // function method
} // class
}
MaybeMaybeMaybeMaybeMaybe
When a class property is optional, it is defined with the type MaybeMaybeMaybeMaybeMaybe.
Before reading the property's value, you must test if it has a value with function hasValue which returns a BooleanboolboolBooleanbool.
If trueTruetrueTruetrue is returned, then you retrieve the value with function getValue; if falseFalsefalseFalsefalse is returned, then it has no current value,
and using getValue will give a runtime error.
To update the property's value, use function setValue. To restore it to having no value, use function clearValue.
Example using MaybeMaybeMaybeMaybeMaybe
● Here a pupil (of class Pupil) need not have a tutor (of class Teacher):
+main
1
variable tTomname? set to new Teacher()value or expression?2
variable pPetename? set to new Pupil()value or expression?3
+if pPete.tutor.hasValue()condition? then
4
print(pPete.tutorarguments?)5
end if
print(parguments?)6
end main
+class TeacherName? inheritance?7
+constructor(parameter definitionsparameter definitions?)
8
new code
end constructor
+function toStringname?(parameter definitionsparameter definitions?) returns StringType?
9
return $"{this}"value or expression?10
end function
end class
+class PupilName? inheritance?11
+constructor(parameter definitionsparameter definitions?)
12
reassign this.tutorvariableName? to new Maybe<of Teacher>()value or expression?13
end constructor
property tutorname? as Maybe<of Teacher>Type?14
+function toStringname?(parameter definitionsparameter definitions?) returns StringType?
15
return "undefined"value or expression?16
end function
end class
+def main() -> None:
1
tTomname? = Teacher()value or expression? # variable definition2
pPetename? = Pupil()value or expression? # variable definition3
+if pPete.tutor.hasValue()condition?:
4
print(pPete.tutorarguments?)5
print(parguments?)6
+class TeacherName? inheritance? # concrete class7
+def __init__(self: Teacher) -> None:
8
new code
+def toStringname?(self: Teacher) -> strType?:
# function method9
return f"{self}"value or expression?10
+class PupilName? inheritance? # concrete class11
+def __init__(self: Pupil) -> None:
12
self.tutorvariableName? = Maybe[Teacher]()value or expression? # reassign variable13
tutorname?: Maybe[Teacher]Type? # property14
+def toStringname?(self: Pupil) -> strType?:
# function method15
return "undefined"value or expression?16
main()
+static void main() {
1
var tTomname? = new Teacher()value or expression?;2
var pPetename? = new Pupil()value or expression?;3
+if (pPete.tutor.hasValue()condition?) {
4
Console.WriteLine(pPete.tutorarguments?); // print5
} // if
Console.WriteLine(parguments?); // print6
} // main
+class TeacherName? inheritance? {7
+public Teacher(parameter definitionsparameter definitions?) {
8
new code
} // constructor
+public stringType? toStringname?(parameter definitionsparameter definitions?) {
// function method9
return $"{this}"value or expression?;10
} // function method
} // class
+class PupilName? inheritance? {11
+public Pupil(parameter definitionsparameter definitions?) {
12
this.tutorvariableName? = new Maybe<Teacher>()value or expression?; // reassign variable13
} // constructor
public Maybe<Teacher>Type? tutorname? {get; private set;} // property14
+public stringType? toStringname?(parameter definitionsparameter definitions?) {
// function method15
return "undefined"value or expression?;16
} // function method
} // class
+Sub main()
1
Dim tTomname? = New Teacher()value or expression? ' variable definition2
Dim pPetename? = New Pupil()value or expression? ' variable definition3
+If pPete.tutor.hasValue()condition? Then
4
Console.WriteLine(pPete.tutorarguments?) ' print5
End If
Console.WriteLine(parguments?) ' print6
End Sub
+Class TeacherName? inheritance?7
+Sub New(parameter definitionsparameter definitions?)
8
new code
End Sub
+Function toStringname?(parameter definitionsparameter definitions?) As StringType?
9
Return $"{Me}"value or expression?10
End Function
End Class
+Class PupilName? inheritance?11
+Sub New(parameter definitionsparameter definitions?)
12
Me.tutorvariableName? = New Maybe(Of Teacher)()value or expression? ' reassign variable13
End Sub
Property tutorname? As Maybe(Of Teacher)Type?14
+Function toStringname?(parameter definitionsparameter definitions?) As StringType?
15
Return "undefined"value or expression?16
End Function
End Class
public class Global {
+static void main() {
1
var tTomname? = new Teacher()value or expression?;2
var pPetename? = new Pupil()value or expression?;3
+if (pPete.tutor.hasValue()condition?) {
4
System.out.println(pPete.tutorarguments?); // print5
} // if
System.out.println(parguments?); // print6
} // main
+class TeacherName? inheritance? {7
+public Teacher(parameter definitionsparameter definitions?) {
8
new code
} // constructor
+public StringType? toStringname?(parameter definitionsparameter definitions?) {
// function method9
return String.format("%", this)value or expression?;10
} // function method
} // class
+class PupilName? inheritance? {11
+public Pupil(parameter definitionsparameter definitions?) {
12
this.tutorvariableName? = new Maybe<Teacher>()value or expression?; // reassign variable13
} // constructor
public Maybe<Teacher>Type? tutorname?; // property14
+public StringType? toStringname?(parameter definitionsparameter definitions?) {
// function method15
return "undefined"value or expression?;16
} // function method
} // class
}
function method
A function method follows the same syntax and rules as a global function . The differences are:
- A
functionfunctionfunctionfunctionfunction method is always referenced (used) by code outside the class using dot syntax on an instance.
- A
functionfunctionfunctionfunctionfunction method may directly reference (read only) any property defined on the class as though it were a variable or parameter.
- A
functionfunctionfunctionfunctionfunction method may be marked privateprivateprivateprivateprivate, in which case it is visible only to code within the class and, if defined on abstract class AAAAA, within its subclasses.
This is done by selecting the property instruction and then keying Ctrl+p. (Pressing these keys again will remove the privateprivateprivateprivateprivate modifier).
- toString method is just a regular function method with the specific name, takes no parameters and and returns a value of type
StringstrstringStringString.
If defined for a class then, if an instance of the class is printed, function method toString will automatically be used.
Typically toString will return a string made up of one or more of the property values, perhaps with additional text, or the results of function calls.
procedure method
A 'procedure method' follows the same syntax and rules as a global procedure . The differences are:
- A procedure method, like a function method, is always referenced (used) by code outside the class using dot syntax on an instance.
- A procedure method may read, or write to, any property defined on the class.
- A procedure method may be marked
privateprivateprivateprivateprivate, in which case it is visible only to code within the class and, if defined on an abstract classclassclassclassclass, within its subclasses.
This is done by selecting the property instruction and then keying Ctrl+p. (Pressing these keys again will remove the privateprivateprivateprivateprivate modifier).
abstract property
An abstract propertypropertypropertypropertyproperty may be defined only on an abstract class . Any concrete subclass must then implement a concrete (regular) property to match.
abstract function
An abstract function method may be defined only on an abstract class . Any concrete subclass must then implement a concrete (regular) function to match.
abstract procedure
An abstract procedure method may be defined only on an abstract class . Any concrete subclass must then implement a concrete (regular) procedure to match.
private (property, function, procedure)
A property may be marked private, in which case it is visible only to code within the class and,
if defined on an abstract class, within its subclasses.
This is done by using the context menu on the property instruction or selecting it and keying Ctrl+p.
This action is a toggle used both to reassign and to remove the modifier private.
- A property that is not private may be read, but not written to.
- A property that is private may
- Whenever you wish to access a property from within a method (or from within the constructor) on the same class, then the name of the property must be prefixed with the 'qualifier':
propertypropertypropertypropertyproperty.('property-dot'). This applies whether you are reading or setting the property. By this means you can have a method parameter with the same name as a property, but they are unambiguous, because the property must be prefixed. A common pattern is to use the same name in a 'setter' method, for example:
+class GameName? inheritance?1
+constructor(board as Boardparameter definitions?)
2
reassign this.boardvariableName? to boardvalue or expression?3
end constructor
+procedure setHeightname?(height as Intparameter definitions?)
4
reassign this.heightvariableName? to heightvalue or expression?5
end procedure
+function toStringname?(parameter definitions?) returns StringType?
6
return "undefined"value or expression?7
end function
end class
+class GameName? inheritance? # concrete class1
+def __init__(self: Game, board: Boardparameter definitions?) -> None:
2
self.boardvariableName? = boardvalue or expression? # reassign variable3
+def setHeightname?(self: Game, height: intparameter definitions?) -> None:
# procedure method4
self.heightvariableName? = heightvalue or expression? # reassign variable5
+def toStringname?(self: Game) -> strType?:
# function method6
return "undefined"value or expression?7
+class GameName? inheritance? {1
+public Game(Board boardparameter definitions?) {
2
this.boardvariableName? = boardvalue or expression?; // reassign variable3
} // constructor
+public void setHeightname?(int heightparameter definitions?) {
// procedure method4
this.heightvariableName? = heightvalue or expression?; // reassign variable5
} // procedure method
+public stringType? toStringname?(parameter definitions?) {
// function method6
return "undefined"value or expression?;7
} // function method
} // class
+Class GameName? inheritance?1
+Sub New(board As Boardparameter definitions?)
2
Me.boardvariableName? = boardvalue or expression? ' reassign variable3
End Sub
+Sub setHeightname?(height As Integerparameter definitions?)
' procedure method4
Me.heightvariableName? = heightvalue or expression? ' reassign variable5
End Sub
+Function toStringname?(parameter definitions?) As StringType?
6
Return "undefined"value or expression?7
End Function
End Class
public class Global {
+class GameName? inheritance? {1
+public Game(Board boardparameter definitions?) {
2
this.boardvariableName? = boardvalue or expression?; // reassign variable3
} // constructor
+public void setHeightname?(int heightparameter definitions?) {
// procedure method4
this.heightvariableName? = heightvalue or expression?; // reassign variable5
} // procedure method
+public StringType? toStringname?(parameter definitions?) {
// function method6
return "undefined"value or expression?;7
} // function method
} // class
}
Statement instructions
Statement instructions (sometimes referred to as 'statements') are the imperative instructions used in the methods (procedural logic) of a program.They are:
variable definition ,
reassign variable ,
if ,
while loop ,
for loop ,
call procedure ,
try ,
throw
and, within a test, assert equal .
variable definition
The variable definition .. set to .. instruction declares and initialises
a mutable named valued. The name defined must be a valid identifier .>/p>
The initial value is given by a following expression. For example:
variable notename? set to 440value or expression?0notename? = 440value or expression? # variable definition0var notename? = 440value or expression?;0Dim notename? = 440value or expression? ' variable definition0var notename? = 440value or expression?;0
reassign variable
The reassign avariableName? to bvalue or expression?0avariableName? = bvalue or expression? # reassign variable0avariableName? = bvalue or expression?; // reassign variable0avariableName? = bvalue or expression? ' reassign variable0avariableName? = bvalue or expression?; // reassign variable0 instruction assigns a new value to an existing named value:
the value in bbbbb is copied into the named value aaaaa
The two named values must be of the same Type.
A reassign variable instruction may not assign a new value to a parameter within a procedure.
To change the value of an argument supplied in a procedure call, the corresponding parameter must have been defined as of type AsRefAsRefAsRefAsRefAsRef,
which then allows use of the dot method set on it. See Call by reference
if (instruction)
The if instruction specifies which of several code sequences is to be executed next.
- It is structured like this:
+if (x < 1)condition? then
0
reassign xvariableName? to 1value or expression?1
elif x < 2condition? then2
reassign xvariableName? to 2value or expression?3
elif x < 3condition? then4
reassign xvariableName? to 3value or expression?5
else6
reassign xvariableName? to 0value or expression?7
end if
+if (x < 1)condition?:
0
xvariableName? = 1value or expression? # reassign variable1
elif x < 2condition?: # else if2
xvariableName? = 2value or expression? # reassign variable3
elif x < 3condition?: # else if4
xvariableName? = 3value or expression? # reassign variable5
else:6
xvariableName? = 0value or expression? # reassign variable7
+if ((x < 1)condition?) {
0
xvariableName? = 1value or expression?; // reassign variable1
} else if (x < 2condition?) {2
xvariableName? = 2value or expression?; // reassign variable3
} else if (x < 3condition?) {4
xvariableName? = 3value or expression?; // reassign variable5
} else {6
xvariableName? = 0value or expression?; // reassign variable7
} // if
+If (x < 1)condition? Then
0
xvariableName? = 1value or expression? ' reassign variable1
ElseIf x < 2condition? Then2
xvariableName? = 2value or expression? ' reassign variable3
ElseIf x < 3condition? Then4
xvariableName? = 3value or expression? ' reassign variable5
Else6
xvariableName? = 0value or expression? ' reassign variable7
End If
+if ((x < 1)condition?) {
0
xvariableName? = 1value or expression?; // reassign variable1
} else if (x < 2condition?) {2
xvariableName? = 2value or expression?; // reassign variable3
} else if (x < 3condition?) {4
xvariableName? = 3value or expression?; // reassign variable5
} else {6
xvariableName? = 0value or expression?; // reassign variable7
} // if
- The conditions, one of which is shown above enclosed in brackets, are Boolean values or expressions.
- else if and else clauses are optional.
- You can add as many else if clauses as you wish, but only one unconditional else which, if present, must be last.
See also if (expression) for using the related if to return a value.
Examples using if instruction
● Simple choice between equality and inequality:
+if head is applecondition? then
0
call setAppleToRandomPositionprocedureName?(apple, bodyarguments?)1
else2
call body.removeAtprocedureName?(0arguments?)3
end if
+if head == applecondition?:
0
setAppleToRandomPositionprocedureName?(apple, bodyarguments?) # call procedure1
else:2
body.removeAtprocedureName?(0arguments?) # call procedure3
+if (head == applecondition?) {
0
setAppleToRandomPositionprocedureName?(apple, bodyarguments?); // call procedure1
} else {2
body.removeAtprocedureName?(0arguments?); // call procedure3
} // if
+If head = applecondition? Then
0
setAppleToRandomPositionprocedureName?(apple, bodyarguments?) ' call procedure1
Else2
body.removeAtprocedureName?(0arguments?) ' call procedure3
End If
+if (head == applecondition?) {
0
setAppleToRandomPositionprocedureName?(apple, bodyarguments?); // call procedure1
} else {2
body.removeAtprocedureName?(0arguments?); // call procedure3
} // if
● Choice between an equality, a Boolean and the alternative:
+main
1
variable resultname? set to falsevalue or expression?2
+if item.equals(value)condition? then
3
reassign resultvariableName? to truevalue or expression?4
elif item.isBefore(value)condition? then5
reassign resultvariableName? to binarySearch(li.subList(0, mid), item)value or expression?6
else7
reassign resultvariableName? to binarySearch(li.subList(mid + 1, li.length()), item)value or expression?8
end if
end main
+def main() -> None:
1
resultname? = Falsevalue or expression? # variable definition2
+if item.equals(value)condition?:
3
resultvariableName? = Truevalue or expression? # reassign variable4
elif item.isBefore(value)condition?: # else if5
resultvariableName? = binarySearch(li.subList(0, mid), item)value or expression? # reassign variable6
else:7
resultvariableName? = binarySearch(li.subList(mid + 1, li.length()), item)value or expression? # reassign variable8
main()
+static void main() {
1
var resultname? = falsevalue or expression?;2
+if (item.equals(value)condition?) {
3
resultvariableName? = truevalue or expression?; // reassign variable4
} else if (item.isBefore(value)condition?) {5
resultvariableName? = binarySearch(li.subList(0, mid), item)value or expression?; // reassign variable6
} else {7
resultvariableName? = binarySearch(li.subList(mid + 1, li.length()), item)value or expression?; // reassign variable8
} // if
} // main
+Sub main()
1
Dim resultname? = Falsevalue or expression? ' variable definition2
+If item.equals(value)condition? Then
3
resultvariableName? = Truevalue or expression? ' reassign variable4
ElseIf item.isBefore(value)condition? Then5
resultvariableName? = binarySearch(li.subList(0, mid), item)value or expression? ' reassign variable6
Else7
resultvariableName? = binarySearch(li.subList(mid + 1, li.length()), item)value or expression? ' reassign variable8
End If
End Sub
public class Global {
+static void main() {
1
var resultname? = falsevalue or expression?;2
+if (item.equals(value)condition?) {
3
resultvariableName? = truevalue or expression?; // reassign variable4
} else if (item.isBefore(value)condition?) {5
resultvariableName? = binarySearch(li.subList(0, mid), item)value or expression?; // reassign variable6
} else {7
resultvariableName? = binarySearch(li.subList(mid + 1, li.length()), item)value or expression?; // reassign variable8
} // if
} // main
}
while loop
The while loop construct provides a conditional loop, used when you want execution of the enclosed instructions to begin
only if some condition is true.
The condition is either a BooleanboolboolBooleanbool variable or an expression that evaluates to a BooleanboolboolBooleanbool value.
The value of the condition must a some point become false otherwise the loop will not terminate and exit.
While the condition is true the enclosed code is executed;
when false the loop is bypassed. For example:
+main
1
variable filename? set to openFileForReading()value or expression?2
+while not file.endOfFile()condition?
3
print(file.readLine()arguments?)4
end while
call file.closeprocedureName?(arguments?)5
end main
+def main() -> None:
1
filename? = openFileForReading()value or expression? # variable definition2
+while not file.endOfFile()condition?:
3
print(file.readLine()arguments?)4
file.closeprocedureName?(arguments?) # call procedure5
main()
+static void main() {
1
var filename? = openFileForReading()value or expression?;2
+while (!file.endOfFile()condition?) {
3
Console.WriteLine(file.readLine()arguments?); // print4
} // while
file.closeprocedureName?(arguments?); // call procedure5
} // main
+Sub main()
1
Dim filename? = openFileForReading()value or expression? ' variable definition2
+While Not file.endOfFile()condition?
3
Console.WriteLine(file.readLine()arguments?) ' print4
End While
file.closeprocedureName?(arguments?) ' call procedure5
End Sub
public class Global {
+static void main() {
1
var filename? = openFileForReading()value or expression?;2
+while (!file.endOfFile()condition?) {
3
System.out.println(file.readLine()arguments?); // print4
} // while
file.closeprocedureName?(arguments?); // call procedure5
} // main
}
for loop
The construct
+for pitem? in qsource?
0
new code
end for
+for pitem? in qsource?:
0
new code
+foreach (pitem? in qsource?) {
0
new code
} // foreach
+For Each pitem? In qsource?
0
new code
Next p
+foreach (pitem? in qsource?) {
0
new code
} // foreach
specifies looping through a sequence either of characters in a StringstrstringStringString, or of items in a ListlistListListList.
The loop variable p does not have to have been previously declared or initialised.
Examples using the for loop
● The loop variable n is of the type of a List's items (here IntintintIntegerint),
and each integer in the List primes is in turn put into n:
+procedure printPrimesname?(parameter definitionsparameter definitions?)
1
variable primesname? set to [2, 3, 5, 7, 11]value or expression?2
+for nitem? in primessource?
3
print(narguments?)4
end for
end procedure
+def printPrimesname?(parameter definitionsparameter definitions?) -> None:
# procedure1
primesname? = [2, 3, 5, 7, 11]value or expression? # variable definition2
+for nitem? in primessource?:
3
print(narguments?)4
+static void printPrimesname?(parameter definitionsparameter definitions?) {
// procedure1
var primesname? = [2, 3, 5, 7, 11]value or expression?;2
+foreach (nitem? in primessource?) {
3
Console.WriteLine(narguments?); // print4
} // foreach
} // procedure
+Sub printPrimesname?(parameter definitionsparameter definitions?)
' procedure1
Dim primesname? = {2, 3, 5, 7, 11}value or expression? ' variable definition2
+For Each nitem? In primessource?
3
Console.WriteLine(narguments?) ' print4
Next n
End Sub
public class Global {
+static void printPrimesname?(parameter definitionsparameter definitions?) {
// procedure1
var primesname? = [2, 3, 5, 7, 11]value or expression?;2
+foreach (nitem? in primessource?) {
3
System.out.println(narguments?); // print4
} // foreach
} // procedure
}
● The loop variable fruit is of the type of a List's items (here StringstrstringStringString).
and each String in the List basket is in turn put into fruit:
+main
1
variable basketname? set to ["apple", "banana", "cherry", "date"]value or expression?2
+for fruititem? in basketsource?
3
print(fruitarguments?)4
end for
end main
+def main() -> None:
1
basketname? = ["apple", "banana", "cherry", "date"]value or expression? # variable definition2
+for fruititem? in basketsource?:
3
print(fruitarguments?)4
main()
+static void main() {
1
var basketname? = ["apple", "banana", "cherry", "date"]value or expression?;2
+foreach (fruititem? in basketsource?) {
3
Console.WriteLine(fruitarguments?); // print4
} // foreach
} // main
+Sub main()
1
Dim basketname? = {"apple", "banana", "cherry", "date"}value or expression? ' variable definition2
+For Each fruititem? In basketsource?
3
Console.WriteLine(fruitarguments?) ' print4
Next fruit
End Sub
public class Global {
+static void main() {
1
var basketname? = ["apple", "banana", "cherry", "date"]value or expression?;2
+foreach (fruititem? in basketsource?) {
3
System.out.println(fruitarguments?); // print4
} // foreach
} // main
}
● To print first the keys and then the values from a DictionaryDictionaryDictionaryDictionaryDictionary:
+main
1
variable diname? set to ["A":1, "B":2, "C":3]value or expression?2
+for sitem? in di.keys()source?
3
print(sarguments?)4
end for
+for nitem? in di.values()source?
5
print(narguments?)6
end for
end main
+def main() -> None:
1
diname? = ["A":1, "B":2, "C":3]value or expression? # variable definition2
+for sitem? in di.keys()source?:
3
print(sarguments?)4
+for nitem? in di.values()source?:
5
print(narguments?)6
main()
+static void main() {
1
var diname? = ["A":1, "B":2, "C":3]value or expression?;2
+foreach (sitem? in di.keys()source?) {
3
Console.WriteLine(sarguments?); // print4
} // foreach
+foreach (nitem? in di.values()source?) {
5
Console.WriteLine(narguments?); // print6
} // foreach
} // main
+Sub main()
1
Dim diname? = ["A":1, "B":2, "C":3]value or expression? ' variable definition2
+For Each sitem? In di.keys()source?
3
Console.WriteLine(sarguments?) ' print4
Next s
+For Each nitem? In di.values()source?
5
Console.WriteLine(narguments?) ' print6
Next n
End Sub
public class Global {
+static void main() {
1
var diname? = ["A":1, "B":2, "C":3]value or expression?;2
+foreach (sitem? in di.keys()source?) {
3
System.out.println(sarguments?); // print4
} // foreach
+foreach (nitem? in di.values()source?) {
5
System.out.println(narguments?); // print6
} // foreach
} // main
}
● Function to reverse a StringstrstringStringString:
+main
1
print(reverse("stressed")arguments?)2
end main
+function reversename?(s as Stringparameter definitions?) returns StringType?
3
variable sReturnname? set to ""value or expression?4
+for chitem? in ssource?
5
reassign sReturnvariableName? to ch + sReturnvalue or expression?6
end for
return sReturnvalue or expression?7
end function
+def main() -> None:
1
print(reverse("stressed")arguments?)2
+def reversename?(s: strparameter definitions?) -> strType?:
# function3
sReturnname? = ""value or expression? # variable definition4
+for chitem? in ssource?:
5
sReturnvariableName? = ch + sReturnvalue or expression? # reassign variable6
return sReturnvalue or expression?7
main()
+static void main() {
1
Console.WriteLine(reverse("stressed")arguments?); // print2
} // main
+static stringType? reversename?(string sparameter definitions?) {
// function3
var sReturnname? = ""value or expression?;4
+foreach (chitem? in ssource?) {
5
sReturnvariableName? = ch + sReturnvalue or expression?; // reassign variable6
} // foreach
return sReturnvalue or expression?;7
} // function
+Sub main()
1
Console.WriteLine(reverse("stressed")arguments?) ' print2
End Sub
+Function reversename?(s As Stringparameter definitions?) As StringType?
3
Dim sReturnname? = ""value or expression? ' variable definition4
+For Each chitem? In ssource?
5
sReturnvariableName? = ch + sReturnvalue or expression? ' reassign variable6
Next ch
Return sReturnvalue or expression?7
End Function
public class Global {
+static void main() {
1
System.out.println(reverse("stressed")arguments?); // print2
} // main
+static StringType? reversename?(String sparameter definitions?) {
// function3
var sReturnname? = ""value or expression?;4
+foreach (chitem? in ssource?) {
5
sReturnvariableName? = ch + sReturnvalue or expression?; // reassign variable6
} // foreach
return sReturnvalue or expression?;7
} // function
}
● Alternatively the loop variable may be defined as an integer range using methods range and
rangeInSteps in order to index into a subject List:
+main
1
variable numbersname? set to ["zero", "one", "two", "three", "four", "five", "six"]value or expression?2
+for nitem? in range(2, 6)source?
3
print(numbers[n]arguments?)4
end for
end main
+def main() -> None:
1
numbersname? = ["zero", "one", "two", "three", "four", "five", "six"]value or expression? # variable definition2
+for nitem? in range(2, 6)source?:
3
print(numbers[n]arguments?)4
main()
+static void main() {
1
var numbersname? = ["zero", "one", "two", "three", "four", "five", "six"]value or expression?;2
+foreach (nitem? in range(2, 6)source?) {
3
Console.WriteLine(numbers[n]arguments?); // print4
} // foreach
} // main
+Sub main()
1
Dim numbersname? = {"zero", "one", "two", "three", "four", "five", "six"}value or expression? ' variable definition2
+For Each nitem? In range(2, 6)source?
3
Console.WriteLine(numbers[n]arguments?) ' print4
Next n
End Sub
public class Global {
+static void main() {
1
var numbersname? = ["zero", "one", "two", "three", "four", "five", "six"]value or expression?;2
+foreach (nitem? in range(2, 6)source?) {
3
System.out.println(numbers[n]arguments?); // print4
} // foreach
} // main
}
Technical note about the for loop variable
● The for instruction creates its own working copy of the values through which to loop sequentially.
So even if the loop variable is changed in any way within the for loop, this will not affect which subject items are referred to.
It is therefore recommended never to reassign the loop variable within the loop.
call procedure
The call procedure instruction is used when you want to run a procedure .
The procedure may be:
- a procedure that you have defined at the global level
call fillRandomprocedureName?(gridarguments?)0fillRandomprocedureName?(gridarguments?) # call procedure0fillRandomprocedureName?(gridarguments?); // call procedure0fillRandomprocedureName?(gridarguments?) ' call procedure0fillRandomprocedureName?(gridarguments?); // call procedure0
- a procedure method on an object of a class that you have defined
call apple.newRandomPositionprocedureName?(snakearguments?)0apple.newRandomPositionprocedureName?(snakearguments?) # call procedure0apple.newRandomPositionprocedureName?(snakearguments?); // call procedure0apple.newRandomPositionprocedureName?(snakearguments?) ' call procedure0apple.newRandomPositionprocedureName?(snakearguments?); // call procedure0
- a procedure method that belongs to the same class as the procedure that you are calling from
call updateNeighboursprocedureName?(arguments?)0updateNeighboursprocedureName?(arguments?) # call procedure0updateNeighboursprocedureName?(arguments?); // call procedure0updateNeighboursprocedureName?(arguments?) ' call procedure0updateNeighboursprocedureName?(arguments?); // call procedure0
- a procedure provided by the standard library
call sleep_msprocedureName?(2000arguments?)0sleep_msprocedureName?(2000arguments?) # call procedure0sleep_msprocedureName?(2000arguments?); // call procedure0sleep_msprocedureName?(2000arguments?) ' call procedure0sleep_msprocedureName?(2000arguments?); // call procedure0
- a procedure method on an object of a type provided by the standard library
call vg.appendprocedureName?(rectarguments?)0vg.appendprocedureName?(rectarguments?) # call procedure0vg.appendprocedureName?(rectarguments?); // call procedure0vg.appendprocedureName?(rectarguments?) ' call procedure0vg.appendprocedureName?(rectarguments?); // call procedure0
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.
An argument whose value is changed by the procedure must be:
- either a mutable data structure (List or Dictionary)
- or a Ref reference to a named value Type
- or a Ref reference to an immutable data structure (Set, Stack or Queue)
For procedures that you define yourself, any argument whose value is changed must be of a mutable Type.
An expression of the correct type can be used as an argument, but its value cannot be changed in the procedure.
Procedures may have side effects, for example input/output or changing a data value in an object.
They can change the contents of any mutable object passed in as an argument.
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 .
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.
Examples using try
● To check a function input, and throw an exception up:
+main
1
+try
2
variable tname? set to foo(true)value or expression?3
print("no error"arguments?)4
catch errvariableName? as CustomErrortype e.g. ElanRuntimeError or CustomError?5
print(errarguments?)6
end try
end main
+function fooname?(torf as Booleanparameter definitions?) returns BooleanType?
7
+if torfcondition? then
8
throw CustomErrorexception type? "error in foo()"message?9
end if
return torfvalue or expression?10
end function
+def main() -> None:
1
+try:
2
tname? = foo(True)value or expression? # variable definition3
print("no error"arguments?)4
except CustomErrortype e.g. ElanRuntimeError or CustomError? as errvariableName?: # catch5
print(errarguments?)6
+def fooname?(torf: boolparameter definitions?) -> boolType?:
# function7
+if torfcondition?:
8
raise CustomErrorexception type?("error in foo()"message?)9
return torfvalue or expression?10
main()
+static void main() {
1
+try {
2
var tname? = foo(true)value or expression?;3
Console.WriteLine("no error"arguments?); // print4
} catch (CustomErrortype e.g. ElanRuntimeError or CustomError? errvariableName?) {5
Console.WriteLine(errarguments?); // print6
} // try
} // main
+static boolType? fooname?(bool torfparameter definitions?) {
// function7
+if (torfcondition?) {
8
throw new CustomErrorexception type?("error in foo()"message?);9
} // if
return torfvalue or expression?;10
} // function
+Sub main()
1
+Try
2
Dim tname? = foo(True)value or expression? ' variable definition3
Console.WriteLine("no error"arguments?) ' print4
Catch errvariableName? As CustomErrortype e.g. ElanRuntimeError or CustomError?5
Console.WriteLine(errarguments?) ' print6
End Try
End Sub
+Function fooname?(torf As Booleanparameter definitions?) As BooleanType?
7
+If torfcondition? Then
8
Throw New CustomErrorexception type?("error in foo()"message?)9
End If
Return torfvalue or expression?10
End Function
public class Global {
+static void main() {
1
+try {
2
var tname? = foo(true)value or expression?;3
System.out.println("no error"arguments?); // print4
} catch (CustomErrortype e.g. ElanRuntimeError or CustomError? errvariableName?) {5
System.out.println(errarguments?); // print6
} // try
} // main
+static boolType? fooname?(bool torfparameter definitions?) {
// function7
+if (torfcondition?) {
8
throw new CustomErrorexception type?("error in foo()"message?);9
} // if
return torfvalue or expression?;10
} // function
}
When foo is given argument true, output is "error in foo()"; when given false, output is "no error".
● To stop the program if one of two points (each a Tuple) has negative x or y:
+main
1
variable aname? set to (1.0, 2.0)value or expression?2
variable bname? set to (3.0, -6.0)value or expression?3
variable fQname? set to firstQuadrant(a, b)value or expression?4
end main
+function firstQuadrantname?(a as (Float, Float), b as (Float, Float)parameter definitions?) returns FloatType?
5
+if (a.item_0 < 0) or (a.item_1 < 0) or (b.item_0 < 0) or (b.item_1 < 0)condition? then
6
throw CustomErrorexception type? $"point {a} or (b} is not in the first quadrant"message?7
end if
return 0value or expression?8
end function
+def main() -> None:
1
aname? = (1.0, 2.0)value or expression? # variable definition2
bname? = (3.0, -6.0)value or expression? # variable definition3
fQname? = firstQuadrant(a, b)value or expression? # variable definition4
+def firstQuadrantname?(a: tuple[float, float], b: tuple[float, float]parameter definitions?) -> floatType?:
# function5
+if (a.item_0 < 0) or (a.item_1 < 0) or (b.item_0 < 0) or (b.item_1 < 0)condition?:
6
raise CustomErrorexception type?(f"point {a} or (b} is not in the first quadrant"message?)7
return 0value or expression?8
main()
+static void main() {
1
var aname? = (1.0, 2.0)value or expression?;2
var bname? = (3.0, -6.0)value or expression?;3
var fQname? = firstQuadrant(a, b)value or expression?;4
} // main
+static doubleType? firstQuadrantname?((double, double) a, (double, double) bparameter definitions?) {
// function5
+if ((a.item_0 < 0) || (a.item_1 < 0) || (b.item_0 < 0) || (b.item_1 < 0)condition?) {
6
throw new CustomErrorexception type?($"point {a} or (b} is not in the first quadrant"message?);7
} // if
return 0value or expression?;8
} // function
+Sub main()
1
Dim aname? = (1.0, 2.0)value or expression? ' variable definition2
Dim bname? = (3.0, -6.0)value or expression? ' variable definition3
Dim fQname? = firstQuadrant(a, b)value or expression? ' variable definition4
End Sub
+Function firstQuadrantname?(a As (Double, Double), b As (Double, Double)parameter definitions?) As DoubleType?
5
+If (a.item_0 < 0) Or (a.item_1 < 0) Or (b.item_0 < 0) Or (b.item_1 < 0)condition? Then
6
Throw New CustomErrorexception type?($"point {a} or (b} is not in the first quadrant"message?)7
End If
Return 0value or expression?8
End Function
public class Global {
+static void main() {
1
var aname? = (1.0, 2.0)value or expression?;2
var bname? = (3.0, -6.0)value or expression?;3
var fQname? = firstQuadrant(a, b)value or expression?;4
} // main
+static doubleType? firstQuadrantname?((double, double) a, (double, double) bparameter definitions?) {
// function5
+if ((a.item_0 < 0) || (a.item_1 < 0) || (b.item_0 < 0) || (b.item_1 < 0)condition?) {
6
throw new CustomErrorexception type?(String.format("point % or (b} is not in the first quadrant", a)message?);7
} // if
return 0value or expression?;8
} // function
}
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 using throw exception
● To stop the program if a value calculated in a function is out of range:
+main
1
print($"{percent(23, 20)}" + "%"arguments?)2
end main
+function percentname?(value as Float, maximum as Floatparameter definitions?) returns FloatType?
3
+if value > maximumcondition? then
4
throw ElanRuntimeErrorexception type? "proportion exceeds 100%"message?5
end if
return value/maximum*100value or expression?6
end function
+def main() -> None:
1
print(f"{percent(23, 20)}" + "%"arguments?)2
+def percentname?(value: float, maximum: floatparameter definitions?) -> floatType?:
# function3
+if value > maximumcondition?:
4
raise ElanRuntimeErrorexception type?("proportion exceeds 100%"message?)5
return value/maximum*100value or expression?6
main()
+static void main() {
1
Console.WriteLine($"{percent(23, 20)}" + "%"arguments?); // print2
} // main
+static doubleType? percentname?(double value, double maximumparameter definitions?) {
// function3
+if (value > maximumcondition?) {
4
throw new ElanRuntimeErrorexception type?("proportion exceeds 100%"message?);5
} // if
return value/maximum*100value or expression?;6
} // function
+Sub main()
1
Console.WriteLine($"{percent(23, 20)}" + "%"arguments?) ' print2
End Sub
+Function percentname?(value As Double, maximum As Doubleparameter definitions?) As DoubleType?
3
+If value > maximumcondition? Then
4
Throw New ElanRuntimeErrorexception type?("proportion exceeds 100%"message?)5
End If
Return value/maximum*100value or expression?6
End Function
public class Global {
+static void main() {
1
System.out.println(String.formatarguments?); // print2
} // main
+static doubleType? percentname?(double value, double maximumparameter definitions?) {
// function3
+if (value > maximumcondition?) {
4
throw new ElanRuntimeErrorexception type?("proportion exceeds 100%"message?);5
} // if
return value/maximum*100value or expression?;6
} // function
}
At runtime, if the condition is met, execution will stop and the display will show:
proportion exceeds 100%
Error
assert
The assert equal instruction is used only within a test ,
which is the mechanism for running unit tests during program development, not during program execution.
Some programming languages have a feature for making assertions while your program is running.
In Elan, you can get equivalent functionality by throwing an exception, as described in the throw exception instruction.
let statement
Of use only in testtesttesttesttest instructions and in Functional Programming functions letletletletlet is used to define constant values defined by expressions (or literals).
The let statement instruction declares and initialises an immutable named value whose scope is confined to the function.
The name defined must be a valid identifier .
You can declare a such a constant within a loop, so that the named value gets a new value each time it is executed, but its value cannot be changed in any other way.
Unlike a global constant , the value assigned in a let statement may be any value, literal or expression:
+function numbersname?(parameter definitionsparameter definitions?) returns (Float, Float)Type?
1
let tauname? be 2*pivalue or expression?2
let phiname? be (1 + sqrt(5))/2value or expression?3
return (tau, phi)value or expression?4
end function
+def numbersname?(parameter definitionsparameter definitions?) -> tuple[float, float]Type?:
# function1
tauname? = 2*pivalue or expression? # let2
phiname? = (1 + sqrt(5))/2value or expression? # let3
return (tau, phi)value or expression?4
+static (double, double)Type? numbersname?(parameter definitionsparameter definitions?) {
// function1
var tauname? = 2*pivalue or expression?; // let2
var phiname? = (1 + sqrt(5))/2value or expression?; // let3
return (tau, phi)value or expression?;4
} // function
+Function numbersname?(parameter definitionsparameter definitions?) As (Double, Double)Type?
1
Dim tauname? = 2*pivalue or expression? ' let2
Dim phiname? = (1 + sqrt(5))/2value or expression? ' let3
Return (tau, phi)value or expression?4
End Function
public class Global {
+static (double, double)Type? numbersname?(parameter definitionsparameter definitions?) {
// function1
var tauname? = 2*pivalue or expression?; // let2
var phiname? = (1 + sqrt(5))/2value or expression?; // let3
return (tau, phi)value or expression?;4
} // function
}
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
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 aname? set to "Hello world!"value or expression?2
print(a[4]arguments?)3
print(a.subString(4, a.length())arguments?)4
print(a.subString(0, 7)arguments?)5
end main
+def main() -> None:
1
aname? = "Hello world!"value or expression? # variable definition2
print(a[4]arguments?)3
print(a.subString(4, a.length())arguments?)4
print(a.subString(0, 7)arguments?)5
main()
+static void main() {
1
var aname? = "Hello world!"value or expression?;2
Console.WriteLine(a[4]arguments?); // print3
Console.WriteLine(a.subString(4, a.length())arguments?); // print4
Console.WriteLine(a.subString(0, 7)arguments?); // print5
} // main
+Sub main()
1
Dim aname? = "Hello world!"value or expression? ' variable definition2
Console.WriteLine(a[4]arguments?) ' print3
Console.WriteLine(a.subString(4, a.length())arguments?) ' print4
Console.WriteLine(a.subString(0, 7)arguments?) ' print5
End Sub
public class Global {
+static void main() {
1
var aname? = "Hello world!"value or expression?;2
System.out.println(a[4]arguments?); // print3
System.out.println(a.subString(4, a.length())arguments?); // print4
System.out.println(a.subString(0, 7)arguments?); // print5
} // main
}
|
⟶ ⟶ ⟶ |
o o world! Hello w (since the upper bound of a range is exclusive) |
And on a list:
+main
1
variable liname? set to new List<of Int>()value or expression?2
reassign livariableName? to [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]value or expression?3
print(li[4]arguments?)4
print(li.subList(4, li.length())arguments?)5
print(li.subList(0, 7)arguments?)6
end main
+def main() -> None:
1
liname? = list[int]()value or expression? # variable definition2
livariableName? = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]value or expression? # reassign variable3
print(li[4]arguments?)4
print(li.subList(4, li.length())arguments?)5
print(li.subList(0, 7)arguments?)6
main()
+static void main() {
1
var liname? = new List<int>()value or expression?;2
livariableName? = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]value or expression?; // reassign variable3
Console.WriteLine(li[4]arguments?); // print4
Console.WriteLine(li.subList(4, li.length())arguments?); // print5
Console.WriteLine(li.subList(0, 7)arguments?); // print6
} // main
+Sub main()
1
Dim liname? = New List(Of Integer)()value or expression? ' variable definition2
livariableName? = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}value or expression? ' reassign variable3
Console.WriteLine(li[4]arguments?) ' print4
Console.WriteLine(li.subList(4, li.length())arguments?) ' print5
Console.WriteLine(li.subList(0, 7)arguments?) ' print6
End Sub
public class Global {
+static void main() {
1
var liname? = new List<int>()value or expression?;2
livariableName? = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]value or expression?; // reassign variable3
System.out.println(li[4]arguments?); // print4
System.out.println(li.subList(4, li.length())arguments?); // print5
System.out.println(li.subList(0, 7)arguments?); // print6
} // 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:
print(pow(4, 4)arguments?)0print(pow(4, 4)arguments?)0Console.WriteLine(pow(4, 4)arguments?); // print0Console.WriteLine(pow(4, 4)arguments?) ' print0System.out.println(pow(4, 4)arguments?); // print0
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:
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 exOrname?(a as Boolean, b as Booleanparameter definitions?) returns BooleanType?
1
return a and not b or b and not avalue or expression?2
end function
+def exOrname?(a: bool, b: boolparameter definitions?) -> boolType?:
# function1
return a and not b or b and not avalue or expression?2
+static boolType? exOrname?(bool a, bool bparameter definitions?) {
// function1
return a && !b || b && !avalue or expression?;2
} // function
+Function exOrname?(a As Boolean, b As Booleanparameter definitions?) As BooleanType?
1
Return a And Not b Or b And Not avalue or expression?2
End Function
public class Global {
+static boolType? exOrname?(bool a, bool bparameter definitions?) {
// function1
return a && !b || b && !avalue 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
print(sin(radians(30))arguments?)2
variable xname? set to pow(sin(radians(30)), 2) + pow(cos(radians(30)), 2)value or expression?3
variable namename? set to input("Your name")value or expression?4
print(name.upperCase()arguments?)5
end main
+def main() -> None:
1
print(sin(radians(30))arguments?)2
xname? = pow(sin(radians(30)), 2) + pow(cos(radians(30)), 2)value or expression? # variable definition3
namename? = input("Your name")value or expression? # variable definition4
print(name.upperCase()arguments?)5
main()
+static void main() {
1
Console.WriteLine(sin(radians(30))arguments?); // print2
var xname? = pow(sin(radians(30)), 2) + pow(cos(radians(30)), 2)value or expression?;3
var namename? = input("Your name")value or expression?;4
Console.WriteLine(name.upperCase()arguments?); // print5
} // main
+Sub main()
1
Console.WriteLine(sin(radians(30))arguments?) ' print2
Dim xname? = pow(sin(radians(30)), 2) + pow(cos(radians(30)), 2)value or expression? ' variable definition3
Dim namename? = input("Your name")value or expression? ' variable definition4
Console.WriteLine(name.upperCase()arguments?) ' print5
End Sub
public class Global {
+static void main() {
1
System.out.println(sin(radians(30))arguments?); // print2
var xname? = pow(sin(radians(30)), 2) + pow(cos(radians(30)), 2)value or expression?;3
var namename? = input("Your name")value or expression?;4
System.out.println(name.upperCase()arguments?); // print5
} // 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 fooname?(parameter definitionsparameter definitions?) returns IntType?
1
return if(isGreen(attempt, target, n), setChar(attempt, n, "*"), attempt)value or expression?2
end function
+def fooname?(parameter definitionsparameter definitions?) -> intType?:
# function1
return if(isGreen(attempt, target, n), setChar(attempt, n, "*"), attempt)value or expression?2
+static intType? fooname?(parameter definitionsparameter definitions?) {
// function1
return if(isGreen(attempt, target, n), setChar(attempt, n, "*"), attempt)value or expression?;2
} // function
+Function fooname?(parameter definitionsparameter definitions?) As IntegerType?
1
Return if(isGreen(attempt, target, n), setChar(attempt, n, "*"), attempt)value or expression?2
End Function
public class Global {
+static intType? fooname?(parameter definitionsparameter definitions?) {
// function1
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 pname? set to unicode(0x03c0)value or expression?2
call testPiprocedureName?(p, 3arguments?)3
call testPiprocedureName?(p, 4arguments?)4
end main
+procedure testPiname?(p as String, v as Floatparameter definitions?)
5
print(if(pi > v, $"{p} > {v}", $"{p} < {v}")arguments?)6
end procedure
+def main() -> None:
1
pname? = unicode(0x03c0)value or expression? # variable definition2
testPiprocedureName?(p, 3arguments?) # call procedure3
testPiprocedureName?(p, 4arguments?) # call procedure4
+def testPiname?(p: str, v: floatparameter definitions?) -> None:
# procedure5
print(if(pi > v, f"{p} > {v}", f"{p} < {v}")arguments?)6
main()
+static void main() {
1
var pname? = unicode(0x03c0)value or expression?;2
testPiprocedureName?(p, 3arguments?); // call procedure3
testPiprocedureName?(p, 4arguments?); // call procedure4
} // main
+static void testPiname?(string p, double vparameter definitions?) {
// procedure5
Console.WriteLine(if(pi > v, $"{p} > {v}", $"{p} < {v}")arguments?); // print6
} // procedure
+Sub main()
1
Dim pname? = unicode(&H03c0)value or expression? ' variable definition2
testPiprocedureName?(p, 3arguments?) ' call procedure3
testPiprocedureName?(p, 4arguments?) ' call procedure4
End Sub
+Sub testPiname?(p As String, v As Doubleparameter definitions?)
' procedure5
Console.WriteLine(if(pi > v, $"{p} > {v}", $"{p} < {v}")arguments?) ' print6
End Sub
public class Global {
+static void main() {
1
var pname? = unicode(0x03c0)value or expression?;2
testPiprocedureName?(p, 3arguments?); // call procedure3
testPiprocedureName?(p, 4arguments?); // call procedure4
} // main
+static void testPiname?(String p, double vparameter definitions?) {
// procedure5
System.out.println(arguments?); // print6
} // 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
# comment
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 is entered at any editor prompt by typing the hash symbol # 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 [.
Comments may be inserted at any level: in the Global ,
Member , or Statement instruction levels,
as well as from the new code prompt. Every prompt provides a commentcommentcommentcommentcomment option, namely a # symbol.
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' and shows the version of Elan being run.
Compile errors and warnings
Q: What is the difference between a compile error and a warning.
A: A warning usually indicates that the fix may involve adding some more code,
for example adding a definition for an unknown identifier. An error usually indicates
that you will need to alter code to fix the error.
But they are similar in that you will not be able to run your program until the issues are fixed. In all programming
languages it is a good practice 'treat all compile warnings as errors' i.e. fix them as soon as you see them appear.
Messages
Expression must be ...
An expression, when evaluated, results in a value of a type that is not compatible with its 'target',
for example: if the result of the expression is being assigned to an existing variable, or if an expression is defined 'inline' as
an argument into a method call.
Cannot use 'this' outside class context
thisthisthisthisthis may only be used within an instance method on a class to refer to the current instance.
Abstract class ... must be declared before it is used
If a class inherits from one or more abstract classes, then the latter must all have already been declared (defined) earlier in the code file.
Member ... must be of type ...
This error occurs when a class is defined as inheriting from an abstract class,
and has implemented an inherited member (method or property) with the correct name, but with different Types.
Incompatible types. Expected: ... Provided: ...
Cannot determine common type between ... and ...
... is not defined for type ...
Arises when 'dot calling' a member (method or property) that does not exist on the type of the named value or expression before the dot.
Cannot call a function as a procedure
A function (or function method) is to be used within an expression, not via a call procedure instruction.
Cannot use a system method in a function
A 'system method' (defined in the Standard Library) returns a value like a function does. However, because a system method
either makes changes to the system and/or depends on external inputs, it may be used only within a procedure or the main routine.
Code change required ...
Indicates that a library method or class has been changed since the version in which your Elan code was written. The link in the
message should take you directly to information in the Library Reference documentation on how to update your code to cope with the change.
Cannot call procedure ... within an expression
A procedure may be used only within a call procedure instruction.
Cannot invoke ... as a method
The code is attempting to use a free-standing method (function or procedure) as a 'dot method' on a named value or the result of an expression.
Cannot ...index ...
An index (in square brackets) may be applied only to certain data structure Types: StringstrstringStringString, ListlistListListList
and DictionaryDictionaryDictionaryDictionaryDictionary.
Cannot range ...
A range may be applied only to certain data structure Types: StringstrstringStringString and ListlistListListList.
Cannot new ...
The type specified after the call procedure instruction cannot be instantiated. Either the type is inapplicable,
or it is an abstract class.
May inherit from one abstract superclass only
The message is self explanatory.
class ... cannot inherit from itself
The message is self explanatory.
May inherit from one abstract superclass only.
The message is self explanatory.
Cannot reference private member ...
A private member (method or property) may be accessed only by code within the class, or within subclasses of it.
It may not be accessed by any code outside the class hierarchy.
... must implement ...
If a concrete class inherits from any abstract class it must implement all abstract methods defined in the abstract type (or in any super-type of the abstract class).
... must be concrete to new
You cannot create an instance of any abstract class: only of a concrete class.
Cannot call extension method directly
A method that is defined within the Library as an extension method, such as toString, may be called on a named
value or an expression only using dot syntax .
Cannot prefix function with 'property'
The prefix property. may only be used before a property name: not a function name.
Missing argument(s) ...
The method being called expects more arguments than have been provided.
A method has been passed more arguments than it expects.
Argument types ...
One or more arguments provided to the method are of the wrong Type.
...<of Type>...
Certain data structure Types, including ListlistListListList, must specify the type of their members, for example ListlistListListList<of IntintintIntegerint>.
Failure to specify the '<of Type>' on these Types will give an error, as will specifying 'of Type' where it is not required.
Dictionaries require Types to be specified for both the keys and the values,
for example: DictionaryDictionaryDictionaryDictionaryDictionary<of StringstrstringStringString, FloatfloatdoubleDoubledouble>.
May not reassign the ...
Attempting to reassign, or mutate, a named value that may not be reassigned in the current context.
Name ... not unique in scope ...
Attempting to create an identifier with the same name as one already defined within the same scope.
May not set ... in a function
A property can be reassigned only within a procedure method, not within a function, because reassigning a property is a side effect.
The identifier ... is already used for a ... and cannot be re-defined here.
An existing named value may not be defined again within the same scope.
Duplicate Dictionary key(s)
Attempting to define a literal DictionaryDictionaryDictionaryDictionaryDictionary
with one or more duplicated keys in the definition.
Library or class function ... cannot be used without brackets
a comment may not start with [ unless it is a recognised compiler directive
Compiler directives are a planned future capability. They will look like comments, but begin with an open square bracket.
To avoid the possibility of ambiguity, you may not start your own comments with an open square bracket.
Condition of 'if' expression does not evaluate to a Boolean.
Cannot have any clause after unconditional 'else'.
... is a reserved word, and may not be used as an identifier.
Most programming languages define keywords, or other 'reserved words' that may not be used as identifiers - for technical reasons.
Because Elan supports multiple programming languages and guarantees that any program written in one language
will convert correctly to the other languages, it must disallow the use of keywords from any
of the supported languages - not just the ones defined by the language you are writing. Fortunately many
of the keywords are common to more than one of the languages.
If you see this message, just alter the identifier you have defined - by extending the word, perhaps even just by adding an underscore -
or choose a different word altogether.
Index cannot be negative.
An index into a list cannot have a negative value. If a negative is given in literal form e.g.
a[−3] then this will generate a compile error.
If you use a named value for an index and it is negative, then this will cause a runtime error.
Cannot do equality operations on Procedures or Functions.
It is not possible to apply comparison operations to functions or procedures as themselves.
It is, however, possible to compare the results of two function evaluations.
You may see this message because you intended to evaluate a function but forgot to add the brackets after the name.
... cannot have key of type ...
The type of the key for any dictionary Dictionary must be an immutable Type, and not itself an indexable Type.
Wrong number of deconstructed variables.
referencing a property requires a prefix.
If you are referring to a property of a class from code defined within the class then the
property name must be preceded by property.
'out' parameters are only supported on procedures.
You cannot defined an out parameter in a function (because that would
imply the possibility of creating a side effect).
There can only be one main in a program.
Unsupported operation.
You cannot chain two 'unary' operators (those that apply to a single value), such as −
or not successively within an expression.
Parameter ... may not have the same name as the method in which it is defined.
A function or procedure named e.g. 'foo' may not define a parameter with that same name.
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.
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 .
Advisory
Code change suggested. Method was deprecated in v7.1.
Runtime errors
Messages
Tests timed out and were aborted
An error or infinite loop found in a test. Refer to ghosting tests .
Overly complex expressions
Overly complex expressions, for example involving a sequence of open brackets, can result in
very slow parsing. We strongly recommend that you you simplify the contents of this field, for example by
breaking out parts of it into separate variable definition instructions; otherwise it might become impossible to add more text.
ReferenceError: Cannot access '[name]' before initialisation
Elan Language Reference go to the top