@nodeguy/generic
Version:
generic functions
116 lines (84 loc) • 3.72 kB
Markdown
# Generic Functions for JavaScript
It's time to bring something <s>new</s> old to JavaScript: generic functions!
# Why?
Polymorphism in JavaScript is changing:
* ES 2015 brought an important new interface, the
[Iterable](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-iterable-interface),
which isn't a type so you can't use inheritance with it.
* After getting `Object.create` added to the language, [Douglas Crockford
doesn't use it any
more](https://www.youtube.com/watch?v=bo36MrBfTk4&feature=youtu.be&t=18m54s).
* Object Oriented Programming is dead.
[Yes](http://lists.squeakfoundation.org/pipermail/squeak-dev/1998-October/017019.html)
[sweetheart](https://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html),
[it](https://en.wikipedia.org/wiki/Composition_over_inheritance)
[really](http://www.catb.org/esr/writings/taoup/html/unix_and_oo.html)
[is](https://www.infoq.com/presentations/Simple-Made-Easy). Loosen your white
knuckles and let it go. That's it, nice and easy. Exhale.
# What are Generic Functions?
Generic functions were popularized in the [Common Lisp Object
System](https://en.wikipedia.org/wiki/Common_Lisp_Object_System), published in
1988.
A generic function has a single signature (or interface) and multiple
implementations, called methods. Unlike in OOP, the methods are specialized
across all of the function arguments, not just the first one.
For example, the signature may be:
```JavaScript
map(mapper, collection)
```
It may have different implementations based on the type of the collection:
```JavaScript
const mapMethod = (callback, array) =>
array.map(callback);
const mapMethod = (callback, set) =>
new Set([...set].map(callback));
```
It may also have a method that takes a lookup table instead of a callback
function:
```JavaScript
const mapMethod = (table, array) =>
array.map((value) => table[value]);
```
In fact we could support lookup tables for every type of collection by adding a
method that calls itself recursively like this:
```JavaScript
const mapMethod = (table, collection) =>
map((value) => table[value], collection);
```
# Usage
Here's how you could implement the above example using the library.
```JavaScript
const assert = require(`/assert`);
const generic = require('/generic')
const _ = generic._;
const map = generic.function();
map.method([m => typeof m === "function", Array.isArray], (callback, array) =>
array.map(callback)
);
map.method(
[m => typeof m === "function", c => c instanceof Set],
(callback, set) => new Set([...set].map(callback))
);
map.method([m => typeof m === "object", _], (table, collection) =>
map(value => table[value], collection)
);
assert.deepEqual(map(Math.sqrt, [1, 4, 9]), [1, 2, 3]);
assert.deepEqual(map(Math.sqrt, new Set([1, 4, 9])), new Set([1, 2, 3]));
assert.deepEqual(map({ 1: 1, 4: 2, 9: 3 }, [1, 4, 9]), [1, 2, 3]);
assert.deepEqual(
map({ 1: 1, 4: 2, 9: 3 }, new Set([1, 4, 9])),
new Set([1, 2, 3])
);
```
See `test/index.js` for more usage examples.
# Installation
`$ npm install /generic`
# Copyright
Copyright 2016 [David Braun](https://www.NodeGuy.com/)
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
these files except in compliance with the License. You may obtain a copy of the
License at `http://www.apache.org/licenses/LICENSE-2.0`. Unless required by
applicable law or agreed to in writing, software distributed under the License
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.