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>
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>
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