overload2
v0.3.2
Published
Elegant solution for function overloading in JavaScript
Downloads
3,281
Readme
overload2
Elegant solution for function overloading in JavaScript.
When you are tired with writing tasteless code to do with arguments, overload2 will MAKE THINGS EASY.
On programming with strongly-typed languages such as C++ and Java, function overloading is frequently employed to make API more convenient to be used. As a weakly-typed language, JavaScript does not support function overloading. At the same time, fortunately, functions in JavaScript may be passed with any arguments that is why overload2 is feasible.
Table of contents
- Get Started
- Datatypes
- Mutable Parameter
- Move Forward
- APIs
- Examples
- Why overload2
- Honorable Dependents
- About
- References
Links
Get Started
Install overload2 firstly.
# Install overload2 and save as a dependency of current package.
npm install overload2 --save
Open node and run next code:
const overload2 = require('overload2');
// Create a function with overloaded implementations.
var getDay = overload2()
// Create an overloaded implementation with method overload().
// The last argument is the implementation function,
// and the previous is/are used to qualify the datatypes or number of real arguments.
.overload(
Date, // consturctor function
function foo(d) { return d.getDay(); }
)
.overload(
'string', // predefined datatype
function bar(s) { return new Date(s).getDay(); }
)
.overload(
'number', 'number', 'number',
function quz(year, month, date) { return new Date(year, month - 1, date).getDay(); }
)
.overload(
2, // length of arguments
function md(month, date) {
var d = new Date;
return d.setMonth(month - 1), d.setDate(date), d.getDay();
}
)
.overload(
'*', Date, '*',
function select(some, d, others) {
return d.getDay();
}
)
;
getDay(new Date);
// foo(d) invoked
getDay('2000-1-1');
// bar(s) invoked
getDay(2000, 1, 1);
// quz(year, month, date) invoked
getDay(12, 1);
// md() invoked
getDay('foo', 'bar', new Date, 'quz');
// select() invoked
Datatypes
According to overload2 , there are different ways to define a datatype.
- Constructor Function
- Customized Datatype
- Predefined Datatype
- Datatype Alias
- Create Datatype With Factory Method
Constructor Function
overload2 can match any instance with its constructor function, e.g. [0,1]
is matched with Array
. See another example:
var getDay = overlaod2()
.overload(Date, function foo(d) { return d.getDay(); })
.overload(String, function bar(s) { return new Date(s).getDay(); })
;
getDay(new Date); // foo() invoked
getDay(new String('2000-1-1')); // bar() invoked
Customized Datatype
You may create customized datatypes by new overload2.Type(fn)
, e.g.
// Create a Type object.
var MonthName = new overload2.Type(function(value) {
var names = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
return names.indexOf(value) >= 0;
});
// Customized type may be used on overloading.
var getDay = overlaod2()
.overload(Date, function foo(d) { return d.getDay(); })
.overload('number', MonthName, 'number', function() {
return new Date(year, month - 1, date).getDay();
})
;
getDay(2000, 'Jan', 1);
Predefined Datatype
| Predefined Data Type | Remark |
| :---------------------------- | :------------- |
| overload2.Type.ANY | Anything. |
| overload2.Type.BOOLEAN | It must be true
or false
, anything else including instance of Boolean
is unmatched. |
| overload2.Type.CHAR | A string whose length equals 1, e.g. "a" |
| overload2.Type.NUMBER | A number, but NOT instance of Number
. |
| overload2.Type.PLAIN_OBJECT | An object whose constructor is Object
instead of anything else. |
| overload2.Type.SCALAR | A number, string or boolean, but NOT instance of Number
, String
or Boolean
. |
| overload2.Type.STRING | A string, but NOT instance of String
. |
ATTENTION:
Predefined datatypes named
Type.BOOLEAN
,Type.NUMBER
andType.STRING
refers to primitive values with types ofboolean
,number
andstring
, not their Object-wrapped forms. If Object-wrapped form required, just directly use constructor functionsBoolean
,Number
andString
as datatype, see Datatypes: Constructor Function.Before version 0.1.0, predefined datatypes are appended directly to the
overload2
module. To avoid ambiguity in future, predefined datatypes will be appended tooverload2.Type
. Although the old ones reserved, it's strongly suggested not to useoverload2.<PREDEFINED_TYPE_NAME>
any longer.
Datatype Alias
ATTENTION: Datatype aliases are CaseSensitive strings.
| Alias | Corresponding Datetype | | :--------- | :------------------------------ | | ? | overload2.Type.ANY | | any | overload2.Type.ANY | | boolean | overload2.Type.BOOLEAN | | char | overload2.Type.CHAR | | number | overload2.Type.NUMBER | | object | overload2.Type.PLAIN_OBJECT | | scalar | overload2.Type.SCALAR | | string | overload2.Type.STRING |
Create Datatype With Factory Method
overload2 offers some factory methods to create frequently used datatypes, e.g. enum.
overload2.Type.enum(item [, ...])
Return an enumeration type.overload2.Type.and(type1, type2 [, ...])
Create a compound type.overload2.Type.or(type1, type2 [, ...])
Create a compound type.overload2.Type.not(type)
Create a new type which is complementary to the origin type.
Mutable Parameter
By appending size decorator, we can define mutable parameters. E.g.
var add = overload2()
.overload('number *', function(numbers) {
var ret = 0;
numbers.forEach(function(number) { ret += number; })
return ret;
})
.overload('boolean {2,3}', function(bools) {
var ret = false;
for (var i = 0; !ret && i < bools.length; i++) {
ret = bools[i];
}
return ret;
})
.overload([ Date, '+' ], function(dates) {
var date = dates[0];
for (var i = 1; i < dates.length; i++) {
if (date < dates[i]) {
date = dates[i];
}
}
return date;
})
;
Size decorators look like repetition in regular expression. Here are some examples for overload param with size decorators:
[ Date, '{2,}'] // takes at least 2 arguments which are instances of Date
'number *' // takes any number (including zero) of arguments of type number
'*' // takes any number (including zero) of arguments of any type
'+' // takes at least one argument
'?' // takes one argument
'{2}' // takes 2 arguments
'{2,4}' // takes 2 to 4 arguments
'{2,}' // takes at least 2 arguments
'{,4{}' // takes no more than 4 arguments
// The braces may be omitted, so the following are also valid.
'2'
'2,4'
'2,'
',4'
Move Forward
Beyond the basic use, overload2 is also suitable with more complex and large-scale programs. See the class hierarchy shown below:
The usage of classes in overload2 is explained in the next table:
| Class | Remark | | :------------------------------- | :------------- | | overload2.OverloadedFunction | wrapper of overloaded function, not a function instance itself | | overload2.Overload | to define overloading implementation | | overload2.ParamList | to define a parameter list | | overload2.Param | to define a parameter | | overload2.Type | wrapper of class (consturctor function), or to customise some datatype |
Instances of Type
, Param
, ParamList
and Overload
are able to be created independently and be re-used in creating instances of superior class(es).
Here is an example for advanced mode.
APIs
- overload2()
- class overload2.Type
- class overload2.Param
- class overload2.ParamList
- class overload2.Overload
- class overload2.OverloadedFunction
overload2(), Create An Overloaded Function
overload2
itself is a function, when invoked, it will return an overloded function instance.
<fn> overload2()
Create a new overloaded function. The function has no implementations before.overload()
called.<fn> <fn>.overload( [ <datatype>, ... ] function <implementation> )
Append an overloading implementation to existing overloaded function.<fn> <fn>.default( function <implementation> )
Set default implementation function for existing overloaded function.
class overload2.Type
To define a datatype in context of overload2, there are different ways including overload2.Type
. And all other datatypes will be converted to instances of overload2.Type
before being used.
new overload2.Type( function | RegExp <matcher> )
Herematcher
may be a function or RegExp object.private boolean <type>.match( <value> )
Returntrue
if value matches the datatype, otherwise returnfalse
.
class overload2.Param
A Param is made up of a Type and some decorators. Available decorators are:
| Decorator | Remark | | :----------- | :------------- | | null | If argument equals null, it matches the parameter. | | undefined | If argument equals undefined (the place should be occupied), it matches the parameter. | | absent | The argument may be absent (optional). See example code for more details. |
new overload2.Param( string "<alias> <decorator> ..." )
Thealias
should be one of alias listed in table Datatype Alias.new overload2.Param( Type | function | string <datatype>, string <decorator(s)> [ , string <decorator(s)> ] )
Heredatatype
may be instance ofType
, or construtor function, or datatype alias.private boolean <param>.satisfy( <value> )
To judge if the argument value satisfy the parameter.Param overload2.Param.parse( ? )
Arguments suitable fornew Param()
are also suitable for theParam.parse()
.
class overload2.ParamList
new overload2.ParamList( [ Param | Array | String <param> [ , ... ] ] )
Hereparam
may be an instance ofParam
, or a string or an array which may used as argument(s) fornew Param()
.private boolean <paramList>.satisfy( Array | Arguments <args> )
To check arguments with parameters, returntrue
if matched orfalse
if not.ParamList overload2.ParamList.parse( ? )
Arguments suitable fornew ParamList()
are also suitable for theParamList.parse()
.
class overload2.Overload
new overload2.Overload( number , function <implementation> )
Create anOverload
instance by restricting the number of arguments.new overload2.Overload( ParamList, function <implementation> )
Create anOverload
instance bound to specifiedParamList
.new overload2.Overload( <param> [ , ... ] , function <implementation> )
Create anOverload
instance with optional definitions ofParam
.new overload2.Overload(function <implementation> )
Create anOverload
instance which will be invoked while arguments length equals 0.Overload overload2.Overload.parse( ? )
Arguments suitable fornew Overload()
are also suitable for theOverload.parse()
.
class overload2.OverloadedFunction
new overload2.OverloadedFunction()
The instance ofOverloadedFunction
is a wrapper, not a function itself.<wrapper>.exec( ... )
Run the overloaded function.<wrapper>.apply( <scope>, Array | Arguments <args> )
Run the overloaded function under specified scope, passing arguments as an array or Arguments instance.<wrapper>.call( <scope> [ , <arg> [ , ... ] ] )
Run the overloaded function under specified scope, passing arguments one by one.<wrapper>.overload( Overload <overloadInstance> [ , Boolean ] )
Append an overloading implementation.<wrapper>.overload( ? )
Append an overloading implementation, arguments suitable fornew Overload()
are also suitable for the<wrapper>.overload()
.
Examples
Basic Usage
To create overloaded function in simple way.Unit Test
Another way to understand overload2 is via reading unit-test code. To run the unit test on the local installed module, please:# Change to the installing directory of overload2. cd node_modules/overload2 # To install devDependencies. npm intall # Run test. npm test
Overloaded Constructor Function
Overloaded function created by overload2 may also be used as class constructor.Run Overloaded Function Under Specified Scope
A function created by overload2 may also be invoked by.apply()
,.call()
, as normal functions do. And, it may also be bound to specified scope with.bind()
.Mutable Parameters
Explain how to define mutable parameters.Optional Parameters
Explain show how to indicate a param which may be absent (that means it is optional), and how to set the default value.Parameter Decorators
Introduce available decorators used to define a more complex parameter.Advanced Usage
Use overload2 in complex situations.
Why overload2
There have been dozens of packages devoted to function overloading in JavaScript, and some of them are really not bad, e.g.
So, is overload2 redundant? I donnot know. Each of previous is unsatisfactory more or less, of course overload2 is not perfect either. Maybe future ECMAScript specification will support function overloading. However, until then, I will depend on overload2 while coding in JavaScript.
Honorable Dependents
Welcome to be the first dependent of overload2!
About
Why postfixed the package name with number 2? Since name "overload" has been occupied, inspired by well-known package "pm2" and "through2", I thought "overload2" is not bad. The most important reason why I choose "overload2" was because 2 /tu:/ is pronounced like tool /tu:l/.
References
- MSDN: Overloading and Signatures
- MSDN: Signatures and overloading
- StackOverflow: What is an “internal slot” of an object in JavaScript?