Function Overloading

The ability to call the same function with different types of data is called "Function Overloading". This allows you to create multiple methods to do the same thing, but from different input data.

For example:

var ValueClass = Class('ValueClass', {
    id: 6,
    value: "",
    'construct()': function() { },
    'construct(number, string)': function(id, val) {
        this.id = id;
        this.value = val;
    },
    'construct(ValueClass)': function(vc) {
        this.id = vc.id;
        this.value = vc.value;
    },
});

var LookupClass = Class('LookupClass', {
    'private object table': [],

    // lookup a value object by id
    'get(number)': function(num) {
        for (var i in this.table) {
            var val = this.table[i];
            if (val.getId() == num) {
                return val;
            }
        }
    },

    // overload the get function to lookup a value object by it's value
    'get(string)': function(str) {
        for (var i in this.table) {
            var val = this.table[i];
            if (val.getValue() == str) {
                return val;
            }
        }
    },

    // add a new value, by providing a ValueClass object
    'add(ValueClass)': function(vc) {
        this.table.push(vc);
    },

    // add a new value, by providing an numeric id and string value
    'add(number, string)': function(id, val) {
        var vc = new ValueClass();
        vc.setId(id);
        vc.setValue(val);

        // call the add function above with our new ValueClass object
        this.add(vc);
    },

    // add a new value, by providing an anonymous object containing the id and value
    'add(object)': function(obj) {
        if ('id' in obj && 'value' in obj) {
            var vc = new ValueClass();
            vc.setId(obj.id);
            vc.setValue(obj.value);

            // call the add function above with our new ValueClass object
            this.add(vc);
        }
    },

    // add several new values at the same time
    'add(...)': function(args) {
        for (var i in args) {
            var val = args[i];
            this.add(val);
        }
    }
});

var table = new LookupClass();

var value1 = new ValueClass(1, 'bob');

// add an instance of ValueClass
table.add(value1);

// add with a number and string
table.add(2, 'joe');

// add an anonymous object
table.add({
    id: 3,
    value: 'sam'
});

// create a few different objects
var value2 = new ValueClass(4, 'george');
var value3 = new ValueClass(7, 'bill');

var obj1 = {
    id: 5,
    value: 'jenny'
};

var obj2 = {
    id: 6,
    value: 'laura'
};

// add several things at once
table.add(value2, obj1, obj2, value3);

table.get(5).getValue(); // returns "jenny"
table.get(2).getValue(); // returns "joe"
table.get("sam").getId(); // returns 3
table.get("laura").getId(); // returns 6
table.get(4).getValue(); // returns "george"

Order of Overloads

Function overloads process from child back upwards to parent, from the first entered at each level, to the last.

Warning: If you place two nearly identical overloads, where the higher in the inheritance chain is at the top, the lower overload will NEVER be executed.

Example:


var IMyInterface = Interface('IMyInterface', {
    // Interface body ...
});

var RandomClass = Class('RandomClass', { implements: IMyInterface }, { });

var MyClass = Class('MyClass', {

    // anything which implements IMyInterface will be passed here
    'test(IMyInterface)': function(val) {
        // do something
    },

    // RandomClass implements IMyInterface, so the above method will always match it.
    // This method will NEVER be called
    'test(RandomClass)': function(val) {
        // do something
    }
});

var MyClass = Class('MyClass', {

    // ALL JOII classes ultimately inherit from object,
    // so this will override ALL other one parameter methods if placed above them
    // unless they're other native types (such as string)
    'test(object)': function(val) {
        // do something
    },

    // RandomClass is an object, so the above method will always match it.
    // This method will NEVER be called
    'test(RandomClass)': function(val) {
        // do something
    },

    // This method WILL be called, because it has an extra parameter to match against
    'test(RandomClass, string)': function(val, str) {
        // do something
    }
});

Variadic Support

You can pass a variable number of parameters to a method by specifying the LAST type as "..."

This will gather all remaining parameters into an array, and pass it in to that last argument.

Example:


var MyClass = Class('MyClass', {

    // normal function overload, taking in a number
    'test(number)': function(num) {
        return "Test variant 1 - (number):              " + num;
    },

    // normal function overload, taking in a number and string
    'test(number, string)': function(num, str) {
        return "Test variant 2 - (number, string):      " + str + ": " + num;
    },

    // variadic function overload, taking in a number and unspecified other arguments after
    'test(number, ...)': function(num, args) {
        return "Test variant 3 - (number, ...):         " + num + ' = ' + args.join(', ');
    },

    // variadic function overload, taking in a number, a string, and unspecified other arguments after
    'test(number, string, ...)': function(num, str, args) {
        return "Test variant 4 - (number, string, ...): " + str + ": " + num + ' = ' + args.join(', ');
    }
});

var mc = new MyClass();

mc.test(1);                 // "Test variant 1 - (number):              1"
mc.test(1, "Test");         // "Test variant 2 - (number, string):      Test: 1"

mc.test(1, 2);              // "Test variant 3 - (number, ...):         1 = 2"
mc.test(1, 2, "asdf", 5);   // "Test variant 3 - (number, ...):         1 = 2, asdf, 5"
mc.test(1, "asdf", 2, 3);   // "Test variant 4 - (number, string, ...): asdf: 1 = 2, 3"