======Guidelines for Time Critical Code======
Use evals instead of branches.
Use parameters passed by reference instead of by value. Take care when passing list elements that will be removed, ie:
branch test()
exc(AllRefs[1])
end
branch exc(ref)
excludef(AllRefs, ref)
ref.call() //error!
end
branch exc(REFERENCE ref)
excludef(AllRefs, ref)
ref.call() //ok!
end
Use list call, array call and list operations instead of while and for, ie:
for INTEGER i = 1 .. count list
list[i] += 1
list[i] *= 2
next
//faster:
list += 1
list *= 2
Another example:
for INTEGER i = i1..i2
list[i].Prop1 += 1
next
//faster:
[list[i1..i2].Prop1] = INTEGERS{list[i1..i2].Prop1} + 1
Use switch instead of if.
======Ordering======
Geeny generates fast links to object properties, branches and evals on the fly, wherever possible. To maximize performance, the same order of properties, branches and evals should be maintained for objects that will be accessed within a specific script expression.
To some extent, the ordering is done automatically in Geeny. This is true for derived templates, which always maintain the order of properties as defined by the parent, regardless of the order within template definition itself. However, consider this example:
BEGIN object TEST1
ATOM Prop1 = 'TEST1'
INTEGER Prop2 = 10
END
BEGIN object DERIVED
OBJECT Parent = TEST1
INTEGER Prop2 = 5
ATOM Prop1 = 'DERIVED'
END
BEGIN object TEST2
INTEGER Prop2 = 15
ATOM Prop1 = 'TEST2'
END
BEGIN global ALIAS
REFERENCES Fast = TEST1 DERIVED
REFERENCES Slow = TEST1 TEST2
END
branch test1(REFERENCE ref)
ATOM Prop2 = ref.Prop2
end
branch test2
INTEGERS Prop1 = Fast.Prop1 //fast access
Prop1 = Slow.Prop1 //slow access
test1( 'TEST1')
test1( 'DERIVED') //ok
test1( 'TEST2') //fast link overriden
end
Similar problem may occur when the same script call may address an object with different branch or eval ordering:
BEGIN object TEST1
OBJECT Scripta = test1
END
BEGIN object TEST2
OBJECT Scripta = test2
END
branch test(REFERENCE ref)
ref . foo1()
ref . foo2()
end
In the above example, both test1 and test2 scripts may contain branches or evals 'foo1' and 'foo2'. However, the ordering may not be the same, which may induce a performance penalty.
This performance penalty may not be avoided for different call types (eval, branch) in both scripts; for example when in 'test1' script 'foo1' is eval, and in 'test2' script 'foo1' is a branch. When such is not the case, however, the ordering for such calls may be defined in base script, ie:
branch foo1
end
branch foo2
end
//or alternatively
eval foo1
end
eval foo2
end
//or even
branch foo1
end
eval foo2
end
Then when an object template is declared, the base script is used as the first script in the list. This will define the ordering for these calls in all derived object templates as well, regardless of the actual ordering of brances and evals in actual script files.
BEGIN object TEST1
OBJECT Scripta = base test1
END
BEGIN object TEST2
OBJECT Scripta = base test2
END
BEGIN object DERIVED
OBJECT Parent = TEST2
OBJECT Scripta = @ derived //base is inherited
END
BEGIN object DERIVED2
OBJECT Parent = TEST1
OBJECT Scripta = base derived test1 //base has to be first!
END
Problems may occur when branches and evals with same name exist on an object. This should be avoided.
======Fast routes======
The compiler generates fast route code when specific patterns are found, such as:
for counter = x..y
for counter = seqi(x, y, z)
a[x..y]
[a[x..y]]
a[seqi(x, y, z)]
[a[seqi(x, y, z)]]
The fast route cannot be generated when a pattern is broken across two lines or more, ie:
INTEGERS set = x..y
for counter = set
INTEGERS index = seqi(x, y, z)
a[index]
As a general rule, performance should be better with a fast route, even if the sequence has already been calculated before hand for other reasons and can be reused, ie:
INTEGERS list = from..to
lwriteln(list)
//faster:
lwriteln(array[from..to])
//slower:
lwriteln(array[list])