Up:
  1. TkScript Reference Guide » Functions
TkScript

reference guide | Functions


 
Table of Contents:

 
1. Functions
Up:
  1. TkScript Reference Guide » Functions » Functions
Functions are used to group and parametrize frequently used statement sequences.
 
The basic idea of a function (in TkScript) is that n values go in and one value comes out (even if it is void):

function Add(var a, var b) {
return a + b;
}
trace Add(42, 23);
trace Add(1.1, 2.2);

 
Functions support modularization of programs and help to split a problem into sub problems (Divide and Conquer):

function LI(String r) {
r.append("<li>");
}
function A(String href, String caption, String r) compile {
r.append("<a href=\"");
r.append(href);
r.append("\">");
r.append(caption);
r.append("</a>");
}

// Add some random links to "document"
String doc = "<html><body>\n";
doc.append("<ul>");
LI(doc); A("http://www.tkscript.de", "The TkScript home page", doc);
LI(doc); A("http://www.contactor.se/~dast/frexxed/", "The FrexxEd home page", doc);
LI(doc); A("http://scene.org", "Demo or Die :-)", doc);
doc.append("</ul>");
doc.append("\n</body></html>\n");

doc.saveLocal("test.html");

 
TkScript has two different parser codepaths for module functions and class functions:
  • It is recommended to use class functions since
    • they support more features
      • constraints
      • strongly typed return values
      • argument declaration lists (i.e. the arg type may be omitted if subsequent arguments share the same type)
    • the order of declaration does not matter
      • class function declarations are already handled in the first (scanning) parser pass.
1.1. Function signatures
The function signature is simply its name.
 
This means that it is not allowed to declare two functions (or methods) that only differ by argument list or return type within the same scope.
 
In other words: TkScript does not support Overloading.
2. Native functions
Up:
  1. TkScript Reference Guide » Functions » Native functions
  2. TkScript reference guide / Expressions » The #() value expression
The core API and additional plugins (e.g. tkopengl) export a number of native code functions that can be used like regular script functions.
 
There is one important difference between script and native functions: Object references are always passed without the ownership flag in calls to native functions and methods.
 
Also see Value wrapper objects, The #() value expression.
 
The number of arguments to a native code function is currently limited to 16.
 
Please see →yac for more information about the native code interface.
 
The following example calls the native code function milliSeconds to calculate the execution time for a (rather pointless) loop:

int t = milliSeconds();
int i = 0; loop(10000000) i++;
t = (milliSeconds() - t);
print "ms=" + t;
3. Module functions
Up:
  1. TkScript Reference Guide » Functions » Module functions
A module function is a function that is declared within the scope of a single source module.
 
Example:

String my_string;

// Declare and implement function
function MyFunction(int i, float f, String s) {
print "i=" + i + " f=" + f + " s=\"" + s + "\" my_string =\"" + my_string + "\".";
}

// Call function
MyFunction(42, PI, "hello, world.");

 
In general, a module function is only visible within the module it has been declared in.
 
There are ways to address functions in other modules or use Function pointers to pass the function object to other modules but this should be avoided, if possible. Please use class functions and methods, instead.
 
Addressing a function in another script module:

MMyModule.MyFunction(42, PI, "hello, world.");

 
Module functions are detected not until the second parser pass which means that an Unresolved node will be created when a function is used before it has been declared. These nodes will be resolved after parsing and before the script is executed.
 
Also see Function/method calls.
4. Static methods
Up:
  1. TkScript Reference Guide » Functions » Static methods

A special case of a function is a static method which basically is a function attached to a class.
 
A static method can access all static members of the respective class (and its base classes).
 
Example:

class MyClass {
static String my_string = "hello, world.";

static public MyStaticMethod() {
print my_string;
}

static AnotherStaticMethod() {
print my_string;
}

function YetAnotherStaticMethod() {
print my_string;
}
}

MyClass.MyStaticMethod();
MyClass.AnotherStaticMethod();
MyClass.YetAnotherStaticMethod();

 
Also see TkScript reference guide / Classes.
 
4.1. Scope
The scope of a static method can be limited to the current module (module), the current class (private), the current class and all derived classes (protected) or not at all (public, default):

class C {
public function FPublic () { }
private function FPrivate () { }
protected function FProtected () { }
module function FModule () { }
function FPublic2 () { }
static FPublic3 () { }
}

 
Note: It may be tempting to use the shortest possible declaration syntax for a (static) method but I recommend to prepend methods with the method keyword simply because it becomes easier to find them in a text editor.
5. Arguments
Up:
  1. TkScript Reference Guide » Functions » Arguments
