jsish
Functions
Not logged in

Function in Jsi have been extended to support types and default values.

An Example

We add a type to a parameter simply by appending :typename, and possibly a default value. Here is an example:

"use strict";
function foo (a:number, b:string='ok'):number {
   return a+1;
}
foo('a', 9, 10);

Upon execution this outputs:

/tmp/foo.js:4: warning: got 3 args, expected 1-2, calling function foo(a:number, b:string="ok")    (at or near "a")

/tmp/foo.js:4: warning: type mismatch for argument arg 1 'a':  "string" is not a "number"    (at or near "a")

/tmp/foo.js:4: warning: type mismatch for argument arg 2 'b':  "number" is not a "string"    (at or near "a")

/tmp/foo.js:2: warning: type mismatch returned from 'foo':  "string" is not a "number"    (at or near "a")

Note the "use strict" turns on parse and runtime type-checking.


Type Names

A type-names is one of the following:

Type Description
numberA double floating point value
booleanA boolean value
stringA string value
functionA javascript function
objectA javascript object
arrayA javascript array
regexA regular expression
userobjA userobj command, eg. from new Socket()
nullA javascript null
anyMeans any value is accepted
voidNo value, ie. undefined

Type-names (except for void and any) are usually the same as that returned by typeof.

Functions may also be given a return type. A function that is returns no value uses void:

function foo (a:number):void {
   return;
}

A function that can return anything uses any:

function foo (n):any {
   return (n?99:"Ok");
}

Checking applies only to functions that have at least one type/default-value/ellipsis.


Fuzzy-Types

Multiple types can be specified by separating with a pipe "|" character, eg:

function foo (a:number, b:number|string|boolean) {
    var typ = (typeof b);
    switch (typ) {
        case "number": return b+1;
        case "string": return b;
        case "boolean": return -1;
        default: throw "unhandled type: "+typ;
    }
}
foo(9,'a');
foo(9,9);
foo(9,true);

This also applies to returns:

function foo (x):number|string {
    return x+x;
}

Multiple (fuzzy) types are frequently used by builtin commands.


Argument Counts

Standard javascript does not complain when the number arguments in a function call do not match the parameter list.

This is also true in Jsi, except when a function is typed:

function foo (a:number, b:number):number {
   return a+1;
}
foo(9);

The presence of a type activates checking for that function, generating warnings like:

/tmp/ss.js:4: warning: incorrect arg count in function call "foo()": got 1 args, but expected 2

Extra argument warnings can be avoided by adding an ellipsis "...":

function fool (a:number, b:number, ...) {
   return console.args.length;
}
foo(9,9,9);

It is also possible to enable argument count checking for untyped functions, by setting typeCheck mode all.


Default Values

Default values allow functions to be called with fewer parameters:

function foo (a, b=1) {}
function bar (a=1, b=2) {}
foo(9);
bar();

Note that a default value must be a primitive, one of:

Type Description
numberA double floating point value
booleanA boolean value
stringA string value
nullA javascript null
voidIndicating no value (ie. undefined)

Also, when a parameter is given a default value, all following it must as well.

However, these can be set to void:

function bar (a=1, b=true, c='ok', d=null, e=void, f=void) {}

Check-Modes

BThe easiest way to turn it on type-checking is adding "use strict"; to the beginning of any line in a script file.

"use strict";
function foo (a:number, b:string='ok'):number {}

It can also be set from the command-line:

jsish -W parse,run foo.jsi;    # Perform checking at parse and run time.

Available mode values are:

Type Description
parse Turn on parse-time checking (enabled by 'use strict')
run Turn-on run-time checking (enabled by 'use strict')
all Both parse and run, plus argument checking for untyped functions
proto Emit warnings for named function calls with no prior declaration
error Promote runtime warnings to errors

The mode can also be changed via Interp.conf():

Interp.conf({typeCheck:['error','run','parse']}); // Promote warnings to errors .

By default type checking is silently disabled after 50 warnings, but this is configurable with:

Interp.conf({typeWarnMax:0}); // Unlimited warnings.

Limitations

There are limitations to what Jsi type-checking can detect.

In particular, parse checking of argument types involving javascript variables do not work. This is due to the dynamic type of javascript variables.

Therefore parse checking is really only able to verify non-variable arguments and arg-counts.

Also, function calls can not be parse-checked prior to a functions definition, unless there is a forward declaration such as:

function f(a:number):number{} // Forward declaration.

function b() {
    f(1,2);
}

function f(a:number):number {
    return a+1;
}

To dynamically enable parse before files are parse we can use include() or require() as in: ../../DebugUI/main.jsi.

parse checking is also limited to simple named functions. Object members function are not checked.


Miscellaneous

The rules for defining functions are:

  1. All or no parameters should be given types.
  2. A default value can only be a primitive.
  3. When a parameter is given a default value, all following it do as well.
  4. Functions with a type are type-checked.

If a function has no types or defaults, it is by default treated in normal javascript fashion. ie. no type-checking is applied.

Although not discussed here, a peek at the reference shows that builtin commands make extensive use of typing.

In the Jsi code-base, these extend to: