BLOG | CODE | ABOUT

Documentation

This section is under construction, but it should give you a good understanding of the library. I will complete and clarify it as I receive questions and feedback.

How it works

The simplest way to explain how to use fSignatures is, I guess, to explain the underlying mechanisms.

Function wrapping

The basic idea is that the function you want to apply typechecking to is wrapped inside another one. That way, we may first filter the arguments. If they're of the right type, we call the function and grab its return value. If the return value is of the right type, the wrapper returns it to the original caller.

In pseudocode, this would give:

    function constructWrapper(wrappedFunction,
                              correctArgTypes,
                              correctReturnType){
        return function(arguments){
            verifyArguments(arguments, correctArgTypes);
            var returnValue = wrappedFunction(arguments);
            verifyReturnValue(returnValue, correctReturnType);
			
            return returnValue;
        }
    }

The wrapped function is actually called in the same context as the wrapper, with apply(), so it may use the this keyword correctly.

The Signature object

The functions participating in the wrapping are args(), returns() and f(). args() and returns() both return a Signature object. That object simply stores the signature parameters, mainly arguments and return types. The chaining works by returning the Signature object itself. That object possesses the args(), returns() and f() methods, so the remaining ones may be called with a dot syntax (args.returns.func).

The f() function is special in that it returns the wrapper function instead of the Signature object. It actually constructs the wrapper function, and attaches a ._signature object to it. That ._signature member points to the original Signature object, which is useful to check interfaces (see bellow). Because it does not return the signature object directly, f() has to be the last in the chain, but it doesn't matter if returns.args.f or args.returns.f order is used.

It is possible to add elements in the chain, other than args() and returns(). An example of this is repeatLastArg(), which permits the repetition of the last argument type when calling the function. That way, you may write

    var myFunction = $.tc
        .args($.ty._string) // $.ty contains the TypeCheckers, see bellow
        .repeatLastArg()
        .returns($.ty._number)
        .f(...);
    
    // This is allowed now
    myFunction("string1", "string2", ...);
    

TypeCheckers

Actual type checking is performed by, hrm, TypeCheckers. These are simply objects having a "check" function, to which we pass the actual values sent before the wrapped function is called. If the value passed isn't of the right type, the type checker throws an error with some explanation of why there was no match.

To be able to actually filter arguments, TypeCheckers check() functions are required to return the original variable, or a filtered version. That way, as an example, a TypeChecker may provide a default value (which is what the opt() TypeChecker allows).

Here is some sample code for a string TypeChecker:

    var stringChecker = new TypeChecker(
        "stringTypechecker",
        function(val){
            if(typeof val == 'string'){
                return val;
            }
			
            throw new Error("Expected 'string' type, got "+typeof val);
        }
    );
    
    // Example use.
    // In actual use, check() is called for you by the function wrapper.
    stringChecker.check("my string") == "my string"; // true
    
    // Throws an error
    stringChecker.check(1234);

(The first parameter to the TypeChecker() constructor is used for comparison of signatures, in interfaces. As TypeCheckers may be constructed on the fly, and contain other inner TypeCheckers, simple variable comparison is not enough.)

TypeCheckers are contained in the $.ty object. You may access them with syntax like $.ty._string. The underscore is used to avoid conflict with JS keywords. But writing $.ty._string is a bit tedious. You may, in a signature, simply write "str" (with the quotes), and a lookup is made in the $.ty object, where the "str" entry also maps to the $.ty._string TypeChecker. This makes for cleaner signatures, like so:

    var myFunction = $.tc
        .args('str') // otherwise we would have $.ty._string
        .returns('num')
        .f(...);

InterfaceChecker

As explained in the "Signature object" section above, the f() function attaches a Signature object to the function wrapper. If the methods of a given object were declared using the f() syntax, we may therefore compare their signatures to the ones found in an InterfaceChecker members.

An InterfaceChecker is therefore simply a TypeChecker to which is passed a map of function names along with their signatures. The cute bit is that to declare those signatures, you may simply reuse the args().returns() syntax, and leave out the f() part at the end. That way, you simply get a Signature object.

For sake of readability, here's the example given in the "Overview" section:

    // Methods that must be present in object implementing addableInterface
    // Notice the use of the same syntax as for function declaration, but
    // without the final "f()" of the function itself.
    var addableInterfaceMembers = {
        "addTo": $.tc
            .args('num')
            .returns('num')
    };
    
    // Interface object
    var addableInterface = $.tc.interfaceChecker(addableInterfaceMembers);
    
    // Object implementing addableInterface
    var addableObj = {
        innerNum : 42,
        addTo : $.tc
            .args('num')
            .returns('num')
            .f(function(theNum){
                return theNum + this.innerNum;
            })
        }
    
    // Function taking an addableInterface instance has parameter
    var addThose = $.tc
        .args('num', addableInterface)
        .returns('num')
        .f(function(theNum, addable){
            return addable.addTo(theNum);
        });
        
    // Call to the function with an object implementing said interface
    addThose(84, addableObj);

Usage

Inclusion

Simply include the fsignatures.js file and, optionally, change the context to which the .tc and .ty objects are appended. You simply have to replace $ by the global object that suits you at the end of fsignatures.js. If you're using a library that defines $ (such as jQuery), you better include that library before fsignatures.js, otherwise the .ty and .tc objects might be overwritten.

Reference

To be completed (lacks details).

The $.tc object

The $.tc object contains the core functions args() and returns(). You must call $.tc.args() or $.tc.returns() to start the signature chain. Only once this is done may you call f() ($.tc.args().returns().f()).

The last argument may be repeated if repeatLastArg() is present in the chain (see example above).

The $.ty object, containing the TypeCheckers

The $.ty object contains the following TypeCheckers, by default (TBD: add shorcuts for those TypeCheckers):

You may add your own TypeCheckers by creating TypeChecker objects, as explained in the section concerning them above. You may also add them to $.ty, but only after the library has been included.