Functions
You can group code between { and }, it then becomes a function. In xoscript we also use the term task sometimes or simply block of code.
You can run a function by sending the message start.
{ Out write: 123, stop. } start.
If your function takes arguments, use apply:.
{ :a Out write: a, stop. } apply: a.
Also see the examples below. Because of the simplistic architecture, a function can only have one point of return. To avoid overhead or excessive nesting for conditions, you can use a procedure (which is the same as using multiplication sign with argument 1):
{
(a = 1) true: { x := 1. }, break.
(a = 2) true: { x := 2. }, break.
} procedure.
This way, (a = 2) will not be evaluated if a = 1. Also, you don’t need nested true-messages this way. Whenever you find yourself nesting conditions, think of the procedure message. It might make your code easier to read.
Here is an important gotcha:
{
False false: {
Out write: ['End the loop.'].
}, break.
Out write: ['Dont show me.'].
} procedure.
In this case, the text ‘Dont show me’ will be shown. Because break is send to False. If you want to execute a break, it needs to be send as a message to True.
{
False not true: {
Out write: ['End the loop.'].
}, break.
Out write: ['Dont show me.'].
} procedure.
Will work as expected.
Exceptions
Exceptions can be handled like this:
{ Task 1 } except: { Task 2 }, start.
You can also cause an error to occur in your program intentionally; and by doing so, activate the handler block. This is done by sending the message error: to the current task as shown in this next illustration:
{
this-task error: ['Whoops!'].
} except: { :mistake
Out write: mistake.
}, start.
Injecting values
Xoscript provides for tasks the option to inject values. Now, have a look at the task below:
>> sending := {
Newsletter to: own recipient.
}.
sending set: ['recipient']
value: ['info@recipient.org'].
sending start.
This illustration presents an imaginary task, which sends a newsletter to an email address or recipient. This recipient can be injected into the task, externally and before the task is started, by sending the message set:value: to the task. By doing so, the value of recipient is preset into the task. This value can also be modified and the task can then be run again. This is a useful method when using Task objects.
Empty Functions
Empty tasks are not allowed. In theory an empty task would look like this: {}, however Xoscript perceives this as a language error. If you like to declare an empty task, you can use the None object:
>> task := None.
Although, this is not a real task, but a None object, a start message can still be sent:
>> answer := task start.
In fact this is the same as:
>> answer := None start.
Because the object None does not recognise the message start, it will return itself as answer, leaving the answer once again None. So, there is no necessity to have an empty task. Due to the elegant design of the programming language Xoscript, you can simply use the None object for this.
Dynamic Scoping
When a Function needs a variable but can’t find it, it will check the variables of the Function that called it, and continue checking up the chain of Functions. This search process goes on until the variable is found. If the variable is still not found, an error message will appear. This method of searching for a variable is called Dynamic Scoping.
To illustrate this principle:
Example:
>> y := { x := 2. }.
{ >> x := 1. y start. Out write: x. } start.
Result:
[ Code ] × [ Number ]
Example:
{ :i Out write: i. } * 7.
Result:
[ Code ] procedure
Example:
>> x := 1.
{
(x = 1) true: { Out write: ['x']. }, break.
Out write: ['y'].
} procedure.
{
(x = 1) true: { Out write: ['x']. }, break.
Out write: ['y'].
} × 1.
Result:
[ Code ] start
Example:
{ Out write: ['123'], stop. } start.
Result:
[ Code ] apply: [ Object ]
Example:
>> q := { <- 9. } start.
Out write: q, stop.
q := { :a <- a * a. } apply: 6.
Out write: q, stop.
q := { :a :b <- (a + b). } apply: 3 and: 4.
Out write: q, stop.
q := { :a :b :c <- (a + b + c). } apply: 3 and: 4 and: 1.
Out write: q, stop.
Result:
[ Code ] while: [ Code ]
Example:
>> x := 0.
{ x add: 1. } while: { <- (x < 6). }.
Out write: x, stop.
Result:
[ Code ] set: [ String ] value: [ Object ]
Example:
>> x := { Out write: (own q + ['!']), stop. }.
x set: ['q'] value: ['123'].
x start.
Result:
[ Code ] error: [ Object ]
Example:
{
this-task error: ['xxx'].
} except: { :e
Out write: e.
}, start.
Result:
[ Code ] catch: [ Code ]
Example:
{
>> z := 4 ÷ 0.
} except: { :e
Out write: e, end.
}, start.
Result:
[ Code ] string
Example:
>> x := { 1 + 1. }.
Out write: x, stop.
Result: