XSharper has a concept of a subroutine, that accepts 0 or more arguments and returns a single object value.
<!-- SUB1.XSH. Calculate squares of 20 and 50 -->
<xsharper>
<set a="${=20}" />
<call subId="square" outTo="result">
<param>${a}</param>
</call>
<print>${a}*${a} = ${result}</print>
<print>50*50 = ${=square(50)}</print>
<!-- Subroutines -->
<sub id="square">
<param name="n" required="true" />
<set ret="${=$n*$n}" />
<return>${ret}</return>
</sub>
</xsharper>
As seen above, subroutines may be invoked directly from the expressions.
To execute square subroutine from another script, it's possible to use include action:
<!-- SUB2.XSH. Calculate square of a value specified as a command-line argument -->
<xsharper>
<include from="sub1.xsh" />
<param name="v" required="true">Value to calculate square</param>
<print>${v}*${v} = ${=square($v)}</print>
</xsharper>
Finally, execute another script as if it was executed from command line:
<!-- SUB3.XSH. Print square of a value using SUB2.XSH -->
<xsharper>
<exec from="sub2.xsh">
<param>500</param>
</exec>
</xsharper>
Isolation level
By default, subroutines have read-only access to the variables of the caller and any set or changed variables in the subroutine body are restored.
<set x="50" />
<print>Before call x=${x}</print>
<call subId="sub" isolation="default" />
<print>After call x=${x}</print>
<sub id="sub">
<print>Sub. Initially x=${x|'Undefined'}.</print>
<set x="100" />
<print>Sub. Later x=${x}.</print>
</sub>
The code above will print:
Before call x=50
Sub. Initially x=50.
Sub. Later x=100.
After call x=50
This behaviour can be changed by caller, by changing attribute isolation
With isolation="none", when no variables are restored, the output will be
Before call x=50
Sub. Initially x=50.
Sub. Later x=100.
After call x=100
With isolation="high", the subroutine will have a totally clean variable list, w/o access to the caller variables at all:
Before call x=50
Sub. Initially x=Undefined.
Sub. Later x=100.
After call x=50