Functions may be parametrized by up to 255 (script) resp. 16 (native) arguments.
 
Function argument declarations look a lot like variable declarations. In fact, static function arguments are simply placed in the variable space of the respective function. Local function arguments are placed in a function stackframe that is created and destroyed every time a function is called / returns.
 
The argument type in the formal argument list of a class function may be omitted if two or more subsequent arguments have the same type:

class C {
static PrintVector(float x, y, z) {
print "(x="+x+"; y="+y+"; z="+z+")";
}
}
C.PrintVector(1.1, 2.2, 3.3);
6. Recursion
Up:
  1. TkScript Reference Guide » Functions » Recursion
Function arguments (and variables) can either be local or static (default).
 
Example:

function Test(int i, local String s) {
String t;
prepare { t= "hello, world.."; }
trace "i="+i+" s="+#(deref s);
trace "t=\""+t+"\".";
t.append("..");
}
Test(42, "hello, world.");
Test(23, "hello, world.");
Test(64, "hello, world.");

 
All function arguments (and also variables) that are used re-entrant or recursively must be prefixed with the local keyword.
 
A re-entrant function is a function that is called from more than one execution context (e.g. from multiple Thread s)
 
A recursive function is a function that calls itself (or calls other code that calls the function).
 
Example for a recursive function:

function Fib(local int _i) {
if(_i == 0)
return 0;
else
if(_i == 1)
return 1;
else
return Fib(_i - 1) + Fib(_i - 2);
}

print "Fib(9)=" + Fib(9);
6.1. Limits
The default recursion depth is 1024. This can be changed using the -fss, --functionstacksize commandline arguments.
 
The default stack size for all function stackframes is 1024. This can be changed using the -fcs, --functioncallstacksize commandline arguments (also see Command line interface)
7. Return value
Up:
  1. TkScript Reference Guide » Functions » Return value
A function returns nothing (void) or a single value which may be a value container holding several values.
 
The return type of a function is usually dynamic, i.e. it depends on the currently returned value:

function GetHashVal(HashTable ht, String key) {
return ht[key];
}
print #(GetHashVal(#[a=42], "a"));
print #(GetHashVal(#[b=PI], "b"));
print #(GetHashVal(#[c="hello, world."], "c"));
print #(GetHashVal(#[d=null], "d"));

 
The following example simply casts the dynamically typed argument v to another type (specified by type):

function MyFunction(int type, var v) {
switch(type)
{
case YAC_TYPE_INT:
return int(v);

case YAC_TYPE_FLOAT:
return float(v);

case YAC_TYPE_OBJECT:
return Object(v);

case YAC_TYPE_STRING:
return String(v);
}
// default: return "void"
}

trace #(MyFunction(YAC_TYPE_INT, "42"));
trace #(MyFunction(YAC_TYPE_FLOAT, "3.1415"));
trace #(MyFunction(YAC_TYPE_OBJECT, 42));
trace #(MyFunction(YAC_TYPE_STRING, 3.1415));

 
This example uses an array to return multiple values:

function MyFunction() : Object {
return [42, PI, "hello, world."];
}
Object r <= MyFunction();
int i = r[0];
float f = r[1];
String s = r[2];
7.1. The return statement
The return statement is used to return from a function before execution reaches the end of the function.
 
The return statement can also be used to simply set the default return value for a function call without leaving the function.
 
Example:

function MyFunction() {
return 42;

// this line is never reached
print "hello, world.";
}
MyFunction();

 
The expression after the return keyword is optional:

class C {
function MyFunction() {
return; // return the default return value (void)

// this line is never reached
print "hello, world.";
}
}
C.MyFunction();
7.1.1. Setting the return value
The return value of a function can be set without returning from a function call:

function MyFunction(int b) {
return = "my default return value";

if(b)
return "true return value";
else
return "false return value";
}
print MyFunction(true);
print MyFunction(false);
print MyFunction(maybe);
7.2. Return type declarations
Class functions (and methods) support the declaration of a return type.
 
The value returned by a function call is cast to the specified return type if the types are not compatible.
 
Example:

class C {
static ToInt (var v) : int { return v; }
static ToFloat (var v) : float { return v; }
static ToObject (var v) : Object { return v; }
static ToString (var v) : String { return v; }
}
trace #(C.ToInt("42"));
trace #(C.ToFloat("3.1415"));
trace #(C.ToObject(42));
trace #(C.ToString(3.1415));
8. Constraints
Up:
  1. TkScript Reference Guide » Functions » Constraints
