Elan Library Reference
Value data Types
Integer
An integer is a whole number, i.e. one that has no fractional part. It may be represented in decimal, hexadecimal or binary:
100 (decimal), 0x64 (hexadecimal) and 0b1100100 all have the same value.
Its Type is Int.
name of Type |
examples of defining a literal value |
| Int |
+constant maxNumbername? set to 10literal value or data structure?1
+maxNumbername? = 10literal value or data structure? # constant1
main()
+const Int maxNumbername? = 10literal value or data structure?1
+Const maxNumbername? = 10literal value or data structure?1
+final Int maxNumbername? = 10literal value or data structure? // constant1 |
| Int |
variable flagsname? set to 0b1100100value or expression?0
flagsname? = 0b1100100value or expression? # variable definition0
var flagsname? = 0b1100100value or expression?;0
Dim flagsname? = &B1100100value or expression? ' variable definition0
var flagsname? = 0b1100100value or expression?;0 |
Function dot methods on an Int
function dot method |
argument Types |
return Type |
returns |
| asBinary |
(none) |
String |
string of binary digits representing the argument's integer value |
| equals |
Int |
Boolean |
true if integer and argument values are equal – false otherwise |
| notEqualTo |
Int |
Boolean |
true if integer and argument values are unequal – false otherwise |
| toString |
(none) |
String |
a string of decimal digits representing the argument's integer value |
Notes
- A literal integer or a named value of Type Int may
always be passed into a function or procedure that is expecting a Float.
- The Int type is intended to represent whole numbers
in the range:
- Maximum: 253 − 1 (which is 9,007,199,254,740,991)
- Minimum value: −(253 − 1)
- If you go greater than the limit given above, the number will be accurate to approximately 17 decimal digits.
Larger numbers will be rounded with zeros at the end, unless they are larger than around 270, when they will automatically be shown
in exponential (scientific) format, as shown in the example.
Example of large numbers
▶ This code calculates 2 raised to the power of 50 through 72, and its output is shown below:
+main
1
+for nitem? in range(50, 73)source?
2
variable sname? set to lambda n as Int => n.toString().length()value or expression?3
variable npname? set to pow(2, n).floor()value or expression?4
call printTabprocedureName?(s(n), $"{n}"arguments?)5
call printTabprocedureName?(30 - s(np), $"{np}\n"arguments?)6
end for
end main
+def main() -> None:
1
+for nitem? in range(50, 73)source?:
2
sname? = lambda n: int => n.toString().length()value or expression? # variable definition3
npname? = pow(2, n).floor()value or expression? # variable definition4
printTabprocedureName?(s(n), f"{n}"arguments?) # call procedure5
printTabprocedureName?(30 - s(np), f"{np}\n"arguments?) # call procedure6
main()
+static void main() {
1
+foreach (nitem? in range(50, 73)source?) {
2
var sname? = lambda int n => n.toString().length()value or expression?;3
var npname? = pow(2, n).floor()value or expression?;4
printTabprocedureName?(s(n), $"{n}"arguments?); // call procedure5
printTabprocedureName?(30 - s(np), $"{np}\n"arguments?); // call procedure6
}
}
+Sub main()
1
+For Each nitem? In range(50, 73)source?
2
Dim sname? = lambda n As Integer => n.toString().length()value or expression? ' variable definition3
Dim npname? = pow(2, n).floor()value or expression? ' variable definition4
printTabprocedureName?(s(n), $"{n}"arguments?) ' call procedure5
printTabprocedureName?(30 - s(np), $"{np}\n"arguments?) ' call procedure6
Next n
End Sub
+static void main() {
1
+foreach (nitem? in range(50, 73)source?) {
2
var sname? = lambda int n => n.toString().length()value or expression?;3
var npname? = pow(2, n).floor()value or expression?;4
printTabprocedureName?(s(n), String.format("%", n)arguments?); // call procedure5
printTabprocedureName?(30 - s(np), String.format("%\n", np)arguments?); // call procedure6
}
}
Floating point
A floating point number is a decimal number (also known as a Real number) that may have both integer and fractional parts.
It may be written using exponential (scientific) notation, e.g.
120.0 can be written as 1.20e2, and
0.012 as 1.20e-2
Its Type is Float.
name of Type |
examples of defining a literal value |
| Float |
constant phi set to 1.618033988749895 |
| Float |
variable reading set to 1.1e-10 |
Function dot methods on a Float
function dot method |
argument Types |
return Type |
returns |
| ceiling |
(none) |
Int |
the first integral value larger than or equal to the argument's floating point value |
| equals |
Float |
Boolean |
true if floating point number and argument values are equal – false otherwise |
| floor |
(none) |
Int |
the first integral value smaller than or equal to the argument's floating point value |
| isInfinite |
(none) |
Boolean |
true if value would be infinite, e.g. after division by zero – false otherwise |
| isNaN |
(none) |
Boolean |
true if value is 'NaN', i.e. Not a Number, e.g. 0/0 – false otherwise |
| notEqualTo |
Float |
Boolean |
true if floating point number and argument values are unequal – false otherwise |
| round |
Int |
Float |
the value rounded (up or down as appropriate) to the number of decimal places specified in the argument |
| toString |
(none) |
String |
a string representing the argument's floating point value |
Notes
- The limits on floating point numbers are:
- Maximum value: just over 1.0 × 10308
- Minimum value: approximately 5.0 × 10-324
- A variable that has been defined as being of Type Float may not be passed as an argument into a method that requires an Int,
nor as an index into a List even if the variable contains no fractional part.
It may, however, be converted into an Int before passing, using the function floor or ceiling.
- If you wish to define a variable to be of Type Float, but initialise it with an integer value, then add .0 on the end of the whole number, as in:
variable hourname? set to 3.0value or expression?0
hourname? = 3.0value or expression? # variable definition0
var hourname? = 3.0value or expression?;0
Dim hourname? = 3.0value or expression? ' variable definition0
var hourname? = 3.0value or expression?;0
- Any variable or expression that evaluates to an Int may always be used where a Float is expected.
Examples of standalone dot methods on a Float
▶ Test assertions using dot methods on a Float:
+test test_floortest_name?
1
variable pname? set to pivalue or expression?2
variable mpname? set to -pivalue or expression?3
assert p.floor()actual (computed) value? is 3expected value? not run4
assert mp.floor()actual (computed) value? is -4expected value? not run5
assert p.ceiling()actual (computed) value? is 4expected value? not run6
assert mp.ceiling()actual (computed) value? is -3expected value? not run7
assert p.round(3)actual (computed) value? is 3.142expected value? not run8
assert mp.round(2)actual (computed) value? is -3.14expected value? not run9
assert sqrt(-p).isNaN()actual (computed) value? is trueexpected value? not run10
variable qname? set to divAsInt(1, 0).floor()value or expression?11
assert q.isInfinite()actual (computed) value? is trueexpected value? not run12
end test
+def test_floortest_name?(self) -> None:
1
pname? = pivalue or expression? # variable definition2
mpname? = -pivalue or expression? # variable definition3
self.assertEqual(p.floor()actual (computed) value?, 3expected value?) not run4
self.assertEqual(mp.floor()actual (computed) value?, -4expected value?) not run5
self.assertEqual(p.ceiling()actual (computed) value?, 4expected value?) not run6
self.assertEqual(mp.ceiling()actual (computed) value?, -3expected value?) not run7
self.assertEqual(p.round(3)actual (computed) value?, 3.142expected value?) not run8
self.assertEqual(mp.round(2)actual (computed) value?, -3.14expected value?) not run9
self.assertEqual(sqrt(-p).isNaN()actual (computed) value?, Trueexpected value?) not run10
qname? = divAsInt(1, 0).floor()value or expression? # variable definition11
self.assertEqual(q.isInfinite()actual (computed) value?, Trueexpected value?) not run12
main()
+[TestMethod] static void test_floortest_name?() {
1
var pname? = pivalue or expression?;2
var mpname? = -pivalue or expression?;3
Assert.AreEqual(3expected value?, p.floor()actual (computed) value?) not run4
Assert.AreEqual(-4expected value?, mp.floor()actual (computed) value?) not run5
Assert.AreEqual(4expected value?, p.ceiling()actual (computed) value?) not run6
Assert.AreEqual(-3expected value?, mp.ceiling()actual (computed) value?) not run7
Assert.AreEqual(3.142expected value?, p.round(3)actual (computed) value?) not run8
Assert.AreEqual(-3.14expected value?, mp.round(2)actual (computed) value?) not run9
Assert.AreEqual(trueexpected value?, sqrt(-p).isNaN()actual (computed) value?) not run10
var qname? = divAsInt(1, 0).floor()value or expression?;11
Assert.AreEqual(trueexpected value?, q.isInfinite()actual (computed) value?) not run12
}
+<TestMethod> Sub test_floortest_name?()
1
Dim pname? = pivalue or expression? ' variable definition2
Dim mpname? = -pivalue or expression? ' variable definition3
Assert.AreEqual(3expected value?, p.floor()actual (computed) value?) not run4
Assert.AreEqual(-4expected value?, mp.floor()actual (computed) value?) not run5
Assert.AreEqual(4expected value?, p.ceiling()actual (computed) value?) not run6
Assert.AreEqual(-3expected value?, mp.ceiling()actual (computed) value?) not run7
Assert.AreEqual(3.142expected value?, p.round(3)actual (computed) value?) not run8
Assert.AreEqual(-3.14expected value?, mp.round(2)actual (computed) value?) not run9
Assert.AreEqual(Trueexpected value?, sqrt(-p).isNaN()actual (computed) value?) not run10
Dim qname? = divAsInt(1, 0).floor()value or expression? ' variable definition11
Assert.AreEqual(Trueexpected value?, q.isInfinite()actual (computed) value?) not run12
End Sub
+@Test static void test_floortest_name?() {
1
var pname? = pivalue or expression?;2
var mpname? = -pivalue or expression?;3
assertEquals(3expected value?, p.floor()actual (computed) value?) not run4
assertEquals(-4expected value?, mp.floor()actual (computed) value?) not run5
assertEquals(4expected value?, p.ceiling()actual (computed) value?) not run6
assertEquals(-3expected value?, mp.ceiling()actual (computed) value?) not run7
assertEquals(3.142expected value?, p.round(3)actual (computed) value?) not run8
assertEquals(-3.14expected value?, mp.round(2)actual (computed) value?) not run9
assertEquals(trueexpected value?, sqrt(-p).isNaN()actual (computed) value?) not run10
var qname? = divAsInt(1, 0).floor()value or expression?;11
assertEquals(trueexpected value?, q.isInfinite()actual (computed) value?) not run12
}
Boolean
A Boolean value is either true or false.
The keywords true and false must be written in lower case.
name of Type |
examples of defining a literal value |
| Boolean |
variable done set to true |
Function dot methods on a Boolean
function dot methods |
argument Types |
return Type |
returns |
| equals |
Boolean |
Boolean |
true if the truth value and argument are equal – false otherwise |
| notEqualTo |
Boolean |
Boolean |
true if the truth value and argument are unequal – false otherwise |
| toString |
(none) |
String |
String "true" if true, "false" if false |
Reference data Types
String
A String represents text, i.e. a sequence of zero or more characters.
name of Type |
examples of defining a literal value |
details |
| String |
constant title set to "Ulysses" |
delimited by double quotes |
| String |
variable quote set to "'Hello', she said" |
' may be used in a string delimited by " |
| String |
variable emptyString set to "" |
a zero-length, or 'empty', string |
Character sets
When typing from the keyboard into a literal string all the basic ASCII characters (0x20 to 0x7e) and '£' can be input.
You cannot use Alt+numeric-keypad to enter accented letters or other special characters in the extended ASCII range (0x80 to 0xff).
You can, however, copy any text from outside Elan and paste it into a string, whether ASCII, extended ASCII or UTF-8 encoded.
To insert a character from the full range, you use its Unicode (codepoint) value, in decimal or hexadecimal, by means of function unicode:
call printprocedureName?($"Spanish introduces a question with {unicode(191)}"arguments?)0
printprocedureName?(f"Spanish introduces a question with {unicode(191)}"arguments?)0
printprocedureName?($"Spanish introduces a question with {unicode(191)}"arguments?);0
printprocedureName?($"Spanish introduces a question with {unicode(191)}"arguments?)0
printprocedureName?(String.format("Spanish introduces a question with %", unicode(191))arguments?);0
|
⟶ | Spanish introduces a question with ¿ |
call printprocedureName?($"This is an up arrow: {unicode(0x2191)}"arguments?)0
printprocedureName?(f"This is an up arrow: {unicode(0x2191)}"arguments?)0
printprocedureName?($"This is an up arrow: {unicode(0x2191)}"arguments?);0
printprocedureName?($"This is an up arrow: {unicode(&H2191)}"arguments?)0
printprocedureName?(String.format("This is an up arrow: %", unicode(0x2191))arguments?);0
|
⟶ | This is an up arrow: ↑
|
These examples 'interpolate' the output of function unicode by using a $ before the string and curly braces within it (see Interpolated fields).
Manipulating strings
Strings can be built from other strings by concatenation using the plus operator, for example:
call print("Hello " + "world") | ⟶ | Hello world
Code does not parse as Elan.
call print("Hello " + "world") | ⟶ | Hello world
Code does not parse as Elan.
call print("Hello " + "world") | ⟶ | Hello world
Code does not parse as Elan.
call print("Hello " + "world") | ⟶ | Hello world
Code does not parse as Elan.
call print("Hello " + "world") | ⟶ | Hello world
Code does not parse as Elan. |
A newline may be inserted within a string with \n:
| call print("Hello\nworld") | ⟶ | Hello world |
When editing and you leave the field, the newline will be implicitly applied in your code.
As in most languages, strings are immutable. When you apply any operation or function with the intent of modifying an existing string, the existing string is never changed. Instead, the operation or function will return a new string that is based on the original, but with the specified differences.
You can loop through a string picking each of its characters sequentially using the for loop.
Function dot methods on a String
function dot method |
argument Types |
return Type |
returns |
| asRegExp |
(none) |
RegExp |
a new string that is a a converted to a regular expression: no check is made of whether the result is a valid regular expression |
| asUnicode |
(none) |
Int |
the Unicode value of the first character of the string
(To convert a Unicode value into a string, use function unicode) |
| contains |
(none) |
Boolean |
true if the string contains the substring specified as the argument – false otherwise |
| equals |
String |
Boolean |
true if the string and argument are equal – false otherwise |
| notEqualTo |
String |
Boolean |
true if the string and argument are unequal – false otherwise |
| indexOf |
String |
Int |
index of the first instance of the argument (substring) within the string If it is not present, -1 is returned |
| isAfter |
String |
Boolean |
true if alphabetic comparison finds the string comes strictly 'after' the argument string – false otherwise |
| isAfterOrSameAs |
String |
Boolean |
true if alphabetic comparison finds the string comes 'after' or equals the argument string – false otherwise |
| isBefore |
String |
Boolean |
true if alphabetic comparison finds the string comes strictly 'before' the argument string – false otherwise |
| isBeforeOrSameAs |
String |
Boolean |
true if alphabetic comparison finds the string comes 'before' or equals the argument string – false otherwise |
| length |
(none) |
Int |
the number of characters in the string |
| lowerCase |
(none) |
String |
a new string with the original rendered in lower case |
| matchesRegExp |
RegExp |
Boolean |
true if the string matches the regular expression – false otherwise |
| replace |
String, String |
String |
a new string with all occurrences of the first argument string replaced by the second argument string |
| split |
String |
List<of String> |
a List of the substrings found between occurrences of the argument string
if the argument is the empty string then the list is of all the individual characters |
| subString |
Int, Int |
String |
a new string that is the substring specified by the two positive integers (m,n) where
m indexes the first character of the substring required (counting from 0) and
n indexes the character after the last character required (exclusive index)
if m ≥ n the result is the empty string
|
| toString |
(none) |
String |
the string itself |
| trim |
(none) |
String |
a new string with leading and trailing spaces removed |
| upperCase |
(none) |
String |
a new string with the original rendered in upper case |
Interpolated fields in strings
Strings support interpolation, that is you can insert the values of variables
or simple expressions within the string by enclosing them in curly braces and
prefixing the string with a $:
If a and b have values 3 and 17:
call print($"{a} times {b} equals {a*b}") | ⟶ | 3 times 17 equals 51
Code does not parse as Elan.
call print($"{a} times {b} equals {a*b}") | ⟶ | 3 times 17 equals 51
Code does not parse as Elan.
call print($"{a} times {b} equals {a*b}") | ⟶ | 3 times 17 equals 51
Code does not parse as Elan.
call print($"{a} times {b} equals {a*b}") | ⟶ | 3 times 17 equals 51
Code does not parse as Elan.
call print($"{a} times {b} equals {a*b}") | ⟶ | 3 times 17 equals 51
Code does not parse as Elan. |
If velocity and fuel have values 3.0 and 50.4:
set messagevariableName? to $"LANDED SAFELY AT SPEED {(velocity*100).floor()} FUEL {fuel.floor()}"value or expression?0
messagevariableName? = f"LANDED SAFELY AT SPEED {(velocity*100).floor()} FUEL {fuel.floor()}"value or expression? # change variable0
messagevariableName? = $"LANDED SAFELY AT SPEED {(velocity*100).floor()} FUEL {fuel.floor()}"value or expression?; // change variable0
messagevariableName? = $"LANDED SAFELY AT SPEED {(velocity*100).floor()} FUEL {fuel.floor()}"value or expression? ' change variable0
messagevariableName? = String.format("LANDED SAFELY AT SPEED % FUEL %", (velocity*100).floor(), fuel.floor())value or expression?; // change variable0
call printprocedureName?(messagearguments?)0
printprocedureName?(messagearguments?)0
printprocedureName?(messagearguments?);0
printprocedureName?(messagearguments?)0
printprocedureName?(messagearguments?);0
|
| ⟶ |
LANDED SAFELY AT SPEED 300 FUEL 50 |
And, for the area of a circle:
+constant rname? set to 2.0literal value or data structure?1
+rname? = 2.0literal value or data structure? # constant1
main()
+const Float rname? = 2.0literal value or data structure?1
+Const rname? = 2.0literal value or data structure?1
+final Float rname? = 2.0literal value or data structure? // constant1
call print($"area = {(pi*r*r).round(2)}"
Code does not parse as Elan.
call print($"area = {(pi*r*r).round(2)}"
Code does not parse as Elan.
call print($"area = {(pi*r*r).round(2)}"
Code does not parse as Elan.
call print($"area = {(pi*r*r).round(2)}"
Code does not parse as Elan.
call print($"area = {(pi*r*r).round(2)}"
Code does not parse as Elan.
| ⟶ |
area = 12.57
|
Standard data structures
Elan has two mutable data structure Types List and Dictionary, and
three immutable data structure Types HashSet, Stack and Queue.
The contents of these structures are referred to as items (or sometimes elements).
The values of items in a mutable structure may be changed directly by calling the various procedure dot methods defined for each structure Type.
The values of items in an immutable structure cannot be changed directly, and so have no procedure dot methods defined for them:
rather, the methods called on them create new copies of the structures containing specified changes.
Since procedure methods may be called only from within the main routine or a procedure,
it is also possible to make changes via function dot methods, which return a copy of the data structure
with specified changes: that is why all such methods have names starting 'with'.
Immutable data structures are intended specifically to facilitate the Functional Programming paradigm,
but some are also useful within other programming paradigms.
All six contain values (and keys in the case of a Dictionary) of only a single Type, that Type being specified either explicitly (as in
<of Int>), or implicitly if the structure is created using a literal definition.
This table summarises the creation and reference to these structures. Details of their methods follow.
|
List |
Dictionary |
HashSet |
Stack |
Queue |
| mutability |
Mutable |
Mutable |
Immutable |
Immutable |
Immutable |
| Type form |
List<of Type> Type of item can be any, including List for 'jagged' data |
Dictionary<of keyType, valueType>
keyType is Int, Float, String or Boolean
valueType may be any Type |
HashSet<of Type> Type of item must be immutable |
Stack<of Type> Type of item must be immutable |
Queue<of Type> Type of item must be immutable |
| size | Dynamic | Dynamic | Dynamic | Dynamic | Dynamic |
| literal definition |
[2, 3, 5, 7, 11] |
["a":3, "b":5] |
Only as converted from a literal List e.g. ["a","b","c"].asSet() |
Not available |
Not available |
| create empty |
new List<of Type>() |
new Dictionary<of keyType, valueType>() |
new HashSet<of Type>() |
new Stack<of Type>() |
new Queue<of Type>() |
| create initialised
| createList(number, value)
createListOfLists(cols, rows, value) |
Not available |
Not available |
Not available |
Not available |
| read by index |
li[2] |
d["b"] |
not available |
not available |
not available |
| read by index range |
li.subList(3, el-lit>5) lower bound is inclusive from 0 upper bound is exclusive |
not available |
not available |
not available |
not available |
| procedure methods to mutate contents |
see Procedure methods on a List |
see Procedure methods on a Dictionary |
not available |
not available |
not available |
| function dot methods |
see Function dot methods on a List |
see Function dot methods on a Dictionary |
see Function dot methods on a Set |
see Function dot methods on a Stack |
see Function dot methods on a Queue |
List
The List Type defines a data structure containing n items of any single Type,
including basic value Types, structure Types such as List,
and user-defined Types such as a Class.
Items in a List of n items are indexed from 0 to n-1.
To create a List, use either of:
- Method createList to define its length and the initial value (and implicitly the Type) of its items:
variable aListname? set to createList(10, "no one")value or expression?0
aListname? = createList(10, "no one")value or expression? # variable definition0
var aListname? = createList(10, "no one")value or expression?;0
Dim aListname? = createList(10, "no one")value or expression? ' variable definition0
var aListname? = createList(10, "no one")value or expression?;0
- Define an empty List of the required type, and use the procedure methods listed below to populate it:
variable aList set to new List<of String>()
Code does not parse as Elan.
variable aList set to new List<of String>()
Code does not parse as Elan.
variable aList set to new List<of String>()
Code does not parse as Elan.
variable aList set to new List<of String>()
Code does not parse as Elan.
variable aList set to new List<of String>()
Code does not parse as Elan.
call aList.initialiseprocedureName?(10, "no one"arguments?)0
aList.initialiseprocedureName?(10, "no one"arguments?) # call procedure0
aList.initialiseprocedureName?(10, "no one"arguments?); // call procedure0
aList.initialiseprocedureName?(10, "no one"arguments?) ' call procedure0
aList.initialiseprocedureName?(10, "no one"arguments?); // call procedure0
call aList.appendprocedureName?("4"arguments?)0
aList.appendprocedureName?("4"arguments?) # call procedure0
aList.appendprocedureName?("4"arguments?); // call procedure0
aList.appendprocedureName?("4"arguments?) ' call procedure0
aList.appendprocedureName?("4"arguments?); // call procedure0
The item at index ix in List aList can then be changed using a set instruction and a valid index value in square brackets:
set aList[ix]variableName? to "Smith"value or expression?0
aList[ix]variableName? = "Smith"value or expression? # change variable0
aList[ix]variableName? = "Smith"value or expression?; // change variable0
aList[ix]variableName? = "Smith"value or expression? ' change variable0
aList[ix]variableName? = "Smith"value or expression?; // change variable0
A List's size can be dynamically changed using the procedure methods listed below.
Deconstructing a List
A List may be split (deconstructed) into new named values using indexes and
the methods head, tail and subList:
- To extract the first item in a List:
variable headItemname? set to myList[0]value or expression?0
headItemname? = myList[0]value or expression? # variable definition0
var headItemname? = myList[0]value or expression?;0
Dim headItemname? = myList[0]value or expression? ' variable definition0
var headItemname? = myList[0]value or expression?;0
or
set heatItemvariableName? to myList.head()value or expression?0
heatItemvariableName? = myList.head()value or expression? # change variable0
heatItemvariableName? = myList.head()value or expression?; // change variable0
heatItemvariableName? = myList.head()value or expression? ' change variable0
heatItemvariableName? = myList.head()value or expression?; // change variable0
- To form a new List of all but the first item in a List:
variable tailListname? set to myList.tail()value or expression?0
tailListname? = myList.tail()value or expression? # variable definition0
var tailListname? = myList.tail()value or expression?;0
Dim tailListname? = myList.tail()value or expression? ' variable definition0
var tailListname? = myList.tail()value or expression?;0
If the original list contains only one item, the new List will be the empty List.
- To get some other portion of a List, use the method subList:
set shortListvariableName? to myList.subList(1, 5)value or expression?0
shortListvariableName? = myList.subList(1, 5)value or expression? # change variable0
shortListvariableName? = myList.subList(1, 5)value or expression?; // change variable0
shortListvariableName? = myList.subList(1, 5)value or expression? ' change variable0
shortListvariableName? = myList.subList(1, 5)value or expression?; // change variable0
In all these cases the items indexed must exist, else a runtime error will stop the program.
Lists of lists
Two dimensional arrays
Understood as a grid, a 2D array is a List of 'columns' each of which is a List of 'row' items, i.e. it is a List of Lists in which the column number is the x coordinate, and the row number is the y coordinate.
To create a 2D array that holds a value of a single Type in every cell, you define such a List of Lists thus:
- Use method createListOfLists to set the size of, and initial value in, every x,y position:
variable array2Dname? set to createListOfLists(cols, rows, value)value or expression?0
array2Dname? = createListOfLists(cols, rows, value)value or expression? # variable definition0
var array2Dname? = createListOfLists(cols, rows, value)value or expression?;0
Dim array2Dname? = createListOfLists(cols, rows, value)value or expression? ' variable definition0
var array2Dname? = createListOfLists(cols, rows, value)value or expression?;0
- For the special case of Block graphics, use 40 columns and 30 rows or (more simply):
variable gridname? set to createBlockGraphics(value)value or expression?0
gridname? = createBlockGraphics(value)value or expression? # variable definition0
var gridname? = createBlockGraphics(value)value or expression?;0
Dim gridname? = createBlockGraphics(value)value or expression? ' variable definition0
var gridname? = createBlockGraphics(value)value or expression?;0
The item at index ix,iy in a 2D array can be accessed and changed
using its two coordinates in square brackets:
variable valuename? set to array2D[ix][iy]value or expression?0
valuename? = array2D[ix][iy]value or expression? # variable definition0
var valuename? = array2D[ix][iy]value or expression?;0
Dim valuename? = array2D[ix][iy]value or expression? ' variable definition0
var valuename? = array2D[ix][iy]value or expression?;0
set array2D[ix][iy]variableName? to 7value or expression?0
array2D[ix][iy]variableName? = 7value or expression? # change variable0
array2D[ix][iy]variableName? = 7value or expression?; // change variable0
array2D[ix][iy]variableName? = 7value or expression? ' change variable0
array2D[ix][iy]variableName? = 7value or expression?; // change variable0
Higher dimensional arrays
For a 3D array, you can, for example, define:
variable array3D set to new List<of List<of List<of Float>>>()
Code does not parse as Elan.
variable array3D set to new List<of List<of List<of Float>>>()
Code does not parse as Elan.
variable array3D set to new List<of List<of List<of Float>>>()
Code does not parse as Elan.
variable array3D set to new List<of List<of List<of Float>>>()
Code does not parse as Elan.
variable array3D set to new List<of List<of List<of Float>>>()
Code does not parse as Elan.
and refer to a cell using three indexes in square brackets.
Procedure methods on a List
Where an argument provides a new value for an item in a List, that value must be of the same Type as defined for the List's items.
procedure method |
arguments |
action |
| append |
value of List item's Type |
the item is added to the end of the List |
| appendList |
List |
the argument List is added to the end of the List |
| initialise |
Int, value of List item's Type |
specify the number (> 0) of items in the List, and an initial value for every item.
May be called at any time to redefine the List's size and initial values. |
| insert |
Int, value of List item's Type |
the item is inserted at the index given.
If the index is negative it is counted from the end
If the index is greater than the list's length, the item is inserted at the end |
| prepend |
value of List item's Type |
the item is is added to the start of the List |
| prependList |
List |
the argument List is added to the start of the List |
| removeAll |
value of List item's Type |
delete all items equal to the given item |
| removeAt |
Int |
delete the item at the argument index |
| removeFirst |
value of List item's Type |
delete the first item equal to the given value |
Function dot methods on a List
function dot method |
arguments |
return Type |
returns |
| asSet |
(none) |
HashSet |
a new Set containing all the unique items in the List |
| contains |
value |
Boolean |
true if the List contains the specified item
– false otherwise |
| equals |
List |
Boolean |
true if list and argument are identical – false otherwise |
| filter |
lambda |
List |
a new List obtained from applying a lambda to the input List
see filter in HoFs |
| head |
(none) |
List item's Type |
the first item of the List (i.e. index = 0, which must exist) |
| indexOf |
value of List item's Type |
Int |
the index of the first occurrence of the argument value in the List, or -1 if no match is found |
| join |
List<of String> |
String |
a single String that joins all the items in the list, with the specified String (which can be empty) inserted between the items |
| length |
(none) |
Int |
the number of items in the List |
| map |
lambda |
List |
a new List obtained from applying a lambda to the input List
see map in HoFs |
| maxBy |
lambda |
List item's Type |
the list item corresponding to the maximum of the values returned by a lambda
see maxBy in HoFs |
| minBy |
lambda |
List item's Type |
the list item corresponding to the minimum of the values returned by a lambda
see minBy in HoFs |
| notEqualTo |
List |
Boolean |
true if list and argument differ l – false otherwise |
| orderBy |
lambda |
List |
a new list with the items ordered according to the value returned by a lambda |
| reduce |
item of List item's Type, lambda |
return Type of lambda |
the final value obtained by applying a lambda cumulatively to each item in the input List
taking account of the first argument as an initial (and default return) value
see reduce in HoFs |
| subList |
Int, Int |
List |
a new list that contains the items specified by the two positive integers (m,n) where
m indexes the first item of the list required (counting from 0) and
n indexes the item after the last item required (exclusive index)
if m ≥ n the result is the empty list
|
| tail |
(none) |
List item's Type |
all items except the first item in the List (i.e. index = 1..n, which must exist) |
| toString |
(none) |
String |
a String that is a comma+space-separated list of the List's items, enclosed in square brackets |
| withAppend |
item of List item's Type |
List |
a new List lengthened with the item added after the end |
| withAppendList |
List of same Type |
List |
a new List lengthened by appending the given List |
| withInsert |
Int, value of List item's Type |
List |
a new List with the item inserted after the item at the given index position |
| withPrepend |
value of List item's Type |
List |
a new List lengthened with the item added before the beginning |
| withPrependList |
List of same Type |
List |
a new List lengthened by prepending the given List |
| withSet |
Int, value of List item's Type |
List |
a new List with the item replacing that at the given index |
| withRemoveAll |
value of List item's Type |
List |
a new List with items equal to the given item removed |
| withRemoveAt |
Int |
List |
a new List with the item at the given index removed |
| withRemoveFirst |
value of List item's Type |
List |
a new List with the first item equal to the given item removed |
Dictionary
A Dictionary is like a List whose items are pairs but, instead of having a numeric index, each item has a key plus an associated value.
The Dictionary is a set of key:value pairs.
The key's Type must be one of Int, Float, String or Boolean.
The values may be of any Type. The Types of both keys and values are fixed when the Dictionary is created.
Procedure method on a Dictionary
procedure method |
argument Types |
action |
| removeAt |
key's Type |
delete the key:pair at the given key (if it exists) |
Function dot methods on a Dictionary
function dot method |
argument Types |
return Type |
returns |
| equals |
Dictionary |
Boolean |
true if dictionary and argument are identical – false otherwise |
| hasKey |
item of Dictionary key's Type |
Boolean |
true if the Dictionary contains the given key – false otherwise |
| keys |
(none) |
List |
a List containing the keys |
| notEqualTo |
Dictionary |
Boolean |
true if dictionary and argument differ – false otherwise |
| toString |
(none) |
String |
a string that is a comma+space-separated list of the Dictionary's key:value pairs, enclosed in square brackets |
| values |
(none) |
List |
a List containing the values |
| withSet |
item of Dictionary key's Type, item of Dictionary value's Type |
Dictionary |
a new Dictionary with the value replacing what was at the specified key |
| withRemoveAt |
item of Dictionary key's Type |
Dictionary |
a new Dictionary with the key:value pair removed from the specified key |
HashSet
A HashSet (also referred to merely as a Set) is a standard data structure containing Set members, that works somewhat like a List with two important differences:
- The value of a Set member may appear only once: if a member being added to a HashSet has the same value as an existing member in the Set then the Set remains the same as before.
- The values in a HashSet are not indexed: two Sets with the same contents but defined in a different sequence, can still be compared correctly with methods equals and notEqualTo.
- There are no methods that modify an existing Set but several, e.g. add and remove,
return a new HashSet that is based on the original Set or Sets with specified differences.
This enables a Set to work like a mathematical set so that it is possible to perform standard set operations such as union and intersection.
When creating a HashSet, the Type of its members must be specified in the form
HashSet<of String>.
You can add members: individually with add, or multiply with addFromList.
And you can create a new HashSet from an existing List by calling asSet on it.
Example of creating a Set from a literal List and changing its content:
variable st set to new HashSet<of Int()
Code does not parse as Elan.
variable st set to new HashSet<of Int()
Code does not parse as Elan.
variable st set to new HashSet<of Int()
Code does not parse as Elan.
variable st set to new HashSet<of Int()
Code does not parse as Elan.
variable st set to new HashSet<of Int()
Code does not parse as Elan.
set st to st.addFromList([3, 5, 7])
Code does not parse as Elan.
set st to st.addFromList([3, 5, 7])
Code does not parse as Elan.
set st to st.addFromList([3, 5, 7])
Code does not parse as Elan.
set st to st.addFromList([3, 5, 7])
Code does not parse as Elan.
set st to st.addFromList([3, 5, 7])
Code does not parse as Elan.
call printprocedureName?(st.length()arguments?)0
printprocedureName?(st.length()arguments?)0
printprocedureName?(st.length()arguments?);0
printprocedureName?(st.length()arguments?)0
printprocedureName?(st.length()arguments?);0
|
⟶ |
3 |
set st to st.add(7)
Code does not parse as Elan.
set st to st.add(7)
Code does not parse as Elan.
set st to st.add(7)
Code does not parse as Elan.
set st to st.add(7)
Code does not parse as Elan.
set st to st.add(7)
Code does not parse as Elan.
call printprocedureName?(st.length()arguments?)0
printprocedureName?(st.length()arguments?)0
printprocedureName?(st.length()arguments?);0
printprocedureName?(st.length()arguments?)0
printprocedureName?(st.length()arguments?);0 |
⟶ | 3 |
set st to st.remove(3)
Code does not parse as Elan.
set st to st.remove(3)
Code does not parse as Elan.
set st to st.remove(3)
Code does not parse as Elan.
set st to st.remove(3)
Code does not parse as Elan.
set st to st.remove(3)
Code does not parse as Elan.
call printprocedureName?(st.length()arguments?)0
printprocedureName?(st.length()arguments?)0
printprocedureName?(st.length()arguments?);0
printprocedureName?(st.length()arguments?)0
printprocedureName?(st.length()arguments?);0 |
⟶ | 2 |
set st to st.remove(3)
Code does not parse as Elan.
set st to st.remove(3)
Code does not parse as Elan.
set st to st.remove(3)
Code does not parse as Elan.
set st to st.remove(3)
Code does not parse as Elan.
set st to st.remove(3)
Code does not parse as Elan.
call printprocedureName?(st.length()arguments?)0
printprocedureName?(st.length()arguments?)0
printprocedureName?(st.length()arguments?);0
printprocedureName?(st.length()arguments?)0
printprocedureName?(st.length()arguments?);0 |
⟶ | 2 |
call printprocedureName?(starguments?)0
printprocedureName?(starguments?)0
printprocedureName?(starguments?);0
printprocedureName?(starguments?)0
printprocedureName?(starguments?);0 |
⟶ | [5, 7] |
Function dot methods on a HashSet
function dot method |
argument Types |
return Type |
returns |
| add |
value (of HashSet members' Type) |
HashSet |
a new Set extended with the item, provided it differs from all of the Set's current members |
| addFromList |
List |
HashSet |
a new Set extended with those items from the List that are not already in the Set |
| asList |
(none) |
List |
a List containing the Set's members as List items |
| contains |
value (of HashSet members' Type) |
Boolean |
true if the Set contains the item – false otherwise |
| difference |
HashSet |
HashSet |
a Set containing those members of the Set that do not occur in the argument Set |
| equals |
HashSet |
Boolean |
true if Set and argument Set contain identical values – false otherwise |
| notEqualTo |
HashSet |
Boolean |
true if Set and argument Set differ in their values – false otherwise |
| intersection |
HashSet |
HashSet |
a Set containing those members common to both the Set and the argument Set |
| isDisjointFrom |
HashSet |
Boolean |
true if the Set has no items in common with the argument Set – false otherwise |
| isSubsetOf |
HashSet |
Boolean |
true if all the Set's items are also in the argument Set – false otherwise |
| isSupersetOf |
HashSet |
Boolean |
true if the Set contains all the items that are in the argument Set – false otherwise |
| length |
(none) |
Int |
the number of members of the Set |
| remove |
value (of HashSet members' Type) |
HashSet |
a new Set with the argument item removed (if present) |
| toString |
(none) |
String |
a string that is a comma+space-separated list of the Set's members, enclosed in brackets |
| union |
HashSet |
HashSet |
a Set containing all the unique members of the Set and the argument Set (i.e. no duplicates) |
Stack and Queue
- Stack and Queue are similar data structures except that Stack is 'LIFO' (last in, first out), while Queue is FIFO (first in, first out). The names of the methods for adding/removing are different, but there are also common methods.
- Both a Stack and a Queue are defined with the Type of the items that they can contain, similarly to how List has a specified item Type, though with different syntax. The Type is specified in the form shown below e.g. Stack<of String>, Queue<of Int>, Stack<of (Float, Float)>, Queue<of Square>.
- Both Stack and Queue are dynamically extensible, like a List. There is no need (or means) to specify a size limit as they will continue to expand until, eventually, the computer's memory limit is reached.
- This same syntax is used to specify the Type if you want to pass a Stack or Queue into a function, or specify it as the return Type.
- Stack and Queue have two methods in common: length and peek.
peek returns the next item to be removed, without actually removing it.
- The methods for adding and removing an item are different for Stack and Queue, as shown here:
Function dot methods on a Stack
function dot method |
argument Types |
return Types |
returns |
| equals |
Stack |
Boolean |
true if stack and argument are identical – false otherwise |
| notEqualTo |
Stack |
Boolean |
true if stack and argument differ – false otherwise |
| push |
value (of Stack item's Type) |
Stack |
the Stack with the value added to its top |
| pop |
(none) |
Stack item, Stack |
the topmost item of the Stack, and the Stack with the item removed |
| peek |
(none) |
Stack item |
the topmost item on the Stack (without altering the Stack) |
| length |
(none) |
Int |
the number of items in the Stack |
| toString |
(none) |
String |
a String that is a comma+space-separated list of the Stack's items, enclosed in square brackets,
the last item pushed being the first in the String |
Function dot methods on a Queue
function dot method |
argument Types |
return Types |
returns |
| equals |
Queue |
Boolean |
true if queue and argument are identical – false otherwise |
| notEqualTo |
Queue |
Boolean |
true if queue and argument differ – false otherwise |
| enqueue |
value (of Queue item's Type) |
Queue |
the Queue with the item added to the end of the Queue |
| dequeue |
(none) |
Queue item, Queue |
the next item in the Queue, and the Queue with the item removed |
| peek |
(none) |
Queue item |
the next item in the Queue (without altering the Queue) |
| length |
(none) |
Int |
the number of items in the Queue |
| toString |
(none) |
String |
a String that is a comma+space-separated list of the Queue's items, enclosed in square brackets,
the first item enqueued being the first in the String |
Examples using Stack and Queue
▶ Results of push and pop on strings in a Stack:
+main
1
variable skname? set to new Stack<of String>()value or expression?2
call printprocedureName?(sk.length()arguments?)3
set skvariableName? to sk.push("apple")value or expression?4
set skvariableName? to sk.push("banana")value or expression?5
set skvariableName? to sk.push("cherry")value or expression?6
call printprocedureName?(sk.length()arguments?)7
call printprocedureName?(skarguments?)8
call printprocedureName?(sk.peek()arguments?)9
call printprocedureName?(sk.pop()arguments?)10
call printprocedureName?(skarguments?)11
call printprocedureName?(sk.pop().item_0arguments?)12
call printprocedureName?(skarguments?)13
set skvariableName? to sk.pop().item_1value or expression?14
call printprocedureName?(skarguments?)15
end main
+def main() -> None:
1
skname? = Stack[str]()value or expression? # variable definition2
printprocedureName?(sk.length()arguments?)3
skvariableName? = sk.push("apple")value or expression? # change variable4
skvariableName? = sk.push("banana")value or expression? # change variable5
skvariableName? = sk.push("cherry")value or expression? # change variable6
printprocedureName?(sk.length()arguments?)7
printprocedureName?(skarguments?)8
printprocedureName?(sk.peek()arguments?)9
printprocedureName?(sk.pop()arguments?)10
printprocedureName?(skarguments?)11
printprocedureName?(sk.pop().item_0arguments?)12
printprocedureName?(skarguments?)13
skvariableName? = sk.pop().item_1value or expression? # change variable14
printprocedureName?(skarguments?)15
main()
+static void main() {
1
var skname? = new Stack<string>()value or expression?;2
printprocedureName?(sk.length()arguments?);3
skvariableName? = sk.push("apple")value or expression?; // change variable4
skvariableName? = sk.push("banana")value or expression?; // change variable5
skvariableName? = sk.push("cherry")value or expression?; // change variable6
printprocedureName?(sk.length()arguments?);7
printprocedureName?(skarguments?);8
printprocedureName?(sk.peek()arguments?);9
printprocedureName?(sk.pop()arguments?);10
printprocedureName?(skarguments?);11
printprocedureName?(sk.pop().item_0arguments?);12
printprocedureName?(skarguments?);13
skvariableName? = sk.pop().item_1value or expression?; // change variable14
printprocedureName?(skarguments?);15
}
+Sub main()
1
Dim skname? = New Stack(Of String)()value or expression? ' variable definition2
printprocedureName?(sk.length()arguments?)3
skvariableName? = sk.push("apple")value or expression? ' change variable4
skvariableName? = sk.push("banana")value or expression? ' change variable5
skvariableName? = sk.push("cherry")value or expression? ' change variable6
printprocedureName?(sk.length()arguments?)7
printprocedureName?(skarguments?)8
printprocedureName?(sk.peek()arguments?)9
printprocedureName?(sk.pop()arguments?)10
printprocedureName?(skarguments?)11
printprocedureName?(sk.pop().item_0arguments?)12
printprocedureName?(skarguments?)13
skvariableName? = sk.pop().item_1value or expression? ' change variable14
printprocedureName?(skarguments?)15
End Sub
+static void main() {
1
var skname? = new Stack<String>()value or expression?;2
printprocedureName?(sk.length()arguments?);3
skvariableName? = sk.push("apple")value or expression?; // change variable4
skvariableName? = sk.push("banana")value or expression?; // change variable5
skvariableName? = sk.push("cherry")value or expression?; // change variable6
printprocedureName?(sk.length()arguments?);7
printprocedureName?(skarguments?);8
printprocedureName?(sk.peek()arguments?);9
printprocedureName?(sk.pop()arguments?);10
printprocedureName?(skarguments?);11
printprocedureName?(sk.pop().item_0arguments?);12
printprocedureName?(skarguments?);13
skvariableName? = sk.pop().item_1value or expression?; // change variable14
printprocedureName?(skarguments?);15
}
|
⟶
⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ⟶
⟶ |
0
3 [cherry, banana, apple] cherry (cherry, [banana, apple]) [cherry, banana, apple] cherry [cherry, banana, apple]
[banana, apple] |
▶ Results of enqueue and dequeue on strings in a Queue:
+main
1
variable quname? set to new Queue<of String>()value or expression?2
call printprocedureName?(qu.length()arguments?)3
set quvariableName? to qu.enqueue("apple")value or expression?4
set quvariableName? to qu.enqueue("banana")value or expression?5
set quvariableName? to qu.enqueue("cherry")value or expression?6
call printprocedureName?(qu.length()arguments?)7
call printprocedureName?(quarguments?)8
call printprocedureName?(qu.peek()arguments?)9
call printprocedureName?(qu.dequeue()arguments?)10
call printprocedureName?(quarguments?)11
call printprocedureName?(qu.dequeue().item_0arguments?)12
call printprocedureName?(quarguments?)13
set quvariableName? to qu.dequeue().item_1value or expression?14
call printprocedureName?(quarguments?)15
end main
+def main() -> None:
1
quname? = Queue[str]()value or expression? # variable definition2
printprocedureName?(qu.length()arguments?)3
quvariableName? = qu.enqueue("apple")value or expression? # change variable4
quvariableName? = qu.enqueue("banana")value or expression? # change variable5
quvariableName? = qu.enqueue("cherry")value or expression? # change variable6
printprocedureName?(qu.length()arguments?)7
printprocedureName?(quarguments?)8
printprocedureName?(qu.peek()arguments?)9
printprocedureName?(qu.dequeue()arguments?)10
printprocedureName?(quarguments?)11
printprocedureName?(qu.dequeue().item_0arguments?)12
printprocedureName?(quarguments?)13
quvariableName? = qu.dequeue().item_1value or expression? # change variable14
printprocedureName?(quarguments?)15
main()
+static void main() {
1
var quname? = new Queue<string>()value or expression?;2
printprocedureName?(qu.length()arguments?);3
quvariableName? = qu.enqueue("apple")value or expression?; // change variable4
quvariableName? = qu.enqueue("banana")value or expression?; // change variable5
quvariableName? = qu.enqueue("cherry")value or expression?; // change variable6
printprocedureName?(qu.length()arguments?);7
printprocedureName?(quarguments?);8
printprocedureName?(qu.peek()arguments?);9
printprocedureName?(qu.dequeue()arguments?);10
printprocedureName?(quarguments?);11
printprocedureName?(qu.dequeue().item_0arguments?);12
printprocedureName?(quarguments?);13
quvariableName? = qu.dequeue().item_1value or expression?; // change variable14
printprocedureName?(quarguments?);15
}
+Sub main()
1
Dim quname? = New Queue(Of String)()value or expression? ' variable definition2
printprocedureName?(qu.length()arguments?)3
quvariableName? = qu.enqueue("apple")value or expression? ' change variable4
quvariableName? = qu.enqueue("banana")value or expression? ' change variable5
quvariableName? = qu.enqueue("cherry")value or expression? ' change variable6
printprocedureName?(qu.length()arguments?)7
printprocedureName?(quarguments?)8
printprocedureName?(qu.peek()arguments?)9
printprocedureName?(qu.dequeue()arguments?)10
printprocedureName?(quarguments?)11
printprocedureName?(qu.dequeue().item_0arguments?)12
printprocedureName?(quarguments?)13
quvariableName? = qu.dequeue().item_1value or expression? ' change variable14
printprocedureName?(quarguments?)15
End Sub
+static void main() {
1
var quname? = new Queue<String>()value or expression?;2
printprocedureName?(qu.length()arguments?);3
quvariableName? = qu.enqueue("apple")value or expression?; // change variable4
quvariableName? = qu.enqueue("banana")value or expression?; // change variable5
quvariableName? = qu.enqueue("cherry")value or expression?; // change variable6
printprocedureName?(qu.length()arguments?);7
printprocedureName?(quarguments?);8
printprocedureName?(qu.peek()arguments?);9
printprocedureName?(qu.dequeue()arguments?);10
printprocedureName?(quarguments?);11
printprocedureName?(qu.dequeue().item_0arguments?);12
printprocedureName?(quarguments?);13
quvariableName? = qu.dequeue().item_1value or expression?; // change variable14
printprocedureName?(quarguments?);15
}
|
⟶
⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ⟶
⟶ |
0
3 [apple, banana, cherry] apple (apple, [banana, cherry]) [apple, banana, cherry] apple [apple, banana, cherry]
[banana, cherry] |
Tuple
A Tuple is not a value or data structure Type. Rather, it is a small collection of values
of differing Types held together and referenced by a single identifier.
It may be considered a lightweight alternative to defining a Class for some specific purpose.
The items in a Tuple may be literal or named values.
Tuples are referred to as 2-Tuples, 3-Tuples, etc. according to the number of values they hold.
An item within a Tuple may be another Tuple, giving nested Tuples.
A function may return a Tuple.
A Tuple differs from a List in that:
- A Tuple may hold items of different Types.
- A Tuple is immutable: you may read, but not modify, the values it contains.
Once defined, Tuples are effectively read-only.
Nor, unlike a List, can you copy a Tuple
from an existing one with specified differences except by referencing each of its items (see below).
Common uses include:
- Holding a pair of x,y coordinates (each of Type Float) as a single unit.
- Allowing a function to pass back a result comprised of both a message in a String and a Boolean indicating whether the operation was successful.
- Returning both an updated copy of a data structure and the value of an item from it, e.g. from method pop on a Stack.
Defining a Tuple
A new Tuple is defined by a list of items separated by commas and enclosed in round brackets:
variable pointname? set to (3, 4)value or expression?0
pointname? = (3, 4)value or expression? # variable definition0
var pointname? = (3, 4)value or expression?;0
Dim pointname? = (3, 4)value or expression? ' variable definition0
var pointname? = (3, 4)value or expression?;0
variable tname? set to (3, "apple", true)value or expression?0
tname? = (3, "apple", True)value or expression? # variable definition0
var tname? = (3, "apple", true)value or expression?;0
Dim tname? = (3, "apple", True)value or expression? ' variable definition0
var tname? = (3, "apple", true)value or expression?;0
Accessing items in a Tuple
The items in a tuple may be individually addressed by a dot reference and its special properties item_N, thus:
+main
1
variable tname? set to (3, "apple", true)value or expression?2
call printprocedureName?(targuments?)3
call printprocedureName?(t.item_0arguments?)4
call printprocedureName?(t.item_1arguments?)5
call printprocedureName?(t.item_2arguments?)6
end main
+def main() -> None:
1
tname? = (3, "apple", True)value or expression? # variable definition2
printprocedureName?(targuments?)3
printprocedureName?(t.item_0arguments?)4
printprocedureName?(t.item_1arguments?)5
printprocedureName?(t.item_2arguments?)6
main()
+static void main() {
1
var tname? = (3, "apple", true)value or expression?;2
printprocedureName?(targuments?);3
printprocedureName?(t.item_0arguments?);4
printprocedureName?(t.item_1arguments?);5
printprocedureName?(t.item_2arguments?);6
}
+Sub main()
1
Dim tname? = (3, "apple", True)value or expression? ' variable definition2
printprocedureName?(targuments?)3
printprocedureName?(t.item_0arguments?)4
printprocedureName?(t.item_1arguments?)5
printprocedureName?(t.item_2arguments?)6
End Sub
+static void main() {
1
var tname? = (3, "apple", true)value or expression?;2
printprocedureName?(targuments?);3
printprocedureName?(t.item_0arguments?);4
printprocedureName?(t.item_1arguments?);5
printprocedureName?(t.item_2arguments?);6
}
|
⟶ ⟶ ⟶ ⟶ |
(3, apple, true) 3 apple true |
And where p1 and p2 represent points each with 2-Tuples containing two Float values, this function returns the distance between them:
+function distanceBetweenname?(p1 as (Float, Float), p2 as (Float, Float)parameter definitions?) returns FloatType?
1
return sqrt(pow(p2.item_0 - p1.item_0, 2) + pow(p2.item_1 - p1.item_1, 2))value or expression?2
end function
+def distanceBetweenname?(p1: tuple[float, float], p2: tuple[float, float]parameter definitions?) -> floatType?:
# function1
return sqrt(pow(p2.item_0 - p1.item_0, 2) + pow(p2.item_1 - p1.item_1, 2))value or expression?2
main()
+static doubleType? distanceBetweenname?((double, double) p1, (double, double) p2parameter definitions?) {
// function1
return sqrt(pow(p2.item_0 - p1.item_0, 2) + pow(p2.item_1 - p1.item_1, 2))value or expression?;2
}
+Function distanceBetweenname?(p1 As (Double, Double), p2 As (Double, Double)parameter definitions?) As DoubleType?
1
Return sqrt(pow(p2.item_0 - p1.item_0, 2) + pow(p2.item_1 - p1.item_1, 2))value or expression?2
End Function
+static doubleType? distanceBetweenname?((double, double) p1, (double, double) p2parameter definitions?) {
// function1
return sqrt(pow(p2.item_0 - p1.item_0, 2) + pow(p2.item_1 - p1.item_1, 2))value or expression?;2
}
Note that the appropriate item_Ns will be listed in the Editor's drop-down menu options for the referenced Tuple.
Function dot methods on a Tuple
function dot methods |
argument Types |
return Type |
returns |
| equals |
Tuple |
Boolean |
true if the Types, item values and order all equal those of the argument, – false otherwise |
| notEqualTo |
Tuple |
Boolean |
true if any of the Types, item values and order differ from those of the argument, – false otherwise |
| toString |
(none) |
String |
String containing Tuple's items surrounded by brackets |
Graphic Types
Block graphics
Block graphics provides a simple way to create low resolution graphics, ideal for simple but engaging games for example.
The graphics are defined and displayed on a grid that is 40 blocks wide by 30 blocks high.
Each block is be rendered as a solid colour.
An example of block graphics to produce a rapidly changing pattern of coloured blocks:
+main
1
variable gridname? set to createBlockGraphics(white)value or expression?2
+while truecondition?
3
variable xname? set to randint(0, 39)value or expression?4
variable yname? set to randint(0, 29)value or expression?5
variable colourname? set to randint(0, white - 1)value or expression?6
set grid[x][y]variableName? to colourvalue or expression?7
call displayBlocksprocedureName?(gridarguments?)8
end while
end main
+def main() -> None:
1
gridname? = createBlockGraphics(white)value or expression? # variable definition2
+while Truecondition?:
3
xname? = randint(0, 39)value or expression? # variable definition4
yname? = randint(0, 29)value or expression? # variable definition5
colourname? = randint(0, white - 1)value or expression? # variable definition6
grid[x][y]variableName? = colourvalue or expression? # change variable7
displayBlocksprocedureName?(gridarguments?) # call procedure8
main()
+static void main() {
1
var gridname? = createBlockGraphics(white)value or expression?;2
+while (truecondition?) {
3
var xname? = randint(0, 39)value or expression?;4
var yname? = randint(0, 29)value or expression?;5
var colourname? = randint(0, white - 1)value or expression?;6
grid[x][y]variableName? = colourvalue or expression?; // change variable7
displayBlocksprocedureName?(gridarguments?); // call procedure8
}
}
+Sub main()
1
Dim gridname? = createBlockGraphics(white)value or expression? ' variable definition2
+While Truecondition?
3
Dim xname? = randint(0, 39)value or expression? ' variable definition4
Dim yname? = randint(0, 29)value or expression? ' variable definition5
Dim colourname? = randint(0, white - 1)value or expression? ' variable definition6
grid[x][y]variableName? = colourvalue or expression? ' change variable7
displayBlocksprocedureName?(gridarguments?) ' call procedure8
End While
End Sub
+static void main() {
1
var gridname? = createBlockGraphics(white)value or expression?;2
+while (truecondition?) {
3
var xname? = randint(0, 39)value or expression?;4
var yname? = randint(0, 29)value or expression?;5
var colourname? = randint(0, white - 1)value or expression?;6
grid[x][y]variableName? = colourvalue or expression?; // change variable7
displayBlocksprocedureName?(gridarguments?); // call procedure8
}
}
Notes
- The definition of the grid is made using the system method createBlockGraphics which initialises
a List<of List<of Int>> structure
containing 40 columns × 30 rows.
- Each cell of the grid is referenced by integers x,y where x is in [0..39] and y is in [0..29].
- x,y is 0,0 at the top left cell of the grid, positive x to the right, positive y downwards.
- You may create multiple such structures holding different patterns of blocks, and switch between them
just by passing the required one as the argument to method displayBlocks.
- Any List<of List<of Int>> structure of the same
40 × 30 dimensions can be the argument to method displayBlocks.
- A colour is specified as an Int, as described under Colours.
Turtle graphics
Turtle graphics are implemented with output to the IDE's display pane, i.e. the 'paper' on which the turtle draws.
The area is 200 turtle units wide by 150 turtle units high, and both integer and floating point values of turtle units can be used.
If a turtle is placed or moved outside the 200 × 150 area boundary, it will not cause an error,
but the turtle and any lines drawn outside the boundary will not be visible.
The origin for turtle units (0,0) is at the centre of the area: positive x rightwards, positive y upwards.
So the top left corner of the display is at (-100,75).
A new turtle's default starting position is at (0,0) facing upwards (heading is 0), from where a move will be in the y direction.
You can move and turn a turtle, causing lines to be drawn, whether or not the turtle is showing.
Procedure methods on a Turtle
procedure method |
argument Types |
action |
| clearAndReset |
(none) |
clears the turtle display and moves the turtle to its starting position and heading |
| hide |
(none) |
makes the turtle invisible in the display |
| move |
Int or Float |
moves the turtle the specified number of turtle units in the direction of its heading or, if negative, in the opposite direction |
| moveTo |
Int or Float,
Int or Float |
moves the turtle to the specified x,y position, drawing its path if its pen is down |
| penColour |
Int |
changes the colour of its path in the display to the literal or named value specified |
| penDown |
(none) |
makes the turtle's subsequent moves leave a trace of its path in the display |
| penUp |
(none) |
makes the turtle's subsequent moves leave no trace of its path in the display |
| penWidth |
Int or Float |
changes the width of the line tracing the turtle's path in the display default (and minimum) is 1 |
| placeAt |
Int or Float,
Int or Float |
places or repositions the turtle at the x,y position specified without drawing a path |
| show |
(none) |
makes the turtle visible in the display as a green blob marked with a black radius that indicates its heading |
| turn |
Int or Float |
turns the turtle through the specified number of degrees clockwise or, if negative, anticlockwise |
| turnToHeading |
Int or Float |
turns the turtle to face in the direction specified in degrees where 0 is upward and increasing values go clockwise from there |
Properties of a Turtle
The current location and heading of the turtle may be read using the properties
x, y, and heading.
| Property |
|
| name |
Type |
description |
default |
| heading |
Float |
the direction in which the turtle is pointing in degrees clockwise from North |
0.0 degrees, i.e. upward in the display |
| x, y |
Float, Float |
the x,y coordinates of the turtle's current position |
0.0, 0.0 |
Examples using turtle graphics
▶ To draw a square:
+main
1
variable tname? set to new Turtle()value or expression?2
call t.placeAtprocedureName?(-75, 50arguments?)3
call t.showprocedureName?(arguments?)4
+for iitem? in range(1, 5)source?
5
call t.turnprocedureName?(90arguments?)6
call t.moveprocedureName?(80arguments?)7
call sleepprocedureName?(0.5arguments?)8
end for
end main
+def main() -> None:
1
tname? = Turtle()value or expression? # variable definition2
t.placeAtprocedureName?(-75, 50arguments?) # call procedure3
t.showprocedureName?(arguments?) # call procedure4
+for iitem? in range(1, 5)source?:
5
t.turnprocedureName?(90arguments?) # call procedure6
t.moveprocedureName?(80arguments?) # call procedure7
sleepprocedureName?(0.5arguments?) # call procedure8
main()
+static void main() {
1
var tname? = new Turtle()value or expression?;2
t.placeAtprocedureName?(-75, 50arguments?); // call procedure3
t.showprocedureName?(arguments?); // call procedure4
+foreach (iitem? in range(1, 5)source?) {
5
t.turnprocedureName?(90arguments?); // call procedure6
t.moveprocedureName?(80arguments?); // call procedure7
sleepprocedureName?(0.5arguments?); // call procedure8
}
}
+Sub main()
1
Dim tname? = New Turtle()value or expression? ' variable definition2
t.placeAtprocedureName?(-75, 50arguments?) ' call procedure3
t.showprocedureName?(arguments?) ' call procedure4
+For Each iitem? In range(1, 5)source?
5
t.turnprocedureName?(90arguments?) ' call procedure6
t.moveprocedureName?(80arguments?) ' call procedure7
sleepprocedureName?(0.5arguments?) ' call procedure8
Next i
End Sub
+static void main() {
1
var tname? = new Turtle()value or expression?;2
t.placeAtprocedureName?(-75, 50arguments?); // call procedure3
t.showprocedureName?(arguments?); // call procedure4
+foreach (iitem? in range(1, 5)source?) {
5
t.turnprocedureName?(90arguments?); // call procedure6
t.moveprocedureName?(80arguments?); // call procedure7
sleepprocedureName?(0.5arguments?); // call procedure8
}
}
▶ To draw a fractal snowflake, using a procedure and recursion:
+main
1
variable tname? set to new Turtle()value or expression?2
call t.placeAtprocedureName?(-50, 30arguments?)3
call t.turnprocedureName?(90arguments?)4
call t.showprocedureName?(arguments?)5
+for iitem? in range(1, 4)source?
6
call drawSideprocedureName?(side, targuments?)7
call t.turnprocedureName?(120arguments?)8
end for
end main
+constant sidename? set to 100literal value or data structure?9
+procedure drawSidename?(length as Float, t as Turtleparameter definitions?)
10
+if (length > 1)condition? then
11
variable thirdname? set to length/3value or expression?12
call drawSideprocedureName?(third, targuments?)13
call t.turnprocedureName?(-60arguments?)14
call drawSideprocedureName?(third, targuments?)15
call t.turnprocedureName?(120arguments?)16
call drawSideprocedureName?(third, targuments?)17
call t.turnprocedureName?(-60arguments?)18
call drawSideprocedureName?(third, targuments?)19
else20
call t.moveprocedureName?(lengtharguments?)21
end if
end procedure
+def main() -> None:
1
tname? = Turtle()value or expression? # variable definition2
t.placeAtprocedureName?(-50, 30arguments?) # call procedure3
t.turnprocedureName?(90arguments?) # call procedure4
t.showprocedureName?(arguments?) # call procedure5
+for iitem? in range(1, 4)source?:
6
drawSideprocedureName?(side, targuments?) # call procedure7
t.turnprocedureName?(120arguments?) # call procedure8
+sidename? = 100literal value or data structure? # constant9
+def drawSidename?(length: float, t: Turtleparameter definitions?) -> None:
# procedure10
+if (length > 1)condition?:
11
thirdname? = length/3value or expression? # variable definition12
drawSideprocedureName?(third, targuments?) # call procedure13
t.turnprocedureName?(-60arguments?) # call procedure14
drawSideprocedureName?(third, targuments?) # call procedure15
t.turnprocedureName?(120arguments?) # call procedure16
drawSideprocedureName?(third, targuments?) # call procedure17
t.turnprocedureName?(-60arguments?) # call procedure18
drawSideprocedureName?(third, targuments?) # call procedure19
else:20
t.moveprocedureName?(lengtharguments?) # call procedure21
main()
+static void main() {
1
var tname? = new Turtle()value or expression?;2
t.placeAtprocedureName?(-50, 30arguments?); // call procedure3
t.turnprocedureName?(90arguments?); // call procedure4
t.showprocedureName?(arguments?); // call procedure5
+foreach (iitem? in range(1, 4)source?) {
6
drawSideprocedureName?(side, targuments?); // call procedure7
t.turnprocedureName?(120arguments?); // call procedure8
}
}
+const Int sidename? = 100literal value or data structure?9
+static void drawSidename?(double length, Turtle tparameter definitions?) {
// procedure10
+if ((length > 1)condition?) {
11
var thirdname? = length/3value or expression?;12
drawSideprocedureName?(third, targuments?); // call procedure13
t.turnprocedureName?(-60arguments?); // call procedure14
drawSideprocedureName?(third, targuments?); // call procedure15
t.turnprocedureName?(120arguments?); // call procedure16
drawSideprocedureName?(third, targuments?); // call procedure17
t.turnprocedureName?(-60arguments?); // call procedure18
drawSideprocedureName?(third, targuments?); // call procedure19
} else {20
t.moveprocedureName?(lengtharguments?); // call procedure21
}
}
+Sub main()
1
Dim tname? = New Turtle()value or expression? ' variable definition2
t.placeAtprocedureName?(-50, 30arguments?) ' call procedure3
t.turnprocedureName?(90arguments?) ' call procedure4
t.showprocedureName?(arguments?) ' call procedure5
+For Each iitem? In range(1, 4)source?
6
drawSideprocedureName?(side, targuments?) ' call procedure7
t.turnprocedureName?(120arguments?) ' call procedure8
Next i
End Sub
+Const sidename? = 100literal value or data structure?9
+Sub drawSidename?(length As Double, t As Turtleparameter definitions?)
' procedure10
+If (length > 1)condition? Then
11
Dim thirdname? = length/3value or expression? ' variable definition12
drawSideprocedureName?(third, targuments?) ' call procedure13
t.turnprocedureName?(-60arguments?) ' call procedure14
drawSideprocedureName?(third, targuments?) ' call procedure15
t.turnprocedureName?(120arguments?) ' call procedure16
drawSideprocedureName?(third, targuments?) ' call procedure17
t.turnprocedureName?(-60arguments?) ' call procedure18
drawSideprocedureName?(third, targuments?) ' call procedure19
Else20
t.moveprocedureName?(lengtharguments?) ' call procedure21
End If
End Sub
+static void main() {
1
var tname? = new Turtle()value or expression?;2
t.placeAtprocedureName?(-50, 30arguments?); // call procedure3
t.turnprocedureName?(90arguments?); // call procedure4
t.showprocedureName?(arguments?); // call procedure5
+foreach (iitem? in range(1, 4)source?) {
6
drawSideprocedureName?(side, targuments?); // call procedure7
t.turnprocedureName?(120arguments?); // call procedure8
}
}
+final Int sidename? = 100literal value or data structure? // constant9
+static void drawSidename?(double length, Turtle tparameter definitions?) {
// procedure10
+if ((length > 1)condition?) {
11
var thirdname? = length/3value or expression?;12
drawSideprocedureName?(third, targuments?); // call procedure13
t.turnprocedureName?(-60arguments?); // call procedure14
drawSideprocedureName?(third, targuments?); // call procedure15
t.turnprocedureName?(120arguments?); // call procedure16
drawSideprocedureName?(third, targuments?); // call procedure17
t.turnprocedureName?(-60arguments?); // call procedure18
drawSideprocedureName?(third, targuments?); // call procedure19
} else {20
t.moveprocedureName?(lengtharguments?); // call procedure21
}
}

Vector graphics
Vector graphics are implemented using the SVG (Scalable Vector Graphics) Html tag <svg>, and are output to the display pane in the user interface.
The area is 100 units wide by 75 units high, and both integer and floating point values of the units can be used.
The origin of the units (0,0) is at the top left corner of the display: positive x rightwards, positive y downwards.
So for example the centre of the display is at (50, 37.5).
The names of the shapes broadly correspond to the names of SVG tags:
- CircleVG for <circle../>
- ImageVG for <image../>
- LineVG for <line../>
- RectangleVG for <rect../>
The properties of these shapes are named to reflect the attributes used in the SVG tags but some names differ. For example, SVG's stroke-width
is set with property strokeWidth, to make it a valid identifier.
Also stroke and fill are set by the properties strokeColour and fillColour.
In addition, graphics may be displayed from any valid string of SVG tags, as described in RawVG.
Defining Vector graphic shapes
A set of SVG shapes is defined in either a List<of VectorGraphic> or a List of any specific Type of VectorGraphic (e.g. List<of CircleVG>) by using the List append method.
VectorGraphic is the abstract superclass of all ..VG shapes. You use it when you want to define a List holding different types of shape.
Adding a shape returns a new instance of the list which must be assigned to a new or existing variable.
The constructors for the VG Types require arguments defining the attributes of the relevant SVG tags, so defaults are supplied from the Class properties,
as shown in the table below.
To change the value of property 'p..', call the setP.. procedure method on the vector graphic or,
in a function, use the withP.. dot method on the vector graphic, in either case specifying new values in the arguments.
The fillColour and strokeColour properties may be specified as described under Colours.
Only fillColour can be specified as transparent.
Note that the height and width properties of an image are also dependent on the dimensions of the original graphic file.
Displaying Vector graphic shapes
As with Block graphics, the assembled list of shapes is not displayed until call procedure displayVectorGraphics with the list as its argument, thus allowing you to make multiple changes before display.
And as with using SVG in Html, the shapes are drawn in the order in which they are added to the VectorGraphic instance.
Later shapes are positioned in front of earlier ones.
Function dot methods on Vector graphic shapes
function dot method |
on Type |
argument Types |
return Type |
returns |
| asHtml |
ImageVG |
none |
String |
string containing the Html <img> tag filled with the image's URL and attribute values |
| asSVG |
CircleVG |
none |
String |
string containing the SVG <circle> tag filled with the circle's attribute values |
| asSVG |
ImageVG |
none |
String |
string containing the SVG <image> tag filled with the image's URL and attribute values |
| asSVG |
LineVG |
none |
String |
string containing the SVG <line> tag filled with the line's attribute values |
| asSVG |
RectangleVG |
none |
String |
string containing the SVG <rectangle> tag filled with the rectangle's attribute values |
Properties of Vector graphic shapes
This table lists the properties of the Vector graphic shapes and their default values,
together with the procedure and function methods provided to alter their values in a given instance.
| Property |
Vector graphic shape |
Property |
Method
|
| name |
Type |
CircleVG |
ImageVG |
LineVG |
RectangleVG |
description |
default |
procedure |
function |
| alt |
String |
|
✔ |
|
|
alternate textual description (for accessibility) |
empty string |
setAlt |
withAlt |
| centreX |
Float |
✔ |
|
|
|
horizontal position of circle centre |
50 |
setCentreX |
withCentreX |
| centreY |
Float |
✔ |
|
|
|
vertical position of circle centre |
37.5 |
setCentreY |
withCentreY |
| fillColour |
Int |
✔ |
|
|
✔ |
colour to fill the shape |
yellow |
setFillColour |
withFillColour |
| height |
Float |
|
✔ |
|
✔ |
height to render the shape or the image |
Image: 13.2 Rectangle: 20 |
setHeight |
withHeight |
| radius |
Float |
✔ |
|
|
|
radius of circle |
10 |
setRadius |
withRadius |
| strokeColour |
Int |
✔ |
|
✔ |
✔ |
colour of the strokes in the shape |
black |
setStrokeColour |
withStrokeColour |
| strokeWidth |
Int |
✔ |
|
✔ |
✔ |
width of the strokes in the shape |
1 |
setStrokeWidth |
withStrokeWidth |
| title |
Float |
|
✔ |
|
|
title text |
empty string |
setTitle |
withTitle |
| width |
Float |
|
✔ |
|
✔ |
width to render the shape or the image |
Image: 13.2 Rectangle: 40 |
setWidth |
withWidth |
| x, y |
Float, Float |
|
✔ ✔ |
|
✔ ✔ |
image's x,y position from top left |
Image: 0, 0 Rectangle: 10, 10 |
setX, setY |
withX, withY |
| x1, y1 |
Float, Float |
|
|
✔ ✔ |
|
line's starting x,y position from top left |
10, 10 |
setX1, setY1 |
withX1, withY1 |
| x2, y2 |
Float, Float |
|
|
✔ ✔ |
|
line's ending x,y position from top left |
70, 40 |
setX2, setY2 |
withX2, withY2 |
Examples using simple SVG graphics
▶ To draw a circle with a coloured circumference:
+main
1
variable vgname? set to new List<of VectorGraphic>()value or expression?2
variable circname? set to new CircleVG()value or expression?3
call circ.setCentreXprocedureName?(20arguments?)4
call circ.setCentreYprocedureName?(20arguments?)5
call circ.setRadiusprocedureName?(5arguments?)6
call circ.setFillColourprocedureName?(greenarguments?)7
call circ.setStrokeColourprocedureName?(redarguments?)8
call circ.setStrokeWidthprocedureName?(2arguments?)9
call vg.appendprocedureName?(circarguments?)10
call displayVectorGraphicsprocedureName?(vgarguments?)11
end main
+def main() -> None:
1
vgname? = list[VectorGraphic]()value or expression? # variable definition2
circname? = CircleVG()value or expression? # variable definition3
circ.setCentreXprocedureName?(20arguments?) # call procedure4
circ.setCentreYprocedureName?(20arguments?) # call procedure5
circ.setRadiusprocedureName?(5arguments?) # call procedure6
circ.setFillColourprocedureName?(greenarguments?) # call procedure7
circ.setStrokeColourprocedureName?(redarguments?) # call procedure8
circ.setStrokeWidthprocedureName?(2arguments?) # call procedure9
vg.appendprocedureName?(circarguments?) # call procedure10
displayVectorGraphicsprocedureName?(vgarguments?) # call procedure11
main()
+static void main() {
1
var vgname? = new List<VectorGraphic>()value or expression?;2
var circname? = new CircleVG()value or expression?;3
circ.setCentreXprocedureName?(20arguments?); // call procedure4
circ.setCentreYprocedureName?(20arguments?); // call procedure5
circ.setRadiusprocedureName?(5arguments?); // call procedure6
circ.setFillColourprocedureName?(greenarguments?); // call procedure7
circ.setStrokeColourprocedureName?(redarguments?); // call procedure8
circ.setStrokeWidthprocedureName?(2arguments?); // call procedure9
vg.appendprocedureName?(circarguments?); // call procedure10
displayVectorGraphicsprocedureName?(vgarguments?); // call procedure11
}
+Sub main()
1
Dim vgname? = New List(Of VectorGraphic)()value or expression? ' variable definition2
Dim circname? = New CircleVG()value or expression? ' variable definition3
circ.setCentreXprocedureName?(20arguments?) ' call procedure4
circ.setCentreYprocedureName?(20arguments?) ' call procedure5
circ.setRadiusprocedureName?(5arguments?) ' call procedure6
circ.setFillColourprocedureName?(greenarguments?) ' call procedure7
circ.setStrokeColourprocedureName?(redarguments?) ' call procedure8
circ.setStrokeWidthprocedureName?(2arguments?) ' call procedure9
vg.appendprocedureName?(circarguments?) ' call procedure10
displayVectorGraphicsprocedureName?(vgarguments?) ' call procedure11
End Sub
+static void main() {
1
var vgname? = new List<VectorGraphic>()value or expression?;2
var circname? = new CircleVG()value or expression?;3
circ.setCentreXprocedureName?(20arguments?); // call procedure4
circ.setCentreYprocedureName?(20arguments?); // call procedure5
circ.setRadiusprocedureName?(5arguments?); // call procedure6
circ.setFillColourprocedureName?(greenarguments?); // call procedure7
circ.setStrokeColourprocedureName?(redarguments?); // call procedure8
circ.setStrokeWidthprocedureName?(2arguments?); // call procedure9
vg.appendprocedureName?(circarguments?); // call procedure10
displayVectorGraphicsprocedureName?(vgarguments?); // call procedure11
}

▶ To draw a circle that changes between red and green every second:
+main
1
variable vgname? set to new List<of VectorGraphic>()value or expression?2
variable circname? set to new CircleVG()value or expression?3
call circ.setCentreXprocedureName?(50arguments?)4
call circ.setCentreYprocedureName?(37.5arguments?)5
call circ.setRadiusprocedureName?(30arguments?)6
call circ.setFillColourprocedureName?(greenarguments?)7
call vg.appendprocedureName?(circarguments?)8
+while truecondition?
9
call displayVectorGraphicsprocedureName?(vgarguments?)10
call sleepprocedureName?(1arguments?)11
call circ.setFillColourprocedureName?(redarguments?)12
call displayVectorGraphicsprocedureName?(vgarguments?)13
call sleepprocedureName?(1arguments?)14
call circ.setFillColourprocedureName?(greenarguments?)15
end while
call displayVectorGraphicsprocedureName?(vgarguments?)16
end main
+def main() -> None:
1
vgname? = list[VectorGraphic]()value or expression? # variable definition2
circname? = CircleVG()value or expression? # variable definition3
circ.setCentreXprocedureName?(50arguments?) # call procedure4
circ.setCentreYprocedureName?(37.5arguments?) # call procedure5
circ.setRadiusprocedureName?(30arguments?) # call procedure6
circ.setFillColourprocedureName?(greenarguments?) # call procedure7
vg.appendprocedureName?(circarguments?) # call procedure8
+while Truecondition?:
9
displayVectorGraphicsprocedureName?(vgarguments?) # call procedure10
sleepprocedureName?(1arguments?) # call procedure11
circ.setFillColourprocedureName?(redarguments?) # call procedure12
displayVectorGraphicsprocedureName?(vgarguments?) # call procedure13
sleepprocedureName?(1arguments?) # call procedure14
circ.setFillColourprocedureName?(greenarguments?) # call procedure15
displayVectorGraphicsprocedureName?(vgarguments?) # call procedure16
main()
+static void main() {
1
var vgname? = new List<VectorGraphic>()value or expression?;2
var circname? = new CircleVG()value or expression?;3
circ.setCentreXprocedureName?(50arguments?); // call procedure4
circ.setCentreYprocedureName?(37.5arguments?); // call procedure5
circ.setRadiusprocedureName?(30arguments?); // call procedure6
circ.setFillColourprocedureName?(greenarguments?); // call procedure7
vg.appendprocedureName?(circarguments?); // call procedure8
+while (truecondition?) {
9
displayVectorGraphicsprocedureName?(vgarguments?); // call procedure10
sleepprocedureName?(1arguments?); // call procedure11
circ.setFillColourprocedureName?(redarguments?); // call procedure12
displayVectorGraphicsprocedureName?(vgarguments?); // call procedure13
sleepprocedureName?(1arguments?); // call procedure14
circ.setFillColourprocedureName?(greenarguments?); // call procedure15
}
displayVectorGraphicsprocedureName?(vgarguments?); // call procedure16
}
+Sub main()
1
Dim vgname? = New List(Of VectorGraphic)()value or expression? ' variable definition2
Dim circname? = New CircleVG()value or expression? ' variable definition3
circ.setCentreXprocedureName?(50arguments?) ' call procedure4
circ.setCentreYprocedureName?(37.5arguments?) ' call procedure5
circ.setRadiusprocedureName?(30arguments?) ' call procedure6
circ.setFillColourprocedureName?(greenarguments?) ' call procedure7
vg.appendprocedureName?(circarguments?) ' call procedure8
+While Truecondition?
9
displayVectorGraphicsprocedureName?(vgarguments?) ' call procedure10
sleepprocedureName?(1arguments?) ' call procedure11
circ.setFillColourprocedureName?(redarguments?) ' call procedure12
displayVectorGraphicsprocedureName?(vgarguments?) ' call procedure13
sleepprocedureName?(1arguments?) ' call procedure14
circ.setFillColourprocedureName?(greenarguments?) ' call procedure15
End While
displayVectorGraphicsprocedureName?(vgarguments?) ' call procedure16
End Sub
+static void main() {
1
var vgname? = new List<VectorGraphic>()value or expression?;2
var circname? = new CircleVG()value or expression?;3
circ.setCentreXprocedureName?(50arguments?); // call procedure4
circ.setCentreYprocedureName?(37.5arguments?); // call procedure5
circ.setRadiusprocedureName?(30arguments?); // call procedure6
circ.setFillColourprocedureName?(greenarguments?); // call procedure7
vg.appendprocedureName?(circarguments?); // call procedure8
+while (truecondition?) {
9
displayVectorGraphicsprocedureName?(vgarguments?); // call procedure10
sleepprocedureName?(1arguments?); // call procedure11
circ.setFillColourprocedureName?(redarguments?); // call procedure12
displayVectorGraphicsprocedureName?(vgarguments?); // call procedure13
sleepprocedureName?(1arguments?); // call procedure14
circ.setFillColourprocedureName?(greenarguments?); // call procedure15
}
displayVectorGraphicsprocedureName?(vgarguments?); // call procedure16
}
RawVG
Strings containing raw SVG tags may be assembled and plotted directly using Class RawVG.
By this means features such as simple SVG animation can be defined.
- The raw SVG content should be enclosed in double quotes within which the SVG attribute values must be enclosed in single quotes.
- To include interpolated values, you precede the string with a $.
- The raw SVG may define multiple shapes.
- Multiple instances of RawVG may be added to the collection to be displayed, along with instances of other SVG Types;
hence the need for list-defining square brackets in the parameter of method displayVectorGraphics.
- Method withContent is used to specify the property of Class RawVG that must contain the SVG string.
- The example is of a simple animation in which the repetition defined in the SVG continues after the program has stopped,
so you would then use the Clear button to blank the display.
Example using RawVG
▶ To display a repeating movement of a circle:
+main
1
variable movingCirclename? set to "<circle cx='50' cy='50' r='50' style='fill:red;'>\n<animate attributeName='cx' begin='0s' dur='2s' from='50' to='90%' repeatCount='indefinite' /></circle>"value or expression?2
variable rawname? set to (new RawVG()).withContent(movingCircle)value or expression?3
call displayVectorGraphicsprocedureName?([raw]arguments?)4
end main
+def main() -> None:
1
movingCirclename? = "<circle cx='50' cy='50' r='50' style='fill:red;'>\n<animate attributeName='cx' begin='0s' dur='2s' from='50' to='90%' repeatCount='indefinite' /></circle>"value or expression? # variable definition2
rawname? = (RawVG()).withContent(movingCircle)value or expression? # variable definition3
displayVectorGraphicsprocedureName?([raw]arguments?) # call procedure4
main()
+static void main() {
1
var movingCirclename? = "<circle cx='50' cy='50' r='50' style='fill:red;'>\n<animate attributeName='cx' begin='0s' dur='2s' from='50' to='90%' repeatCount='indefinite' /></circle>"value or expression?;2
var rawname? = (new RawVG()).withContent(movingCircle)value or expression?;3
displayVectorGraphicsprocedureName?([raw]arguments?); // call procedure4
}
+Sub main()
1
Dim movingCirclename? = "<circle cx='50' cy='50' r='50' style='fill:red;'>\n<animate attributeName='cx' begin='0s' dur='2s' from='50' to='90%' repeatCount='indefinite' /></circle>"value or expression? ' variable definition2
Dim rawname? = (New RawVG()).withContent(movingCircle)value or expression? ' variable definition3
displayVectorGraphicsprocedureName?({raw}arguments?) ' call procedure4
End Sub
+static void main() {
1
var movingCirclename? = "<circle cx='50' cy='50' r='50' style='fill:red;'>\n<animate attributeName='cx' begin='0s' dur='2s' from='50' to='90%' repeatCount='indefinite' /></circle>"value or expression?;2
var rawname? = (new RawVG()).withContent(movingCircle)value or expression?;3
displayVectorGraphicsprocedureName?([raw]arguments?); // call procedure4
}
Combining graphic outputs
Program outputs, whether text or graphical, can be combined in the display. In particular, Block graphics and text or Html printing can share the display
along with either Vector graphics or Turtle graphics (but not both).
If you want to share the display in this way, remember that both text and Html print outputs appear sequentially down the display (which can be scrolled), whereas the graphic outputs are positioned in the display using their own absolute coordinate systems.
The order in which the outputs are displayed (and therefore overwrite) is:
- Block graphics
- Vector or Turtle graphics
- Printed text or Html
So some care is needed to manage the layout in the display.
Note that, while vector graphics are being drawn, printed text that exceeds the height of the display does not scroll until the graphic completes.
Other Types
Random
Generating random numbers within a function
It is not possible to use the system methods random or randint within a function because they create unseen side effects. You may use those system methods outside the function and pass the resulting random number (as an Int or a Float) as an argument into a function.
It is, however, possible to create and use random numbers within a function, but it requires a different approach and is a little more complex. You use the special Type Random. (Note the upper case R required for a Type name).
You start by getting a seed random number in your main or in a procedure using method initialiseFromClock:
variable randname? set to new Random()value or expression?0
randname? = Random()value or expression? # variable definition0
var randname? = new Random()value or expression?;0
Dim randname? = New Random()value or expression? ' variable definition0
var randname? = new Random()value or expression?;0
call rand.initialiseFromClockprocedureName?(arguments?)0
rand.initialiseFromClockprocedureName?(arguments?) # call procedure0
rand.initialiseFromClockprocedureName?(arguments?); // call procedure0
rand.initialiseFromClockprocedureName?(arguments?) ' call procedure0
rand.initialiseFromClockprocedureName?(arguments?); // call procedure0
Then, in a function, you apply the dot method next or nextInt to the Random passed in, which returns a 2-Tuple containing both a new random value and a new instance of Type Random.
If you need another random value, you use the returned Random on which to apply the dot method again.
Avoid applying next or nextInt more than once on the same Random because they will return the same values.
If the initialiseFromClock call is absent, the program will still generate a sequence of random values, but the sequence will be exactly the same each time you run the program. Initialising from the clock ensures that you get a different sequence each run. Using Random without so initialising, however, can be extremely useful for testing purposes since the results are repeatable.
Procedure method for random seed
procedure method |
argument Type |
action |
| initialiseFromClock |
(none) |
uses the system clock to provide a seed from which to generate fresh random values |
Function dot methods on a Random
function dot method |
argument Types |
return Types |
returns |
| next |
Float, Float |
2-Tuple: (Float, Random) |
random Float value in the range of the arguments, and new instance of Random for subsequent use |
| nextInt |
Int, Int |
2-Tuple: (Int, Random) |
random Int value in the range of the arguments, and new instance of Random for subsequent use |
Example using Random
▶ To roll a dice in a function:
+main
1
variable rndname? set to new Random()value or expression?2
call rnd.initialiseFromClockprocedureName?(arguments?)3
variable dicename? set to 0value or expression?4
+for iitem? in range(1, 11)source?
5
set dicevariableName? to rollDice(rnd).item_0value or expression?6
set rndvariableName? to rollDice(rnd).item_1value or expression?7
call printprocedureName?(dicearguments?)8
end for
end main
+function rollDicename?(rnd as Randomparameter definitions?) returns (Int, Random)Type?
9
return rnd.nextInt(1, 6)value or expression?10
end function
+def main() -> None:
1
rndname? = Random()value or expression? # variable definition2
rnd.initialiseFromClockprocedureName?(arguments?) # call procedure3
dicename? = 0value or expression? # variable definition4
+for iitem? in range(1, 11)source?:
5
dicevariableName? = rollDice(rnd).item_0value or expression? # change variable6
rndvariableName? = rollDice(rnd).item_1value or expression? # change variable7
printprocedureName?(dicearguments?)8
+def rollDicename?(rnd: Randomparameter definitions?) -> tuple[int, Random]Type?:
# function9
return rnd.nextInt(1, 6)value or expression?10
main()
+static void main() {
1
var rndname? = new Random()value or expression?;2
rnd.initialiseFromClockprocedureName?(arguments?); // call procedure3
var dicename? = 0value or expression?;4
+foreach (iitem? in range(1, 11)source?) {
5
dicevariableName? = rollDice(rnd).item_0value or expression?; // change variable6
rndvariableName? = rollDice(rnd).item_1value or expression?; // change variable7
printprocedureName?(dicearguments?);8
}
}
+static (int, Random)Type? rollDicename?(Random rndparameter definitions?) {
// function9
return rnd.nextInt(1, 6)value or expression?;10
}
+Sub main()
1
Dim rndname? = New Random()value or expression? ' variable definition2
rnd.initialiseFromClockprocedureName?(arguments?) ' call procedure3
Dim dicename? = 0value or expression? ' variable definition4
+For Each iitem? In range(1, 11)source?
5
dicevariableName? = rollDice(rnd).item_0value or expression? ' change variable6
rndvariableName? = rollDice(rnd).item_1value or expression? ' change variable7
printprocedureName?(dicearguments?)8
Next i
End Sub
+Function rollDicename?(rnd As Randomparameter definitions?) As (Integer, Random)Type?
9
Return rnd.nextInt(1, 6)value or expression?10
End Function
+static void main() {
1
var rndname? = new Random()value or expression?;2
rnd.initialiseFromClockprocedureName?(arguments?); // call procedure3
var dicename? = 0value or expression?;4
+foreach (iitem? in range(1, 11)source?) {
5
dicevariableName? = rollDice(rnd).item_0value or expression?; // change variable6
rndvariableName? = rollDice(rnd).item_1value or expression?; // change variable7
printprocedureName?(dicearguments?);8
}
}
+static (int, Random)Type? rollDicename?(Random rndparameter definitions?) {
// function9
return rnd.nextInt(1, 6)value or expression?;10
}
Func
A function may be passed as an argument into another function (or a procedure), or returned as the result of calling another function.
This pattern is known as Higher-order Function (HoF), and is a key idea in Functional Programming.
To define a function that takes in another function as a parameter, or returns a function, you need to specify the Type of the function,
just as you would specify the Type of every parameter and the return Type for the function.
Type name
The Type of any function starts with the word Func followed by angle brackets defining the Type of each parameter,
then a 'fat arrow' => and the return Type for that function. This property definition shows the syntax:
+constructor(parameter definitions?)
0
new code
end constructor
property matchAt as Func Boolean>
Code does not parse as Elan.
property matchAt as Func Boolean>
Code does not parse as Elan.
+Sub New(parameter definitions?)
0
new code
End Sub
property matchAt as Func Boolean>
Code does not parse as Elan.
This example defines the Type for a function that defines three parameters of Type String, String, and Int respectively, and returns a Boolean value. This Type would match that of a function definition like this:
function matchAt(a as String, b as String, p as Int) returns Boolean
return if a[p].equals(b[p]) then true else false
end function
Code does not parse as Elan.
function matchAt(a as String, b as String, p as Int) returns Boolean
return if a[p].equals(b[p]) then true else false
end function
Code does not parse as Elan.
function matchAt(a as String, b as String, p as Int) returns Boolean
return if a[p].equals(b[p]) then true else false
end function
Code does not parse as Elan.
function matchAt(a as String, b as String, p as Int) returns Boolean
return if a[p].equals(b[p]) then true else false
end function
Code does not parse as Elan.
function matchAt(a as String, b as String, p as Int) returns Boolean
return if a[p].equals(b[p]) then true else false
end function
Code does not parse as Elan.
This section covers a variety of input and output facilities:
soliciting and retrieving keyboard input requires using these system methods:
system method |
argument Types |
return Types |
action |
| getKey |
(none) |
String |
returns the last character last pressed on the keyboard during program execution |
| getKeyWithModifier |
(none) |
2-Tuple: (String, String) |
returns the last key combination pressed on the keyboard:
the key pressed and the modifier key's name (if also pressed) |
| getNumericKey |
(none) |
String |
returns either the numeric key last pressed or, if the last pressed key was not numeric, then "-1" |
| input |
String |
String |
prints the string as a prompt, and returns the typed input when Enter is pressed |
| inputStringWithLimits |
String, Int, Int |
String |
prints the string as a prompt and returns the typed input when Enter is pressed
provided the length of the response is within the minimum and maximum limits specified.
If it is not, the prompt is repeated with the relevant limit displayed |
| inputStringFromOptions |
String, List<of String> |
String |
prints the string as a prompt and returns the typed input when Enter is pressed
provided it is one of the options in the list.
If it is not, the prompt is repeated with the options displayed |
| inputInt |
String |
Int |
prints the string as a prompt and returns the value of the typed input when Enter is pressed
provided that it is an integer. If it is not, the prompt is repeated with an error message |
| inputIntBetween |
String, Int, Int |
Int |
prints the string as a prompt and returns the value of the typed input when Enter is pressed
provided that it is an integer with a value in the (inclusive) range. The first range value must be less than or equal to the second |
| inputFloat |
String |
Float |
prints the string as a prompt and returns the value of the typed input when Enter is pressed
provided that it is a number. If it is not, the prompt is repeated with an error message |
| inputFloatBetween |
String, Int, Int |
Float |
prints the string as a prompt and returns the value of the typed input when Enter is pressed
provided that it is a number with a value in the (inclusive) range. The first range value must be less than or equal to the second |
| waitForKey |
(none) |
String |
pauses execution of the program until a key is pressed on the keyboard,
and returns either a character or the name of a non-character key |
Reading keys 'on the fly'
In some applications – especially in games, for example – you want the program to react to a key pressed by the user, but without holding up the program to wait for value to be input.
Whether your application makes use of graphics, or uses the display just for text, reading keystrokes 'on the fly' is done via one of the three methods shown here:
+main
1
variable key1name? set to getKey()value or expression?2
variable key2name? set to getNumericKey()value or expression?3
variable kmname? set to getKeyWithModifier()value or expression?4
variable keyCapname? set to km.item_0value or expression?5
variable keyModname? set to km.item_1value or expression?6
end main
+def main() -> None:
1
key1name? = getKey()value or expression? # variable definition2
key2name? = getNumericKey()value or expression? # variable definition3
kmname? = getKeyWithModifier()value or expression? # variable definition4
keyCapname? = km.item_0value or expression? # variable definition5
keyModname? = km.item_1value or expression? # variable definition6
main()
+static void main() {
1
var key1name? = getKey()value or expression?;2
var key2name? = getNumericKey()value or expression?;3
var kmname? = getKeyWithModifier()value or expression?;4
var keyCapname? = km.item_0value or expression?;5
var keyModname? = km.item_1value or expression?;6
}
+Sub main()
1
Dim key1name? = getKey()value or expression? ' variable definition2
Dim key2name? = getNumericKey()value or expression? ' variable definition3
Dim kmname? = getKeyWithModifier()value or expression? ' variable definition4
Dim keyCapname? = km.item_0value or expression? ' variable definition5
Dim keyModname? = km.item_1value or expression? ' variable definition6
End Sub
+static void main() {
1
var key1name? = getKey()value or expression?;2
var key2name? = getNumericKey()value or expression?;3
var kmname? = getKeyWithModifier()value or expression?;4
var keyCapname? = km.item_0value or expression?;5
var keyModname? = km.item_1value or expression?;6
}
- When any of these functions (except waitForKey) is called, the system does not wait for a response, but immediately returns a String or Tuple.
- getKey returns a string containing the keyboard character last pressed, possibly shifted, e.g. "z" or "@".
- getNumericKey returns a string containing either a digit ("0".."9") or, if the last key pressed was not numeric, then "-1".
A digit will be returned if the key pressed was either from the main keyboard, or from the numeric keypad when NumLock is on.
- getKeyWithModifier returns a 2-Tuple of two strings: the key last pressed and the name of one modifier key "Shift",
"Ctrl" or "Alt" if simultaneously pressed.
If no modifier had been pressed, the Tuple's second item will be the empty string. Note that a few such modified keys will be acted on by the browser and may not then be passed to your program.
- Non-printable keys will also be returned as strings, e.g. "Home", "End", "Delete", "Tab",
"Backspace", "Enter", "Escape",
"ArrowUp" etc., function key "Fn", "AltGraph", "Meta", "ContextMenu", as well as most others.
- Pressing just control keys Shift, Ctrl (⌘ Command under macOS) or Alt keys will not be detected by getKey.
- If no key has been pressed (since the last time the method was called), it will return the empty string.
- All these methods are system methods because they have a dependency on the system and so may be used only within a procedure or in main.
- Use the procedure method clearKeyBuffer if you want to enforce that the user cannot get too far ahead of the program by hitting keys in rapid succession.
- Method waitForKey waits for a key to be pressed, and returns it.
- Procedure methodpressAnyKeyToContinue gives an optional prompt and is used when you don't need to know which key was pressed. Its argument is a Boolean value:
if true, the prompt "Press any key to continue" appears,
if false, no prompt appears.
+main
1
call pressAnyKeyToContinueprocedureName?(?)2
call printprocedureName?("OK, press A or B"arguments?)3
variable keyname? set to waitForKey()value or expression?4
call printprocedureName?($"That was {key}"arguments?)5
end main
+def main() -> None:
1
pressAnyKeyToContinueprocedureName?(?) # call procedure2
printprocedureName?("OK, press A or B"arguments?)3
keyname? = waitForKey()value or expression? # variable definition4
printprocedureName?(f"That was {key}"arguments?)5
main()
+static void main() {
1
pressAnyKeyToContinueprocedureName?(?); // call procedure2
printprocedureName?("OK, press A or B"arguments?);3
var keyname? = waitForKey()value or expression?;4
printprocedureName?($"That was {key}"arguments?);5
}
+Sub main()
1
pressAnyKeyToContinueprocedureName?(?) ' call procedure2
printprocedureName?("OK, press A or B"arguments?)3
Dim keyname? = waitForKey()value or expression? ' variable definition4
printprocedureName?($"That was {key}"arguments?)5
End Sub
+static void main() {
1
pressAnyKeyToContinueprocedureName?(?); // call procedure2
printprocedureName?("OK, press A or B"arguments?);3
var keyname? = waitForKey()value or expression?;4
printprocedureName?(String.format("That was %", key)arguments?);5
}
Reading or writing a text file requires that you open (for reading) or create (for writing) a file using these system methods:
system method |
argument Types |
return Class |
action |
| openFileForReading |
(none) |
TextFileReader |
opens a file system dialog to choose the filename of filetype .txt to be read,
and returns a file handle
see Reading text files |
| createFileForWriting |
String |
TextFileWriter |
sets up a buffer for the data to be output, and specifies a filename (or the empty string)
with or without the default filetype of .txt, and returns a file handle
see Writing text files |
Reading text files
The TextFileReader Class is used to read text data from a file with type extension .txt.
An instance is created by the system method openFileForReading.
The available procedure methods are:
procedure method |
argument Type |
action |
| readLine |
(none) |
reads the next substring from the file that is terminated with a newline |
| readWholeFile |
(none) |
reads the whole file and closes the file |
| endOfFile |
(none) |
returns true after the last line has been read
– otherwise false |
| close |
(none) |
closes the file |
These methods may be used to read a whole file in one go:
+main
1
variable filename? set to openFileForReading()value or expression?2
variable textname? set to file.readWholeFile()value or expression?3
call printprocedureName?(textarguments?)4
end main
+def main() -> None:
1
filename? = openFileForReading()value or expression? # variable definition2
textname? = file.readWholeFile()value or expression? # variable definition3
printprocedureName?(textarguments?)4
main()
+static void main() {
1
var filename? = openFileForReading()value or expression?;2
var textname? = file.readWholeFile()value or expression?;3
printprocedureName?(textarguments?);4
}
+Sub main()
1
Dim filename? = openFileForReading()value or expression? ' variable definition2
Dim textname? = file.readWholeFile()value or expression? ' variable definition3
printprocedureName?(textarguments?)4
End Sub
+static void main() {
1
var filename? = openFileForReading()value or expression?;2
var textname? = file.readWholeFile()value or expression?;3
printprocedureName?(textarguments?);4
}
Notes
- openFileForReading will present the user with a dialog to select the file.
- readWholeFile returns a String containing every character in the file, without any trimming. It automatically closes the file after the read.
- readLine reads as far as the next newline character (\n) and then automatically trims the line to remove any spaces and/or carriage-returns (which some file systems insert after the newline automatically) from the resulting line returned as a String. If this behaviour is not desired, you can use readWholeFile, which does no trimming, and then parse the resulting String into separate lines.
- Calling file.close after reading line by line is strongly recommended to avoid any risk of leaving the file locked. It is not necessary to call it after using readWholeFile because that method automatically closes the file.
- Calling any method on a file that is already closed will result in a runtime error.
Writing text files
The TextFileWriter Class is used to write textual data to a file.
An instance is created by the system method createFileForWriting.
The available procedure methods are:
procedure method |
argument Type |
action |
| writeLine |
String |
writes the string to the buffer |
| writeWholeFile |
String |
writes the string to the buffer and then outputs the buffer to the file system |
| saveAndClose |
none |
writes the buffer to the file system |
These methods may be used to write a whole file in one go:
+main
1
variable filename? set to createFileForWriting("myFile.txt")value or expression?2
call file.writeWholeFileprocedureName?("Text line 1\nText line 2"arguments?)3
end main
+def main() -> None:
1
filename? = createFileForWriting("myFile.txt")value or expression? # variable definition2
file.writeWholeFileprocedureName?("Text line 1\nText line 2"arguments?) # call procedure3
main()
+static void main() {
1
var filename? = createFileForWriting("myFile.txt")value or expression?;2
file.writeWholeFileprocedureName?("Text line 1\nText line 2"arguments?); // call procedure3
}
+Sub main()
1
Dim filename? = createFileForWriting("myFile.txt")value or expression? ' variable definition2
file.writeWholeFileprocedureName?("Text line 1\nText line 2"arguments?) ' call procedure3
End Sub
+static void main() {
1
var filename? = createFileForWriting("myFile.txt")value or expression?;2
file.writeWholeFileprocedureName?("Text line 1\nText line 2"arguments?); // call procedure3
}
Notes
- writeLine adds the string it is passed onto the end of any data previously written, with a newline character (\n) automatically appended.
- When execution reaches saveAndClose you will be presented with a dialog to confirm (or edit) the given filename and location where it is to be saved. It is not therefore strictly necessary to specify a filename when creating the file, since it can be specified by the user in the dialog so, in that case, you might put the empty string "" into the parameter of createFileForWriting.
- writeWholeFile puts the string it is given into the file and then automatically saves the file, so the user will be presented with the same dialog as if saveAndClose had been called.
- Calling any method on a file that has already been closed (by calling either saveAndClose or by writeWholeFile) will result in a runtime error.
- If the user were to click Cancel in the save dialogue, then the program will exit with an error.
To guard against this possibility (it might mean the loss of important data), you should perform the save and close within a try...catch instruction like this (where ElanRuntimeError is a Class provided by Elan for this purpose):
+main
1
variable filename? set to createFileForWriting("squares.txt")value or expression?2
+for iitem? in range(1, (101))source?
3
call file.writeLineprocedureName?($"{i*i}"arguments?)4
end for
+try
5
call file.saveAndCloseprocedureName?(arguments?)6
catch ElanRuntimeErrortype e.g. ElanRuntimeError or CustomError?7
call printprocedureName?("Save cancelled"arguments?)8
end try
end main
+def main() -> None:
1
filename? = createFileForWriting("squares.txt")value or expression? # variable definition2
+for iitem? in range(1, (101))source?:
3
file.writeLineprocedureName?(f"{i*i}"arguments?) # call procedure4
+try:
5
file.saveAndCloseprocedureName?(arguments?) # call procedure6
except ElanRuntimeErrortype e.g. ElanRuntimeError or CustomError?: # catch7
printprocedureName?("Save cancelled"arguments?)8
main()
+static void main() {
1
var filename? = createFileForWriting("squares.txt")value or expression?;2
+foreach (iitem? in range(1, (101))source?) {
3
file.writeLineprocedureName?($"{i*i}"arguments?); // call procedure4
}
+try {
5
file.saveAndCloseprocedureName?(arguments?); // call procedure6
} catch (ElanRuntimeErrortype e.g. ElanRuntimeError or CustomError? evariableName?) {7
printprocedureName?("Save cancelled"arguments?);8
}
}
+Sub main()
1
Dim filename? = createFileForWriting("squares.txt")value or expression? ' variable definition2
+For Each iitem? In range(1, (101))source?
3
file.writeLineprocedureName?($"{i*i}"arguments?) ' call procedure4
Next i
+Try
5
file.saveAndCloseprocedureName?(arguments?) ' call procedure6
Catch evariableName? As ElanRuntimeErrortype e.g. ElanRuntimeError or CustomError?7
printprocedureName?("Save cancelled"arguments?)8
End Try
End Sub
+static void main() {
1
var filename? = createFileForWriting("squares.txt")value or expression?;2
+foreach (iitem? in range(1, (101))source?) {
3
file.writeLineprocedureName?(String.format("%", i*i)arguments?); // call procedure4
}
+try {
5
file.saveAndCloseprocedureName?(arguments?); // call procedure6
} catch (ElanRuntimeErrortype e.g. ElanRuntimeError or CustomError? evariableName?) {7
printprocedureName?("Save cancelled"arguments?);8
}
}
or you could make the code offer the user options: to save again, or to continue without saving.
Rendering Html in the display
If you embed Html code in a string and then attempt to print it, you will see the string displayed literally: the Html tags
will not be recognised. This is for security reasons. However, it is possible to display formatted Html in the display.
The following code:
call displayHtmlprocedureName?("<h1 style='color: blue;'>A heading</h1><p>some text</p>"arguments?)0
displayHtmlprocedureName?("<h1 style='color: blue;'>A heading</h1><p>some text</p>"arguments?) # call procedure0
displayHtmlprocedureName?("<h1 style='color: blue;'>A heading</h1><p>some text</p>"arguments?); // call procedure0
displayHtmlprocedureName?("<h1 style='color: blue;'>A heading</h1><p>some text</p>"arguments?) ' call procedure0
displayHtmlprocedureName?("<h1 style='color: blue;'>A heading</h1><p>some text</p>"arguments?); // call procedure0
will produce:
This Html forms another 'layer' in the IDE's display pane. Any plain text that you print
(using call print() or any of the print procedures)
will be overlaid on top of this.
You can clear just the Html layer in the display using the procedure clearHtml.
For specifying style or other attributes within Html tags, the attribute values should be enclosed in single quotation marks ' as shown above.
Html will recognise single or double quotation marks, but entering double quotation marks would terminate the Elan string.
Alternatively, you could use the constant quotes within curly braces as an interpolated field.
Using an embedded CSS stylesheet
You can also specify a <style> tag at the start of your Html string, to apply to the whole Html being displayed. In this case you would put
the style definition into a named value as a literal but enclosed in single quotes, for example:
+main
1
variable stylename? set to "<style> h1 { color: Red; font-size: 24pt; } p { font-family: Serif; } </style>"value or expression?2
call displayHtmlprocedureName?($"{style}<h1>New heading</h1><p>some new text</p>"arguments?)3
end main
+def main() -> None:
1
stylename? = "&lt;style&gt; h1 { color: Red; font-size: 24pt; } p { font-family: Serif; } &lt;/style&gt;"value or expression? # variable definition2
displayHtmlprocedureName?(f"{style}&lt;h1&gt;New heading&lt;/h1&gt;&lt;p&gt;some new text&lt;/p&gt;"arguments?) # call procedure3
main()
+static void main() {
1
var stylename? = "&lt;style&gt; h1 { color: Red; font-size: 24pt; } p { font-family: Serif; } &lt;/style&gt;"value or expression?;2
displayHtmlprocedureName?($"{style}<h1>New heading</h1><p>some new text</p>"arguments?); // call procedure3
}
+Sub main()
1
Dim stylename? = "&lt;style&gt; h1 { color: Red; font-size: 24pt; } p { font-family: Serif; } &lt;/style&gt;"value or expression? ' variable definition2
displayHtmlprocedureName?($"{style}<h1>New heading</h1><p>some new text</p>"arguments?) ' call procedure3
End Sub
+static void main() {
1
var stylename? = "&lt;style&gt; h1 { color: Red; font-size: 24pt; } p { font-family: Serif; } &lt;/style&gt;"value or expression?;2
displayHtmlprocedureName?(String.format("%&lt;h1&gt;New heading&lt;/h1&gt;&lt;p&gt;some new text&lt;/p&gt;", style)arguments?); // call procedure3
}
will produce:
Displaying images from URLs
An image that can be retrieved with an http or https URL may be sent to the display, though note that other URI schemes, such as in file://host/path to access an image from your local file system, are not supported. Here are two techniques:
Sound
The tone procedure allows the generation of a simple tone. It requires three arguments to be provided:
- the duration of the generated tone specified in milliseconds (Int)
- the frequency of the generated tone in Hertz (Int)
- the volume of the tone (Float)
Note that the volume parameter is only relative in that the actual volume will be modified by the various sound settings on the output device, and may even be muted.
Example using tone
▶ An example that plays a C major scale first ascending then descending:
+main
1
variable scalename? set to [262, 294, 330, 349, 392, 440, 494, 523]value or expression?2
variable scaleLname? set to scale.length()value or expression?3
variable quavername? set to 250value or expression?4
variable volumename? set to 1.5value or expression?5
+for iitem? in range(0, scaleL)source?
6
call toneprocedureName?(quaver, scale[i], volumearguments?)7
end for
call sleepprocedureName?(1arguments?)8
+for iitem? in range(0, scaleL)source?
9
call toneprocedureName?(quaver, scale[scaleL - 1 - i], volumearguments?)10
end for
end main
+def main() -> None:
1
scalename? = [262, 294, 330, 349, 392, 440, 494, 523]value or expression? # variable definition2
scaleLname? = scale.length()value or expression? # variable definition3
quavername? = 250value or expression? # variable definition4
volumename? = 1.5value or expression? # variable definition5
+for iitem? in range(0, scaleL)source?:
6
toneprocedureName?(quaver, scale[i], volumearguments?) # call procedure7
sleepprocedureName?(1arguments?) # call procedure8
+for iitem? in range(0, scaleL)source?:
9
toneprocedureName?(quaver, scale[scaleL - 1 - i], volumearguments?) # call procedure10
main()
+static void main() {
1
var scalename? = [262, 294, 330, 349, 392, 440, 494, 523]value or expression?;2
var scaleLname? = scale.length()value or expression?;3
var quavername? = 250value or expression?;4
var volumename? = 1.5value or expression?;5
+foreach (iitem? in range(0, scaleL)source?) {
6
toneprocedureName?(quaver, scale[i], volumearguments?); // call procedure7
}
sleepprocedureName?(1arguments?); // call procedure8
+foreach (iitem? in range(0, scaleL)source?) {
9
toneprocedureName?(quaver, scale[scaleL - 1 - i], volumearguments?); // call procedure10
}
}
+Sub main()
1
Dim scalename? = {262, 294, 330, 349, 392, 440, 494, 523}value or expression? ' variable definition2
Dim scaleLname? = scale.length()value or expression? ' variable definition3
Dim quavername? = 250value or expression? ' variable definition4
Dim volumename? = 1.5value or expression? ' variable definition5
+For Each iitem? In range(0, scaleL)source?
6
toneprocedureName?(quaver, scale[i], volumearguments?) ' call procedure7
Next i
sleepprocedureName?(1arguments?) ' call procedure8
+For Each iitem? In range(0, scaleL)source?
9
toneprocedureName?(quaver, scale[scaleL - 1 - i], volumearguments?) ' call procedure10
Next i
End Sub
+static void main() {
1
var scalename? = [262, 294, 330, 349, 392, 440, 494, 523]value or expression?;2
var scaleLname? = scale.length()value or expression?;3
var quavername? = 250value or expression?;4
var volumename? = 1.5value or expression?;5
+foreach (iitem? in range(0, scaleL)source?) {
6
toneprocedureName?(quaver, scale[i], volumearguments?); // call procedure7
}
sleepprocedureName?(1arguments?); // call procedure8
+foreach (iitem? in range(0, scaleL)source?) {
9
toneprocedureName?(quaver, scale[scaleL - 1 - i], volumearguments?); // call procedure10
}
}
Common methods
Common dot methods
Click on a Type to go to the Type's function dot methods, or on to go to the specific method on that Type.
Notes
- The method toString is so widely applicable because it enables you to print
all variables and data structures to the IDE's display pane for debugging purposes.
- methods ceiling, floor, isInfinite, isNaN and round are designed for use on Float values, but they can accept Int values without raising an error.
- The length of a Dictionary can be found by applying method length to the list returned by method keys on the dictionary:
call print(dict.keys().length()) ⟶ 15
Code does not parse as Elan.
call print(dict.keys().length()) ⟶ 15
Code does not parse as Elan.
call print(dict.keys().length()) ⟶ 15
Code does not parse as Elan.
call print(dict.keys().length()) ⟶ 15
Code does not parse as Elan.
call print(dict.keys().length()) ⟶ 15
Code does not parse as Elan.
- Checking whether an item is contained in a Dictionary can be
done by applying method contains to the list returned by methods keys and values on the dictionary:
call print (dict.keys().contains("widget"))⟶true or false
Code does not parse as Elan.
call print (dict.keys().contains("widget"))⟶true or false
Code does not parse as Elan.
call print (dict.keys().contains("widget"))⟶true or false
Code does not parse as Elan.
call print (dict.keys().contains("widget"))⟶true or false
Code does not parse as Elan.
call print (dict.keys().contains("widget"))⟶true or false
Code does not parse as Elan. |
call print (dict.values().contains(42))⟶true or false
Code does not parse as Elan.
call print (dict.values().contains(42))⟶true or false
Code does not parse as Elan.
call print (dict.values().contains(42))⟶true or false
Code does not parse as Elan.
call print (dict.values().contains(42))⟶true or false
Code does not parse as Elan.
call print (dict.values().contains(42))⟶true or false
Code does not parse as Elan. |
Library procedures
All procedures are accessed via a call statement.
Standalone procedures
| procedure | input argument Types | output argument Types | action |
|---|
| clearPrintedText |
(none) |
(none) |
clears the IDE's display pane |
| clearBlocks |
(none) |
(none) |
clears the block graphics layer of the IDE's display pane |
| clearVectorGraphics |
(none) |
(none) |
clears the vector graphics layer of the IDE's display pane |
| clearHtml |
(none) |
(none) |
clears the Html layer of the IDE's display pane |
| clearAllDisplays |
(none) |
(none) |
clears display pane as well as the blocks, vector graphics and Html layers |
| clearKeyBuffer |
(none) |
(none) |
clears the IDE's keyboard input |
| pressAnyKeyToContinue |
Boolean |
(none) |
pauses execution of the program until a keyboard key is pressed
if the argument is true 'Press any key to continue' is first displayed,
if false nothing is displayed |
| print |
String |
(none) |
prints the string to the display followed by a newline |
| printNoLine |
String |
(none) |
prints the string to the display without appending a newline so
a following call will output on the same line.
You can put your own \n newlines in the argument string |
| printTab |
Int, String |
(none) |
prints the string to the display starting at the tab position given (from 0) without appending a newline |
| sleep |
Int |
(none) |
pauses the execution of the program for the specified number of seconds, e.g. for a game sleep(1.5) delays execution for 1.5 seconds |
| sleep_ms |
Int |
(none) |
pauses the execution of the program for the specified number of milliseconds, e.g. sleep(100) delays execution for one tenth of a second |
Examples using print and printTab
▶ Procedure print sends text strings to the display pane:
+main
1
call printprocedureName?("Hello"arguments?)2
variable aname? set to 3value or expression?3
variable bname? set to 4value or expression?4
call printprocedureName?(a*barguments?)5
call printprocedureName?($"{a} times {b}) equals {a*b}"arguments?)6
variable tname? set to (true, 42)value or expression?7
call printprocedureName?(t.item_0arguments?)8
call printprocedureName?(t.item_1arguments?)9
end main
+def main() -> None:
1
printprocedureName?("Hello"arguments?)2
aname? = 3value or expression? # variable definition3
bname? = 4value or expression? # variable definition4
printprocedureName?(a*barguments?)5
printprocedureName?(f"{a} times {b}) equals {a*b}"arguments?)6
tname? = (True, 42)value or expression? # variable definition7
printprocedureName?(t.item_0arguments?)8
printprocedureName?(t.item_1arguments?)9
main()
+static void main() {
1
printprocedureName?("Hello"arguments?);2
var aname? = 3value or expression?;3
var bname? = 4value or expression?;4
printprocedureName?(a*barguments?);5
printprocedureName?($"{a} times {b}) equals {a*b}"arguments?);6
var tname? = (true, 42)value or expression?;7
printprocedureName?(t.item_0arguments?);8
printprocedureName?(t.item_1arguments?);9
}
+Sub main()
1
printprocedureName?("Hello"arguments?)2
Dim aname? = 3value or expression? ' variable definition3
Dim bname? = 4value or expression? ' variable definition4
printprocedureName?(a*barguments?)5
printprocedureName?($"{a} times {b}) equals {a*b}"arguments?)6
Dim tname? = (True, 42)value or expression? ' variable definition7
printprocedureName?(t.item_0arguments?)8
printprocedureName?(t.item_1arguments?)9
End Sub
+static void main() {
1
printprocedureName?("Hello"arguments?);2
var aname? = 3value or expression?;3
var bname? = 4value or expression?;4
printprocedureName?(a*barguments?);5
printprocedureName?(String.format("% times %) equals %", a, b, a*b)arguments?);6
var tname? = (true, 42)value or expression?;7
printprocedureName?(t.item_0arguments?);8
printprocedureName?(t.item_1arguments?);9
}
|
⟶
⟶ ⟶
⟶ ⟶ |
Hello
12 3 times 4 equals 12 [using interpolated strings] [defining a 2-Tuple] true 42 |
▶ Procedure printTab helps in the layout of information printed to the display, e.g. when printing columns of data:
+main
1
call printTabprocedureName?(0, "Number"arguments?)2
call printTabprocedureName?(10, "Square"arguments?)3
call printTabprocedureName?(20, "Cube\n"arguments?)4
+for iitem? in range(1, 11)source?
5
call printTabprocedureName?(0, i.toString()arguments?)6
call printTabprocedureName?(10, $"{pow(i, 2)}"arguments?)7
call printTabprocedureName?(20, $"{pow(i, 3)}\n"arguments?)8
end for
end main
+def main() -> None:
1
printTabprocedureName?(0, "Number"arguments?) # call procedure2
printTabprocedureName?(10, "Square"arguments?) # call procedure3
printTabprocedureName?(20, "Cube\n"arguments?) # call procedure4
+for iitem? in range(1, 11)source?:
5
printTabprocedureName?(0, i.toString()arguments?) # call procedure6
printTabprocedureName?(10, f"{pow(i, 2)}"arguments?) # call procedure7
printTabprocedureName?(20, f"{pow(i, 3)}\n"arguments?) # call procedure8
main()
+static void main() {
1
printTabprocedureName?(0, "Number"arguments?); // call procedure2
printTabprocedureName?(10, "Square"arguments?); // call procedure3
printTabprocedureName?(20, "Cube\n"arguments?); // call procedure4
+foreach (iitem? in range(1, 11)source?) {
5
printTabprocedureName?(0, i.toString()arguments?); // call procedure6
printTabprocedureName?(10, $"{pow(i, 2)}"arguments?); // call procedure7
printTabprocedureName?(20, $"{pow(i, 3)}\n"arguments?); // call procedure8
}
}
+Sub main()
1
printTabprocedureName?(0, "Number"arguments?) ' call procedure2
printTabprocedureName?(10, "Square"arguments?) ' call procedure3
printTabprocedureName?(20, "Cube\n"arguments?) ' call procedure4
+For Each iitem? In range(1, 11)source?
5
printTabprocedureName?(0, i.toString()arguments?) ' call procedure6
printTabprocedureName?(10, $"{pow(i, 2)}"arguments?) ' call procedure7
printTabprocedureName?(20, $"{pow(i, 3)}\n"arguments?) ' call procedure8
Next i
End Sub
+static void main() {
1
printTabprocedureName?(0, "Number"arguments?); // call procedure2
printTabprocedureName?(10, "Square"arguments?); // call procedure3
printTabprocedureName?(20, "Cube\n"arguments?); // call procedure4
+foreach (iitem? in range(1, 11)source?) {
5
printTabprocedureName?(0, i.toString()arguments?); // call procedure6
printTabprocedureName?(10, String.format("%", pow(i, 2))arguments?); // call procedure7
printTabprocedureName?(20, String.format("%\n", pow(i, 3))arguments?); // call procedure8
}
}
▶ For numeric output, it is preferable to right-align the columns, e.g. when listing powers of 9: :
+main
1
variable tabname? set to 10value or expression?2
+for iitem? in range(1, tab)source?
3
variable jname? set to pow(9, i).floor()value or expression?4
variable fname? set to (lambda j as Int => j.toString().length())value or expression?5
call printTabprocedureName?(tab - f(j), $"{j}\n"arguments?)6
end for
end main
+def main() -> None:
1
tabname? = 10value or expression? # variable definition2
+for iitem? in range(1, tab)source?:
3
jname? = pow(9, i).floor()value or expression? # variable definition4
fname? = (lambda j: int => j.toString().length())value or expression? # variable definition5
printTabprocedureName?(tab - f(j), f"{j}\n"arguments?) # call procedure6
main()
+static void main() {
1
var tabname? = 10value or expression?;2
+foreach (iitem? in range(1, tab)source?) {
3
var jname? = pow(9, i).floor()value or expression?;4
var fname? = (lambda int j => j.toString().length())value or expression?;5
printTabprocedureName?(tab - f(j), $"{j}\n"arguments?); // call procedure6
}
}
+Sub main()
1
Dim tabname? = 10value or expression? ' variable definition2
+For Each iitem? In range(1, tab)source?
3
Dim jname? = pow(9, i).floor()value or expression? ' variable definition4
Dim fname? = (lambda j As Integer => j.toString().length())value or expression? ' variable definition5
printTabprocedureName?(tab - f(j), $"{j}\n"arguments?) ' call procedure6
Next i
End Sub
+static void main() {
1
var tabname? = 10value or expression?;2
+foreach (iitem? in range(1, tab)source?) {
3
var jname? = pow(9, i).floor()value or expression?;4
var fname? = (lambda int j => j.toString().length())value or expression?;5
printTabprocedureName?(tab - f(j), String.format("%\n", j)arguments?); // call procedure6
}
}
Type instance procedures
Procedures applicable to standard Reference Types are linked from:
User-defined Classes may have procedures that can be applied to their Class instances.
Library methods
These methods may be referenced from within a function.
Standalone functions
Standalone library functions always return a value and are therefore used in contexts that expect a value, such as in the right-hand side of a variable declaration or a set assignment, either on their own or within a more complex expression.
Standalone library functions require at least one argument to be passed (in round brackets), corresponding to the parameters defined for that function.
system method |
argument Types |
return Types |
returns |
| parseAsFloat |
String |
Boolean, Float |
a 2-Tuple in which the first item is true if the parse was successful,
– false otherwise
and, if true, the second item is the Float value, otherwise zero |
| parseAsInt |
String |
Boolean, Int |
a 2-Tuple in which the first item is true if the parse was successful,
– false otherwise
and, if true, the second item is the Int value, otherwise zero |
| unicode |
Int |
String |
a string containing the one character defined at the given Unicode code point |
Examples using standalone functions
▶ Deconstructing the 2-Tuple returned by parseAsInt:
variable successname? set to parseAsInt(s).item_0value or expression?0
successname? = parseAsInt(s).item_0value or expression? # variable definition0
var successname? = parseAsInt(s).item_0value or expression?;0
Dim successname? = parseAsInt(s).item_0value or expression? ' variable definition0
var successname? = parseAsInt(s).item_0value or expression?;0
variable valuename? set to parseAsInt(s).item_1value or expression?0
valuename? = parseAsInt(s).item_1value or expression? # variable definition0
var valuename? = parseAsInt(s).item_1value or expression?;0
Dim valuename? = parseAsInt(s).item_1value or expression? ' variable definition0
var valuename? = parseAsInt(s).item_1value or expression?;0
Always check the Boolean (success) before using the returned value (value) in case the latter is zero only because the parse was unsuccessful.
▶ Test assertions that use methods parseAsInt and parseAsFloat:
+test test_parsetest_name?
1
assert parseAsInt("31")actual (computed) value? is (true, 31)expected value? not run2
assert parseAsInt("0")actual (computed) value? is (true, 0)expected value? not run3
assert parseAsInt("thirty one")actual (computed) value? is (false, 0)expected value? not run4
assert parseAsInt("3.1")actual (computed) value? is (false, 0)expected value? not run5
assert parseAsFloat("31")actual (computed) value? is (true, 31)expected value? not run6
assert parseAsFloat("0")actual (computed) value? is (true, 0)expected value? not run7
assert parseAsFloat("3.1")actual (computed) value? is (true, 3.1)expected value? not run8
end test
+def test_parsetest_name?(self) -> None:
1
self.assertEqual(parseAsInt("31")actual (computed) value?, (True, 31)expected value?) not run2
self.assertEqual(parseAsInt("0")actual (computed) value?, (True, 0)expected value?) not run3
self.assertEqual(parseAsInt("thirty one")actual (computed) value?, (False, 0)expected value?) not run4
self.assertEqual(parseAsInt("3.1")actual (computed) value?, (False, 0)expected value?) not run5
self.assertEqual(parseAsFloat("31")actual (computed) value?, (True, 31)expected value?) not run6
self.assertEqual(parseAsFloat("0")actual (computed) value?, (True, 0)expected value?) not run7
self.assertEqual(parseAsFloat("3.1")actual (computed) value?, (True, 3.1)expected value?) not run8
main()
+[TestMethod] static void test_parsetest_name?() {
1
Assert.AreEqual((true, 31)expected value?, parseAsInt("31")actual (computed) value?) not run2
Assert.AreEqual((true, 0)expected value?, parseAsInt("0")actual (computed) value?) not run3
Assert.AreEqual((false, 0)expected value?, parseAsInt("thirty one")actual (computed) value?) not run4
Assert.AreEqual((false, 0)expected value?, parseAsInt("3.1")actual (computed) value?) not run5
Assert.AreEqual((true, 31)expected value?, parseAsFloat("31")actual (computed) value?) not run6
Assert.AreEqual((true, 0)expected value?, parseAsFloat("0")actual (computed) value?) not run7
Assert.AreEqual((true, 3.1)expected value?, parseAsFloat("3.1")actual (computed) value?) not run8
}
+<TestMethod> Sub test_parsetest_name?()
1
Assert.AreEqual((True, 31)expected value?, parseAsInt("31")actual (computed) value?) not run2
Assert.AreEqual((True, 0)expected value?, parseAsInt("0")actual (computed) value?) not run3
Assert.AreEqual((False, 0)expected value?, parseAsInt("thirty one")actual (computed) value?) not run4
Assert.AreEqual((False, 0)expected value?, parseAsInt("3.1")actual (computed) value?) not run5
Assert.AreEqual((True, 31)expected value?, parseAsFloat("31")actual (computed) value?) not run6
Assert.AreEqual((True, 0)expected value?, parseAsFloat("0")actual (computed) value?) not run7
Assert.AreEqual((True, 3.1)expected value?, parseAsFloat("3.1")actual (computed) value?) not run8
End Sub
+@Test static void test_parsetest_name?() {
1
assertEquals((true, 31)expected value?, parseAsInt("31")actual (computed) value?) not run2
assertEquals((true, 0)expected value?, parseAsInt("0")actual (computed) value?) not run3
assertEquals((false, 0)expected value?, parseAsInt("thirty one")actual (computed) value?) not run4
assertEquals((false, 0)expected value?, parseAsInt("3.1")actual (computed) value?) not run5
assertEquals((true, 31)expected value?, parseAsFloat("31")actual (computed) value?) not run6
assertEquals((true, 0)expected value?, parseAsFloat("0")actual (computed) value?) not run7
assertEquals((true, 3.1)expected value?, parseAsFloat("3.1")actual (computed) value?) not run8
}
Notes
- Any string that parses as an Int will also parse as a Float.
- When validating user input,it may be easier to use the various input methods.
▶ Using method unicode:
call printprocedureName?(unicode(0x2665)arguments?)0
printprocedureName?(unicode(0x2665)arguments?)0
printprocedureName?(unicode(0x2665)arguments?);0
printprocedureName?(unicode(&H2665)arguments?)0
printprocedureName?(unicode(0x2665)arguments?);0 | ⟶ | ♥ |
Maths functions
All the maths functions expect Float arguments, but Int arguments are accepted.
They all return a value of Type Float, except for divAsInt which returns an Int.
| function | argument Type | input unit | returns | output unit |
| abs | Float | | absolute value of the input | |
| acos | Float | | arccosine of the input | radians |
| asin | Float | | arcsine of the input | radians |
| atan | Float | | arctangent of the input | radians |
| cos | Float | radians | cosine of the input | |
| divAsFloat | Float, Float | | first input value divided by second input value | |
| divAsInt | Float, Float | | first input value divided by second input value and result rounded down to integer | |
| exp |
Float |
|
𝑒𝑥 where 𝑥 is the argument and 𝑒 is Euler's number 2.718281828459045.. the base of natural logarithms |
|
| logE | Float | | natural logarithm of the input | |
| log10 | Float | | base-10 logarithm of the input | |
| log2 | Float | | base-2 logarithm of the input | |
| sin | Float | radians | sine of the input | |
| sqrt | Float | | positive square root of the input | |
| tan | Float | radians | tangent of the input | |
| radians | Float | degrees | converts input from degrees to radians | radians |
| degrees | Float | radians | converts input from radians to degrees | degrees |
Examples of some maths functions and constants being tested:
+test test_mathstest_name?
1
assert piactual (computed) value? is 3.141592653589793expected value? not run2
assert abs(-3.7)actual (computed) value? is 3.7expected value? not run3
assert pow(2, 10)actual (computed) value? is 1024expected value? not run4
assert sqrt(2).round(3)actual (computed) value? is 1.414expected value? not run5
assert asin(0.5).round(3)actual (computed) value? is 0.524expected value? not run6
assert acos(0.5).round(3)actual (computed) value? is 1.047expected value? not run7
assert atan(1).round(2)actual (computed) value? is 0.79expected value? not run8
assert sin(pi/6).round(2)actual (computed) value? is 0.5expected value? not run9
assert cos(pi/4).round(3)actual (computed) value? is 0.707expected value? not run10
assert tan(pi/4).round(2)actual (computed) value? is 1expected value? not run11
assert exp(2).round(3)actual (computed) value? is 7.389expected value? not run12
assert logE(7.389).round(2)actual (computed) value? is 2expected value? not run13
assert log10(1000)actual (computed) value? is 3expected value? not run14
assert log2(65536)actual (computed) value? is 16expected value? not run15
assert log2(0x10000)actual (computed) value? is 16expected value? not run16
end test
+def test_mathstest_name?(self) -> None:
1
self.assertEqual(piactual (computed) value?, 3.141592653589793expected value?) not run2
self.assertEqual(abs(-3.7)actual (computed) value?, 3.7expected value?) not run3
self.assertEqual(pow(2, 10)actual (computed) value?, 1024expected value?) not run4
self.assertEqual(sqrt(2).round(3)actual (computed) value?, 1.414expected value?) not run5
self.assertEqual(asin(0.5).round(3)actual (computed) value?, 0.524expected value?) not run6
self.assertEqual(acos(0.5).round(3)actual (computed) value?, 1.047expected value?) not run7
self.assertEqual(atan(1).round(2)actual (computed) value?, 0.79expected value?) not run8
self.assertEqual(sin(pi/6).round(2)actual (computed) value?, 0.5expected value?) not run9
self.assertEqual(cos(pi/4).round(3)actual (computed) value?, 0.707expected value?) not run10
self.assertEqual(tan(pi/4).round(2)actual (computed) value?, 1expected value?) not run11
self.assertEqual(exp(2).round(3)actual (computed) value?, 7.389expected value?) not run12
self.assertEqual(logE(7.389).round(2)actual (computed) value?, 2expected value?) not run13
self.assertEqual(log10(1000)actual (computed) value?, 3expected value?) not run14
self.assertEqual(log2(65536)actual (computed) value?, 16expected value?) not run15
self.assertEqual(log2(0x10000)actual (computed) value?, 16expected value?) not run16
main()
+[TestMethod] static void test_mathstest_name?() {
1
Assert.AreEqual(3.141592653589793expected value?, piactual (computed) value?) not run2
Assert.AreEqual(3.7expected value?, abs(-3.7)actual (computed) value?) not run3
Assert.AreEqual(1024expected value?, pow(2, 10)actual (computed) value?) not run4
Assert.AreEqual(1.414expected value?, sqrt(2).round(3)actual (computed) value?) not run5
Assert.AreEqual(0.524expected value?, asin(0.5).round(3)actual (computed) value?) not run6
Assert.AreEqual(1.047expected value?, acos(0.5).round(3)actual (computed) value?) not run7
Assert.AreEqual(0.79expected value?, atan(1).round(2)actual (computed) value?) not run8
Assert.AreEqual(0.5expected value?, sin(pi/6).round(2)actual (computed) value?) not run9
Assert.AreEqual(0.707expected value?, cos(pi/4).round(3)actual (computed) value?) not run10
Assert.AreEqual(1expected value?, tan(pi/4).round(2)actual (computed) value?) not run11
Assert.AreEqual(7.389expected value?, exp(2).round(3)actual (computed) value?) not run12
Assert.AreEqual(2expected value?, logE(7.389).round(2)actual (computed) value?) not run13
Assert.AreEqual(3expected value?, log10(1000)actual (computed) value?) not run14
Assert.AreEqual(16expected value?, log2(65536)actual (computed) value?) not run15
Assert.AreEqual(16expected value?, log2(0x10000)actual (computed) value?) not run16
}
+<TestMethod> Sub test_mathstest_name?()
1
Assert.AreEqual(3.141592653589793expected value?, piactual (computed) value?) not run2
Assert.AreEqual(3.7expected value?, abs(-3.7)actual (computed) value?) not run3
Assert.AreEqual(1024expected value?, pow(2, 10)actual (computed) value?) not run4
Assert.AreEqual(1.414expected value?, sqrt(2).round(3)actual (computed) value?) not run5
Assert.AreEqual(0.524expected value?, asin(0.5).round(3)actual (computed) value?) not run6
Assert.AreEqual(1.047expected value?, acos(0.5).round(3)actual (computed) value?) not run7
Assert.AreEqual(0.79expected value?, atan(1).round(2)actual (computed) value?) not run8
Assert.AreEqual(0.5expected value?, sin(pi/6).round(2)actual (computed) value?) not run9
Assert.AreEqual(0.707expected value?, cos(pi/4).round(3)actual (computed) value?) not run10
Assert.AreEqual(1expected value?, tan(pi/4).round(2)actual (computed) value?) not run11
Assert.AreEqual(7.389expected value?, exp(2).round(3)actual (computed) value?) not run12
Assert.AreEqual(2expected value?, logE(7.389).round(2)actual (computed) value?) not run13
Assert.AreEqual(3expected value?, log10(1000)actual (computed) value?) not run14
Assert.AreEqual(16expected value?, log2(65536)actual (computed) value?) not run15
Assert.AreEqual(16expected value?, log2(&H10000)actual (computed) value?) not run16
End Sub
+@Test static void test_mathstest_name?() {
1
assertEquals(3.141592653589793expected value?, piactual (computed) value?) not run2
assertEquals(3.7expected value?, abs(-3.7)actual (computed) value?) not run3
assertEquals(1024expected value?, pow(2, 10)actual (computed) value?) not run4
assertEquals(1.414expected value?, sqrt(2).round(3)actual (computed) value?) not run5
assertEquals(0.524expected value?, asin(0.5).round(3)actual (computed) value?) not run6
assertEquals(1.047expected value?, acos(0.5).round(3)actual (computed) value?) not run7
assertEquals(0.79expected value?, atan(1).round(2)actual (computed) value?) not run8
assertEquals(0.5expected value?, sin(pi/6).round(2)actual (computed) value?) not run9
assertEquals(0.707expected value?, cos(pi/4).round(3)actual (computed) value?) not run10
assertEquals(1expected value?, tan(pi/4).round(2)actual (computed) value?) not run11
assertEquals(7.389expected value?, exp(2).round(3)actual (computed) value?) not run12
assertEquals(2expected value?, logE(7.389).round(2)actual (computed) value?) not run13
assertEquals(3expected value?, log10(1000)actual (computed) value?) not run14
assertEquals(16expected value?, log2(65536)actual (computed) value?) not run15
assertEquals(16expected value?, log2(0x10000)actual (computed) value?) not run16
}
Bitwise functions
These functions take in an integer value, and manipulate the bit representation of that value.
| function |
argument Types |
return Type |
returns |
| bitAnd |
Int, Int |
Int |
integer whose binary representation is the bitwise AND of the inputs |
| bitOr |
Int, Int |
Int |
integer whose binary representation is the bitwise OR of the inputs |
| bitNot |
Int |
Int |
integer whose binary representation is the bitwise complement of the input |
| bitXor |
Int, Int |
Int |
integer whose binary representation is the bitwise XOR of the inputs |
| bitShiftL |
Int, Int |
Int |
integer bit shifted to the left by the value of the second argument, i.e. multiplied by 2 to the power of the second argument |
| bitShiftR |
Int, Int |
Int |
integer bit shifted to the right by the value of the second argument, i.e. divided by 2 to the power of the second argument |
Examples of the bitwise functions being tested
▶ Examples of the bitwise functions being tested
+test test_bitwisetest_name?
1
variable aname? set to 13value or expression?2
assert aactual (computed) value? is 0xdexpected value? not run3
assert aactual (computed) value? is 0b1101expected value? not run4
assert a.asBinary()actual (computed) value? is "1101"expected value? not run5
variable bname? set to 30value or expression?6
assert bactual (computed) value? is 0b11110expected value? not run7
assert bitAnd(a, b)actual (computed) value? is 0b1100expected value? not run8
variable aobname? set to bitOr(a, b)value or expression?9
assert aobactual (computed) value? is 0b11111expected value? not run10
variable axbname? set to bitXor(a, b)value or expression?11
assert axbactual (computed) value? is 0b10011expected value? not run12
variable notaname? set to bitNot(a)value or expression?13
assert notaactual (computed) value? is -14expected value? not run14
variable aLname? set to bitShiftL(a, 2)value or expression?15
assert aLactual (computed) value? is 0b110100expected value? not run16
assert bitShiftR(a, 2)actual (computed) value? is 0b11expected value? not run17
end test
+def test_bitwisetest_name?(self) -> None:
1
aname? = 13value or expression? # variable definition2
self.assertEqual(aactual (computed) value?, 0xdexpected value?) not run3
self.assertEqual(aactual (computed) value?, 0b1101expected value?) not run4
self.assertEqual(a.asBinary()actual (computed) value?, "1101"expected value?) not run5
bname? = 30value or expression? # variable definition6
self.assertEqual(bactual (computed) value?, 0b11110expected value?) not run7
self.assertEqual(bitAnd(a, b)actual (computed) value?, 0b1100expected value?) not run8
aobname? = bitOr(a, b)value or expression? # variable definition9
self.assertEqual(aobactual (computed) value?, 0b11111expected value?) not run10
axbname? = bitXor(a, b)value or expression? # variable definition11
self.assertEqual(axbactual (computed) value?, 0b10011expected value?) not run12
notaname? = bitNot(a)value or expression? # variable definition13
self.assertEqual(notaactual (computed) value?, -14expected value?) not run14
aLname? = bitShiftL(a, 2)value or expression? # variable definition15
self.assertEqual(aLactual (computed) value?, 0b110100expected value?) not run16
self.assertEqual(bitShiftR(a, 2)actual (computed) value?, 0b11expected value?) not run17
main()
+[TestMethod] static void test_bitwisetest_name?() {
1
var aname? = 13value or expression?;2
Assert.AreEqual(0xdexpected value?, aactual (computed) value?) not run3
Assert.AreEqual(0b1101expected value?, aactual (computed) value?) not run4
Assert.AreEqual("1101"expected value?, a.asBinary()actual (computed) value?) not run5
var bname? = 30value or expression?;6
Assert.AreEqual(0b11110expected value?, bactual (computed) value?) not run7
Assert.AreEqual(0b1100expected value?, bitAnd(a, b)actual (computed) value?) not run8
var aobname? = bitOr(a, b)value or expression?;9
Assert.AreEqual(0b11111expected value?, aobactual (computed) value?) not run10
var axbname? = bitXor(a, b)value or expression?;11
Assert.AreEqual(0b10011expected value?, axbactual (computed) value?) not run12
var notaname? = bitNot(a)value or expression?;13
Assert.AreEqual(-14expected value?, notaactual (computed) value?) not run14
var aLname? = bitShiftL(a, 2)value or expression?;15
Assert.AreEqual(0b110100expected value?, aLactual (computed) value?) not run16
Assert.AreEqual(0b11expected value?, bitShiftR(a, 2)actual (computed) value?) not run17
}
+<TestMethod> Sub test_bitwisetest_name?()
1
Dim aname? = 13value or expression? ' variable definition2
Assert.AreEqual(&Hdexpected value?, aactual (computed) value?) not run3
Assert.AreEqual(&B1101expected value?, aactual (computed) value?) not run4
Assert.AreEqual("1101"expected value?, a.asBinary()actual (computed) value?) not run5
Dim bname? = 30value or expression? ' variable definition6
Assert.AreEqual(&B11110expected value?, bactual (computed) value?) not run7
Assert.AreEqual(&B1100expected value?, bitAnd(a, b)actual (computed) value?) not run8
Dim aobname? = bitOr(a, b)value or expression? ' variable definition9
Assert.AreEqual(&B11111expected value?, aobactual (computed) value?) not run10
Dim axbname? = bitXor(a, b)value or expression? ' variable definition11
Assert.AreEqual(&B10011expected value?, axbactual (computed) value?) not run12
Dim notaname? = bitNot(a)value or expression? ' variable definition13
Assert.AreEqual(-14expected value?, notaactual (computed) value?) not run14
Dim aLname? = bitShiftL(a, 2)value or expression? ' variable definition15
Assert.AreEqual(&B110100expected value?, aLactual (computed) value?) not run16
Assert.AreEqual(&B11expected value?, bitShiftR(a, 2)actual (computed) value?) not run17
End Sub
+@Test static void test_bitwisetest_name?() {
1
var aname? = 13value or expression?;2
assertEquals(0xdexpected value?, aactual (computed) value?) not run3
assertEquals(0b1101expected value?, aactual (computed) value?) not run4
assertEquals("1101"expected value?, a.asBinary()actual (computed) value?) not run5
var bname? = 30value or expression?;6
assertEquals(0b11110expected value?, bactual (computed) value?) not run7
assertEquals(0b1100expected value?, bitAnd(a, b)actual (computed) value?) not run8
var aobname? = bitOr(a, b)value or expression?;9
assertEquals(0b11111expected value?, aobactual (computed) value?) not run10
var axbname? = bitXor(a, b)value or expression?;11
assertEquals(0b10011expected value?, axbactual (computed) value?) not run12
var notaname? = bitNot(a)value or expression?;13
assertEquals(-14expected value?, notaactual (computed) value?) not run14
var aLname? = bitShiftL(a, 2)value or expression?;15
assertEquals(0b110100expected value?, aLactual (computed) value?) not run16
assertEquals(0b11expected value?, bitShiftR(a, 2)actual (computed) value?) not run17
}
The result of bitNot(a) being -14 , when a is 13, might be a surprise. But this is because the bitwise functions assume that the arguments are represented as 32-bit signed binary integers. So 13 is represented as
00000000000000000000000000001101, and applying bitNot gives
11111111111111111111111111110010 which is the value -14 in signed two's complement format,
the left-most bit being the sign (0 positive, 1 negative).
Single bit operations
▶ A reminder of single bit operations.
As noted in the example tests above, these methods act on 32-bit signed integers rather than on values of only one or a few bits,
so the effect of bitNot is not just the simple bit reversal shown here:
| p,q |
| 0,0 | 0,1 | 1,0 | 1,1 |
| bitAnd(p,q) | 0 | 0 | 0 | 1 |
| bitOr(p,q) | 0 | 1 | 1 | 1 |
| bitNot(p) | 1 | 1 | 0 | 0 |
| bitXor(p,q) | 0 | 1 | 1 | 0 |
RegExp functions
Elan's regular expressions are modelled on those of JavaScript, including the syntax for literal regular expressions. See, for example this Guide to Regular Expressions.
More functions for using regular expressions will be added in a future release of Elan. For now:
The method matchesRegExp is applied to a String using dot syntax and requires a RegExp parameter specified as a literal or as variable. It returns a Boolean. For example:
+test test_matchesRegExptest_name?
1
variable s1name? set to "hello"value or expression?2
variable s2name? set to "World"value or expression?3
variable rname? set to /^[a-z]*$/value or expression?4
assert s1.matchesRegExp(r)actual (computed) value? is trueexpected value? not run5
assert s2.matchesRegExp(r)actual (computed) value? is falseexpected value? not run6
end test
+def test_matchesRegExptest_name?(self) -> None:
1
s1name? = "hello"value or expression? # variable definition2
s2name? = "World"value or expression? # variable definition3
rname? = /^[a-z]*$/value or expression? # variable definition4
self.assertEqual(s1.matchesRegExp(r)actual (computed) value?, Trueexpected value?) not run5
self.assertEqual(s2.matchesRegExp(r)actual (computed) value?, Falseexpected value?) not run6
main()
+[TestMethod] static void test_matchesRegExptest_name?() {
1
var s1name? = "hello"value or expression?;2
var s2name? = "World"value or expression?;3
var rname? = /^[a-z]*$/value or expression?;4
Assert.AreEqual(trueexpected value?, s1.matchesRegExp(r)actual (computed) value?) not run5
Assert.AreEqual(falseexpected value?, s2.matchesRegExp(r)actual (computed) value?) not run6
}
+<TestMethod> Sub test_matchesRegExptest_name?()
1
Dim s1name? = "hello"value or expression? ' variable definition2
Dim s2name? = "World"value or expression? ' variable definition3
Dim rname? = /^[a-z]*$/value or expression? ' variable definition4
Assert.AreEqual(Trueexpected value?, s1.matchesRegExp(r)actual (computed) value?) not run5
Assert.AreEqual(Falseexpected value?, s2.matchesRegExp(r)actual (computed) value?) not run6
End Sub
+@Test static void test_matchesRegExptest_name?() {
1
var s1name? = "hello"value or expression?;2
var s2name? = "World"value or expression?;3
var rname? = /^[a-z]*$/value or expression?;4
assertEquals(trueexpected value?, s1.matchesRegExp(r)actual (computed) value?) not run5
assertEquals(falseexpected value?, s2.matchesRegExp(r)actual (computed) value?) not run6
}
You can convert a valid string without /../ delimiters to a RegExp using function asRegExp:
+test test_matchesRegExptest_name?
1
variable s1name? set to "hello"value or expression?2
variable s2name? set to "World"value or expression?3
variable rname? set to "^[a-z]*$".asRegExp()value or expression?4
assert s1.matchesRegExp(r)actual (computed) value? is trueexpected value? not run5
assert s2.matchesRegExp(r)actual (computed) value? is falseexpected value? not run6
end test
+def test_matchesRegExptest_name?(self) -> None:
1
s1name? = "hello"value or expression? # variable definition2
s2name? = "World"value or expression? # variable definition3
rname? = "^[a-z]*$".asRegExp()value or expression? # variable definition4
self.assertEqual(s1.matchesRegExp(r)actual (computed) value?, Trueexpected value?) not run5
self.assertEqual(s2.matchesRegExp(r)actual (computed) value?, Falseexpected value?) not run6
main()
+[TestMethod] static void test_matchesRegExptest_name?() {
1
var s1name? = "hello"value or expression?;2
var s2name? = "World"value or expression?;3
var rname? = "^[a-z]*$".asRegExp()value or expression?;4
Assert.AreEqual(trueexpected value?, s1.matchesRegExp(r)actual (computed) value?) not run5
Assert.AreEqual(falseexpected value?, s2.matchesRegExp(r)actual (computed) value?) not run6
}
+<TestMethod> Sub test_matchesRegExptest_name?()
1
Dim s1name? = "hello"value or expression? ' variable definition2
Dim s2name? = "World"value or expression? ' variable definition3
Dim rname? = "^[a-z]*$".asRegExp()value or expression? ' variable definition4
Assert.AreEqual(Trueexpected value?, s1.matchesRegExp(r)actual (computed) value?) not run5
Assert.AreEqual(Falseexpected value?, s2.matchesRegExp(r)actual (computed) value?) not run6
End Sub
+@Test static void test_matchesRegExptest_name?() {
1
var s1name? = "hello"value or expression?;2
var s2name? = "World"value or expression?;3
var rname? = "^[a-z]*$".asRegExp()value or expression?;4
assertEquals(trueexpected value?, s1.matchesRegExp(r)actual (computed) value?) not run5
assertEquals(falseexpected value?, s2.matchesRegExp(r)actual (computed) value?) not run6
}
Although it is recommended that literal regular expressions are written with /../ delimiters, the ability to convert a string allows you to input a regular expression into a running program.
System methods
System methods appear to work like functions, because:
- they may require one or more arguments to be provided
- they always return a value
- they can be used in expressions
They are not, however, pure functions because:
- they may have a dependency on data that is not provided in an argument
- they may generate side effects, such as changing the screen display or writing to a file
Because of these properties, system methods maybe used only within the main routine or a procedure.
They may not be used inside a function that you have defined, because to do so would prevent the function from being pure.
You cannot write a system method yourself.
Input/output
Clock and random numbers
Methods random and randint cannot be used in a function because
of their dependence on external factors, i.e. they are subject to side effects.
To obtain random numbers within a function, use Type Random.
system method |
argument Types |
return Types |
returns |
| clock |
(none) |
Int |
the current value (in milliseconds) of a system clock. Useful for measuring elapsed time by comparing the values returned by two calls |
| random |
(none) |
Float |
a random number in the range [0..1] |
| randint |
Int, Int |
Int |
a random number in the (inclusive) range between the two arguments |
System functions
These methods are pure functions and so may be referenced in your functions as well as in procedures:
system method |
argument Types |
return Types |
returns |
| copy |
named value of any Type |
same Type as argument |
a copy of the named value |
| createList |
Int, value of List item's Type |
List<of item's Type> |
a List containing the specified number of items each initialised to the value in the second argument |
| createListOfLists |
Int, Int, value of List item's Type |
List<of List<of item's Type>> |
a List of length the first argument containing that number of Lists
each initialised to a List of length the second argument
with each item therein initialised to the value in the third argument |
| max |
List<of Int> or List<of Float> |
Int or Float |
the maximum value found in the List |
| min |
List<of Int> or List<of Float> |
Int or Float |
the minimum value found in the List |
| range |
Int, Int |
List |
a List containing the integers from the first argument to one less than the second argument.
If the second argument is not greater than the first, then the empty List is returned |
| rangeInSteps |
Int, Int, Int |
List |
a List containing the integers from the first argument to one less than the second argument
in increments specified by the third argument.
If, however, the third argument is negative, the second argument must be less than the first,
and the integers returned will run from the first to one more than the second |
Example using rangeInSteps
▶ and which uses Higher-order Functions to print the prime numbers between 2 and 30:
call printprocedureName?(rangeInSteps(2, 30, 1).filter(lambda n as Int => rangeInSteps(2, sqrt(n).floor(), 1).reduce(true, lambda c as Boolean, m as Int => c and ((n mod m) isnt 0)))arguments?)0
printprocedureName?(rangeInSteps(2, 30, 1).filter(lambda n: int => rangeInSteps(2, sqrt(n).floor(), 1).reduce(True, lambda c: bool, m: int => c and ((n % m) != 0)))arguments?)0
printprocedureName?(rangeInSteps(2, 30, 1).filter(lambda int n => rangeInSteps(2, sqrt(n).floor(), 1).reduce(true, lambda bool c, int m => c && ((n % m) != 0)))arguments?);0
printprocedureName?(rangeInSteps(2, 30, 1).filter(lambda n As Integer => rangeInSteps(2, sqrt(n).floor(), 1).reduce(True, lambda c As Boolean, m As Integer => c And ((n Mod m) <> 0)))arguments?)0
printprocedureName?(rangeInSteps(2, 30, 1).filter(lambda int n => rangeInSteps(2, sqrt(n).floor(), 1).reduce(true, lambda bool c, int m => c && ((n % m) != 0)))arguments?);0
Higher-order Functions (HoFs)
A higher-order function (HoF) is one that takes in a reference to another function as a parameter, or (less commonly) that returns a reference to another function as its result.
Standard HoFs
The standard library contains several HoFs that are widely recognised and used within functional programming, namely
filter,
map and
reduce, and also provides
maxBy,
minBy and
orderBy.
Passing a function as a reference
To use a higher-order function (HoF), you have to pass in a reference to a function.
This can be either a lambda or the name of a function.
It is also possible to use references to functions not in the context of HoFs.
On most occasions when you write the name of an existing function elsewhere in code your intent is to evaluate the function and, to do so, you write the name of the function followed by round brackets containing such arguments as are required by the function. When passing a function, its name is not followed by round brackets (or arguments), as in this example:
+class PupilName? inheritance?1
property mathsPercentname? as IntType?2
+constructor(parameter definitions?)
3
new code
end constructor
+function toStringname?(parameter definitions?) returns StringType?
4
return "undefined"value or expression?5
end function
end class
+main
6
variable allPupilsname? set to new List<of Pupil>()value or expression?7
variable passesname? set to allPupils.filter(passedMathsTest)value or expression?8
end main
+function passedMathsTestname?(p as Pupilparameter definitions?) returns BooleanType?
9
return p.mathsPercent > 35value or expression?10
end function
+class PupilName? inheritance?1
mathsPercentname?: intType? # property2
+def __init__(self: Pupil) -> None:
3
new code
+def toStringname?(self: Pupil) -> strType?:
# function4
return "undefined"value or expression?5
+def main() -> None:
6
allPupilsname? = list[Pupil]()value or expression? # variable definition7
passesname? = allPupils.filter(passedMathsTest)value or expression? # variable definition8
+def passedMathsTestname?(p: Pupilparameter definitions?) -> boolType?:
# function9
return p.mathsPercent > 35value or expression?10
main()
+class PupilName? inheritance? {1
public intType? mathsPercentname? {get; private set;} // property2
+public Pupil(parameter definitions?) {
3
new code
}
+public stringType? toStringname?(parameter definitions?) {
// function4
return "undefined"value or expression?;5
}
}
+static void main() {
6
var allPupilsname? = new List<Pupil>()value or expression?;7
var passesname? = allPupils.filter(passedMathsTest)value or expression?;8
}
+static boolType? passedMathsTestname?(Pupil pparameter definitions?) {
// function9
return p.mathsPercent > 35value or expression?;10
}
+Class PupilName?1
Property mathsPercentname? As IntegerType?2
+Sub New(parameter definitions?)
3
new code
End Sub
+Function toStringname?(parameter definitions?) As StringType?
4
Return "undefined"value or expression?5
End Function
End Class
+Sub main()
6
Dim allPupilsname? = New List(Of Pupil)()value or expression? ' variable definition7
Dim passesname? = allPupils.filter(passedMathsTest)value or expression? ' variable definition8
End Sub
+Function passedMathsTestname?(p As Pupilparameter definitions?) As BooleanType?
9
Return p.mathsPercent > 35value or expression?10
End Function
+class PupilName? {1
public intType? mathsPercentname?; // property2
+public Pupil(parameter definitions?) {
3
new code
}
+public StringType? toStringname?(parameter definitions?) {
// function4
return "undefined"value or expression?;5
}
}
+static void main() {
6
var allPupilsname? = new List<Pupil>()value or expression?;7
var passesname? = allPupils.filter(passedMathsTest)value or expression?;8
}
+static boolType? passedMathsTestname?(Pupil pparameter definitions?) {
// function9
return p.mathsPercent > 35value or expression?;10
}
System constants
System constants are unlike values that you define in your program constants,
in that they are mutable named values, though it would be poor practice to change them.
String constants
These constants are of use when the characters { } and " are required within a string.
| name | Type | value |
| openBrace |
String |
{ |
| closeBrace |
String |
} |
| quotes |
String |
" |
Maths constant
| name | Type | value |
| pi |
Float |
𝜋 = 3.141592653589793.. |
Boolean constants
| name | Type | value |
| true |
Boolean |
true |
| false |
Boolean |
false |
Colour constants
| colour | | decimal | decimal
| hexadecimal |
| name | | integer | R G B | 0xrrggbb |
| black | ◼ | 0 | 0 0 0 | 0x000000 |
| white | ◼ | 16777215 | 255 255 255 | 0xffffff |
| red | ◼ | 16711680 | 255 0 0 | 0xff0000 |
| green | ◼ | 32768 | 0 128 0 | 0x008000 |
| blue | ◼ | 255 | 0 0 255 | 0x0000ff |
| yellow | ◼ | 16776960 | 255 255 0 | 0xffff00 |
| brown | ◼ | 10824234 | 165 42 42 | 0xa52a2a |
| grey | ◼ | 8421504 | 128 128 128 | 0x808080 |
| transparent | ◻ | -1 | n/a | n/a |
A colour is specified as an Int value using one of these methods:
- the limited colours defined as library constants as in the above table.
- an integer in the decimal range 0 (black) to 224-1 (white).
- a six digit hexadecimal value in the range 0x000000 – 0xffffff
using the same 'RGB' format as used in Html style, for example 0xff0000 for red.
- transparent is only used for filling vector graphics shapes.
Defining your own HoFs
Library functions that process Lists
These dot methods are called on any List, or String. As Higher-order Functions they take either a lambda or a function reference as one of their arguments: see above.
These are not yet fully documented but, for readers familiar with HoFs from another programming language, some examples are shown below.
filter
You give a List to the higher-order function filter in order to return a new List containing a subset of items.
The subset is chosen by a lambda function that tests list item values and returns a Boolean to specify filtering in or out.
Example using filter
▶ Example from demo program pathfinder.elan in which filter applies the lambda to the nodes (of Class Node) to find one that contains p (of Class Point):
function getNodeFor(p as Point) returns Node
variable matches set to this.nodes.filter(lambda n as Node => n.point.equals(p))
return if matches.length() is 1, matches.head(), emptyNode()
end function
Code does not parse as Elan.
function getNodeFor(p as Point) returns Node
variable matches set to this.nodes.filter(lambda n as Node => n.point.equals(p))
return if matches.length() is 1, matches.head(), emptyNode()
end function
Code does not parse as Elan.
function getNodeFor(p as Point) returns Node
variable matches set to this.nodes.filter(lambda n as Node => n.point.equals(p))
return if matches.length() is 1, matches.head(), emptyNode()
end function
Code does not parse as Elan.
function getNodeFor(p as Point) returns Node
variable matches set to this.nodes.filter(lambda n as Node => n.point.equals(p))
return if matches.length() is 1, matches.head(), emptyNode()
end function
Code does not parse as Elan.
function getNodeFor(p as Point) returns Node
variable matches set to this.nodes.filter(lambda n as Node => n.point.equals(p))
return if matches.length() is 1, matches.head(), emptyNode()
end function
Code does not parse as Elan.
map
The function map is used to apply a function to every item in a List, and return a new List.
The function to be applied is usually specified as a lambda having a single argument of the Type of the list's items, as in these examples:
Examples using map
▶ To cube each integer value in a list:
+main
1
variable liname? set to [1, 2, 3, 4, 5]value or expression?2
call printprocedureName?(li.map(lambda n as Int => pow(n, 3))arguments?)3
end main
+def main() -> None:
1
liname? = [1, 2, 3, 4, 5]value or expression? # variable definition2
printprocedureName?(li.map(lambda n: int => pow(n, 3))arguments?)3
main()
+static void main() {
1
var liname? = [1, 2, 3, 4, 5]value or expression?;2
printprocedureName?(li.map(lambda int n => pow(n, 3))arguments?);3
}
+Sub main()
1
Dim liname? = {1, 2, 3, 4, 5}value or expression? ' variable definition2
printprocedureName?(li.map(lambda n As Integer => pow(n, 3))arguments?)3
End Sub
+static void main() {
1
var liname? = [1, 2, 3, 4, 5]value or expression?;2
printprocedureName?(li.map(lambda int n => pow(n, 3))arguments?);3
}
⟶ [1, 8, 27, 64, 125]
▶ To change each string in a list to upper case:
+main
1
variable namesname? set to ["Tom", "Dick", "Harriet"]value or expression?2
call printprocedureName?(names.map(lambda s as String => s.upperCase())arguments?)3
end main
+def main() -> None:
1
namesname? = ["Tom", "Dick", "Harriet"]value or expression? # variable definition2
printprocedureName?(names.map(lambda s: str => s.upperCase())arguments?)3
main()
+static void main() {
1
var namesname? = ["Tom", "Dick", "Harriet"]value or expression?;2
printprocedureName?(names.map(lambda string s => s.upperCase())arguments?);3
}
+Sub main()
1
Dim namesname? = {"Tom", "Dick", "Harriet"}value or expression? ' variable definition2
printprocedureName?(names.map(lambda s As String => s.upperCase())arguments?)3
End Sub
+static void main() {
1
var namesname? = ["Tom", "Dick", "Harriet"]value or expression?;2
printprocedureName?(names.map(lambda String s => s.upperCase())arguments?);3
}
⟶ ["TOM", "DICK", "HARRIET"]
▶ To reverse each string in the list of names using the function reverse
(from the example of the for loop):
call printprocedureName?(names.map(lambda s as String => reverseString(s))arguments?)0
printprocedureName?(names.map(lambda s: str => reverseString(s))arguments?)0
printprocedureName?(names.map(lambda string s => reverseString(s))arguments?);0
printprocedureName?(names.map(lambda s As String => reverseString(s))arguments?)0
printprocedureName?(names.map(lambda String s => reverseString(s))arguments?);0
⟶ ["moT", "kciD", "teirraH"]
▶ And this example from demo program maze-generator.elan:
variable nname? set to p.neighbouringPoints().map(lambda p as Point => getValue(p, g))value or expression?0
nname? = p.neighbouringPoints().map(lambda p: Point => getValue(p, g))value or expression? # variable definition0
var nname? = p.neighbouringPoints().map(lambda Point p => getValue(p, g))value or expression?;0
Dim nname? = p.neighbouringPoints().map(lambda p As Point => getValue(p, g))value or expression? ' variable definition0
var nname? = p.neighbouringPoints().map(lambda Point p => getValue(p, g))value or expression?;0
reduce
The function reduce is used to combine the items in a list in some way to produce
a single result. This result may be of the same Type as the items in the list, for example to:
- Find the sum or sum-of-squares of a list of numeric values.
- Concatenate, or combine in some other way, the items from a List of Strings.
The result may, however, be of a different Type than the items in the list, and may even be a data structure, for example to:
- Generate a 3-Tuple of the sum, sum-of-squares, and count of numerical items.
- Generate a dictionary of all the unique words in a list, with the number of times each word appears in the input List
Method reduce requires two arguments:
- The initial, or 'seed', value, of the Type that you wish to be returned by the function specified in the second argument..
For example, if you were finding the sum of a list of Type Float, the initial seed value
would typically be 0.0. If you were creating a dictionary of words, the initial seed
value would be an empty Dictionary of the correct Types.
- The function (or lambda) to be applied, which itself requires two arguments:
- The accumulating value, which is therefore of the same Type as the initial seed value.
(This will be the return value of the function or lambda).
- The item to which the function is applied, which is therefore of the same Type
as the items in the input list.
In other words, the specified function or lambda is applied to each itme of the input List in turn, in each case passing in the current value
of the result. The function makes use of both to generate a new value for the result, replacing the current one
for application to the next item. This is best understood by looking at the examples.
Examples using reduce
▶ To reduce the floating point values in a List to their sum:
+main
1
variable nname? set to [0.1, 2, 2.5, 0.3, 5.75, 0.29]value or expression?2
call printprocedureName?(n.reduce(0.0, lambda sum as Float, m as Float => (sum + m).round(2))arguments?)3
end main
+def main() -> None:
1
nname? = [0.1, 2, 2.5, 0.3, 5.75, 0.29]value or expression? # variable definition2
printprocedureName?(n.reduce(0.0, lambda sum: float, m: float => (sum + m).round(2))arguments?)3
main()
+static void main() {
1
var nname? = [0.1, 2, 2.5, 0.3, 5.75, 0.29]value or expression?;2
printprocedureName?(n.reduce(0.0, lambda double sum, double m => (sum + m).round(2))arguments?);3
}
+Sub main()
1
Dim nname? = {0.1, 2, 2.5, 0.3, 5.75, 0.29}value or expression? ' variable definition2
printprocedureName?(n.reduce(0.0, lambda sum As Double, m As Double => (sum + m).round(2))arguments?)3
End Sub
+static void main() {
1
var nname? = [0.1, 2, 2.5, 0.3, 5.75, 0.29]value or expression?;2
printprocedureName?(n.reduce(0.0, lambda double sum, double m => (sum + m).round(2))arguments?);3
}
⟶ 10.94
Notes
- You usually need to round floating point values when outputting them.
- The inclusion of an integer in a List of floats is valid provided it is not the first value.
▶ To reverse the order of items in a List:
+main
1
variable nname? set to [2, 3, 5, 7, 11, 13]value or expression?2
variable nRname? set to new List<of Int>()value or expression?3
variable eLname? set to new List<of Int>()value or expression?4
call printprocedureName?(n.reduce(eL, lambda nR as List<of Int>, m as Int => nR.withPrepend(m))arguments?)5
end main
+def main() -> None:
1
nname? = [2, 3, 5, 7, 11, 13]value or expression? # variable definition2
nRname? = list[int]()value or expression? # variable definition3
eLname? = list[int]()value or expression? # variable definition4
printprocedureName?(n.reduce(eL, lambda nR: list[int], m: int => nR.withPrepend(m))arguments?)5
main()
+static void main() {
1
var nname? = [2, 3, 5, 7, 11, 13]value or expression?;2
var nRname? = new List<int>()value or expression?;3
var eLname? = new List<int>()value or expression?;4
printprocedureName?(n.reduce(eL, lambda List<int> nR, int m => nR.withPrepend(m))arguments?);5
}
+Sub main()
1
Dim nname? = {2, 3, 5, 7, 11, 13}value or expression? ' variable definition2
Dim nRname? = New List(Of Integer)()value or expression? ' variable definition3
Dim eLname? = New List(Of Integer)()value or expression? ' variable definition4
printprocedureName?(n.reduce(eL, lambda nR As List(Of Integer), m As Integer => nR.withPrepend(m))arguments?)5
End Sub
+static void main() {
1
var nname? = [2, 3, 5, 7, 11, 13]value or expression?;2
var nRname? = new List<int>()value or expression?;3
var eLname? = new List<int>()value or expression?;4
printprocedureName?(n.reduce(eL, lambda List<int> nR, int m => nR.withPrepend(m))arguments?);5
}
⟶ [13, 11, 7, 5, 3, 2]
▶ To reverse the order of the words in a String,
use reduce on a List of words (created by split and then reassembled by join):
+main
1
variable sname? set to "'Twas brillig and the slithy toves"value or expression?2
variable sRname? set to ""value or expression?3
variable eLname? set to new List<of String>()value or expression?4
set sRvariableName? to s.split(" ").reduce(eL, lambda sR as List<of String>, word as String => sR.withPrepend(word)).join(" ")value or expression?5
call printprocedureName?(sRarguments?)6
end main
+def main() -> None:
1
sname? = "'Twas brillig and the slithy toves"value or expression? # variable definition2
sRname? = ""value or expression? # variable definition3
eLname? = list[str]()value or expression? # variable definition4
sRvariableName? = s.split(" ").reduce(eL, lambda sR: list[str], word: str => sR.withPrepend(word)).join(" ")value or expression? # change variable5
printprocedureName?(sRarguments?)6
main()
+static void main() {
1
var sname? = "'Twas brillig and the slithy toves"value or expression?;2
var sRname? = ""value or expression?;3
var eLname? = new List<string>()value or expression?;4
sRvariableName? = s.split(" ").reduce(eL, lambda List<string> sR, string word => sR.withPrepend(word)).join(" ")value or expression?; // change variable5
printprocedureName?(sRarguments?);6
}
+Sub main()
1
Dim sname? = "'Twas brillig and the slithy toves"value or expression? ' variable definition2
Dim sRname? = ""value or expression? ' variable definition3
Dim eLname? = New List(Of String)()value or expression? ' variable definition4
sRvariableName? = s.split(" ").reduce(eL, lambda sR As List(Of String), word As String => sR.withPrepend(word)).join(" ")value or expression? ' change variable5
printprocedureName?(sRarguments?)6
End Sub
+static void main() {
1
var sname? = "'Twas brillig and the slithy toves"value or expression?;2
var sRname? = ""value or expression?;3
var eLname? = new List<String>()value or expression?;4
sRvariableName? = s.split(" ").reduce(eL, lambda List<String> sR, String word => sR.withPrepend(word)).join(" ")value or expression?; // change variable5
printprocedureName?(sRarguments?);6
}
⟶ toves slithy the and brillig 'Twas
Note
- In these two examples on Lists, an empty List has to defined for use as the first argument of reduce.
maxBy and minBy
maxBy and minBy are dot methods on a List.
They take a function as an argument, and return the list item corresponding to the maximum or minimum of the values returned by the function.
For simply finding the maximum or minimum value in a List, you can use
max,
min.
Examples using maxBy and minBy
▶ To find in a list the integer that has the highest last digit:
+main
1
variable aname? set to [33, 4, 0, 92, 89, 55, 102]value or expression?2
call printprocedureName?(a.maxBy(lambda x as Int => x mod 10)arguments?)3
end main
+def main() -> None:
1
aname? = [33, 4, 0, 92, 89, 55, 102]value or expression? # variable definition2
printprocedureName?(a.maxBy(lambda x: int => x % 10)arguments?)3
main()
+static void main() {
1
var aname? = [33, 4, 0, 92, 89, 55, 102]value or expression?;2
printprocedureName?(a.maxBy(lambda int x => x % 10)arguments?);3
}
+Sub main()
1
Dim aname? = {33, 4, 0, 92, 89, 55, 102}value or expression? ' variable definition2
printprocedureName?(a.maxBy(lambda x As Integer => x Mod 10)arguments?)3
End Sub
+static void main() {
1
var aname? = [33, 4, 0, 92, 89, 55, 102]value or expression?;2
printprocedureName?(a.maxBy(lambda int x => x % 10)arguments?);3
}
⟶ 89
▶ To find in a list the the shortest string:
+main
1
variable fruitname? set to ["apple", "orange", "pear"]value or expression?2
call printprocedureName?(fruit.minBy(lambda x as String => x.length())arguments?)3
end main
+def main() -> None:
1
fruitname? = ["apple", "orange", "pear"]value or expression? # variable definition2
printprocedureName?(fruit.minBy(lambda x: str => x.length())arguments?)3
main()
+static void main() {
1
var fruitname? = ["apple", "orange", "pear"]value or expression?;2
printprocedureName?(fruit.minBy(lambda string x => x.length())arguments?);3
}
+Sub main()
1
Dim fruitname? = {"apple", "orange", "pear"}value or expression? ' variable definition2
printprocedureName?(fruit.minBy(lambda x As String => x.length())arguments?)3
End Sub
+static void main() {
1
var fruitname? = ["apple", "orange", "pear"]value or expression?;2
printprocedureName?(fruit.minBy(lambda String x => x.length())arguments?);3
}
⟶ pear
orderBy
orderBy takes a lambda that has two arguments of the same Type as that of the List items to be re-ordered
and compares them, returning a Boolean value that distinguishes between less than (or greater than) for numerics and before (or after) for strings.
Examples using orderBy
▶ To reorder integers in a List, using > for ascending (you would use < for descending):
variable numbersname? set to [27, 2, 3, 5, 7, 31, 37, 11, 23, 13, 19, 23]value or expression?0
numbersname? = [27, 2, 3, 5, 7, 31, 37, 11, 23, 13, 19, 23]value or expression? # variable definition0
var numbersname? = [27, 2, 3, 5, 7, 31, 37, 11, 23, 13, 19, 23]value or expression?;0
Dim numbersname? = {27, 2, 3, 5, 7, 31, 37, 11, 23, 13, 19, 23}value or expression? ' variable definition0
var numbersname? = [27, 2, 3, 5, 7, 31, 37, 11, 23, 13, 19, 23]value or expression?;0
⟶ [2, 3, 5, 7, 11, 13, 19, 23, 23, 27, 31, 37]
▶ To reorder strings in a List, using method isBefore for descending (you would use isAfter for ascending):
+main
1
variable namesname? set to ["Simon", "Pauline", "Jason", "Zelda", "Edith", "Lance", "Alice", "Paul"]value or expression?2
call printprocedureName?(names.orderBy(lambda x as String, y as String => x.isBefore(y))arguments?)3
end main
+def main() -> None:
1
namesname? = ["Simon", "Pauline", "Jason", "Zelda", "Edith", "Lance", "Alice", "Paul"]value or expression? # variable definition2
printprocedureName?(names.orderBy(lambda x: str, y: str => x.isBefore(y))arguments?)3
main()
+static void main() {
1
var namesname? = ["Simon", "Pauline", "Jason", "Zelda", "Edith", "Lance", "Alice", "Paul"]value or expression?;2
printprocedureName?(names.orderBy(lambda string x, string y => x.isBefore(y))arguments?);3
}
+Sub main()
1
Dim namesname? = {"Simon", "Pauline", "Jason", "Zelda", "Edith", "Lance", "Alice", "Paul"}value or expression? ' variable definition2
printprocedureName?(names.orderBy(lambda x As String, y As String => x.isBefore(y))arguments?)3
End Sub
+static void main() {
1
var namesname? = ["Simon", "Pauline", "Jason", "Zelda", "Edith", "Lance", "Alice", "Paul"]value or expression?;2
printprocedureName?(names.orderBy(lambda String x, String y => x.isBefore(y))arguments?);3
}
⟶ [Zelda, Simon, Pauline, Paul, Lance, Jason, Edith, Alice]
Elan Library Reference go to the top