Function arguments and return values can be assigned a constraint expression.
 
Argument constraints are checked after the actual argument list has been evaluated. A runtime error is raised when a constraint violation is detected.
 
Return value constraints are checked shortly before a function call returns and a runtime error is raised in case of a constraint violation.
 
The magic variable _ is used to refer to the current argument or return value in a constraint expression.
 
The predefined notnull constraint can be used to make sure that an Object reference is not null (or an invalid Object).
 
Example:

constraint csneg _<0 "< 0";
constraint cspos _>=0 ">= 0";
constraint csarr [0,2,4,6,8].contains(_) "value must be one of [0,2,4,6,8]";

class C {
static Test(int negI.csneg, posI.cspos, int iArr.csarr,
Object o.notnull, Object p) returns Object.notnull
{
return p;
}
}

C.Test(-1, 1, 8, "hello, world.", 42); // OK

//C.Test( 1, -1, 8, "hello, world.", 42); // violates constraint "cspos"

//C.Test(-1, 1, 10, "hello, world.", 42); // violates constraint "csarr"

//C.Test(-1, 1, 8, null, 42); // violates constraint "notnull"

//C.Test(-1, 1, 8, "hello, world", null); // violates (return) constraint "notnull"

 
To be honest, this feature was added as a proof-of-concept implementation after a discussion with a colleague some years ago.
 
Currently, I recommend to NOT use it since a) the constraint violations are currently not exceptions (and therefore not catchable) and b) the script engine does not always shut down properly if a constraint violation occurs.
 
However, the constraint checks can be entirely disabled using the -ncs,--noconstraints command line option so it cannot hurt to decorate your methods with e.g. notnull constraints..
9. Function objects
Up:
  1. TkScript Reference Guide » Functions » Function objects
A Function object is simply the Object representation of a script function or static script class method.
 
Example:

function MyFunction() {
return "hello, world.";
}
Function fo <= MyFunction;
trace #(fo);
print fo.eval({}); // evaluate with empty argument list

 
Example:

function MyCallBack(String line) {
explain "This callback function will be invoked everytime a new line has
been read from stdin."
;

trace "MyCallBack: line=\""+line+"\".";
switch(line)
{
case "?":
case "h":
case "help":
print "\n\ntype 'q' to quit";
break;

case "q":
case "quit":
print "[...] quitting..";
exit(0);
}
}

function ProcessInput(Function cbk) {
String line; line.alloc(1024);
line.empty();

while(StdInStream.readLine(line, 1024))
{
cbk.eval({line});
}
}

ProcessInput(MyCallBack);
9.1. Thread example
The following example uses a Function Object to pass the reference to a static script class method to a native C++ method (Thread.create()) :

class C {
private Thread thread;

static MyThreadEntry(local Thread t) {
C c <= t.userdata;
c.test();
}

public method run() {
thread.userdata = this;
// C.MyThreadEntry returns a Function Object for
// the static method "MyThreadEntry"
thread.create(C.MyThreadEntry);
thread.wait();
}

protected method test() {
trace "hello, world.";
}
}
C c;
c.run();
9.2. Other ways to implement callbacks
The use of function objects can usually be avoided by using an object-oriented design approach and virtual methods (see Method vtables).
 
See Delegates for a different, yet similar way to implement callback functions.
10. Synchronization
Up:
  1. TkScript Reference Guide » Functions » Synchronization
  2. TkScript reference guide / Classes » Methods

When using multi-threading, it is required to synchronize methods that are used in more than one script context (Thread).
 
TkScript supports the following synchronization short-cuts :
  • Synchronize method calls per method (=)
  • Synchronize method calls per class instance (==)
  • Synchronize method calls per named mutex (=name=)

 
Example:

=mymutex= // declare global mutex

Mutex mtx; // declare Mutex object

class C {
= public method myGloballySynchronizedMethod() { }

== public method myPerInstanceSynchronizedMethod() { }

=mymutex= public method myNamedMutexSynchronizedMethod() { }

public method myTraditionalSynchronizedMethod() {
mtx.lock();
/* ... */
mtx.unlock();
}
}

 
Note: the synchronization tags =, == and =mymutex= are currently only supported in the class parser !


auto-generated by "DOG", the TkScript document generator. Wed, 31/Dec/2008 15:53:35