Show HN: multimethod.js - a Clojure-inspired multimethod library for JavaScript
krisjordan.com
krisjordan.com
But what is the benchmark for this kind of structure against regular JS workflow? I guess it will be slower, but how much ?
Performance will depend on a number of factors, such as how complex your dispatch function is, how complex your dispatched values and match values are (deep equality becomes more expensive as the compared objects grow in complexity), and how many methods are registered. In general, it is much more expensive than native switch statements or prototype chain lookups.
If performance is of utmost importance and you can substitute a switch statement or prototype hierarchy for a multimethod, you should. Multimethods are a useful pattern for achieving things that either aren't possible in switch (add/remove cases dynamically, deep equality case matching) or are not naturally/painlessly expressed with a prototype hierarchy.
fib = (n) -> switch n
when 0 then 0
when 1 then 1
else fib(n-1) + fib(n-2)
alert fib 20To illustrate this flexibility in the context of fib, multimethod.js, and CoffeeScript:
> fib = multimethod()
.when(0, 0)
.when(1, 1)
.default (n) -> fib(n)
> fib 20
6765
> fib.dispatch (n) -> n.numberVal or n
> fib 20
6765
> fib { numberVal: 20 }
6765
> fib.when 2, 1
> fib.when 3, 2
> fib 20
6765 (now "optimized" with fewer recursive calls than before)So the use-case is the same use-case as defining classes, except we have a lot more flexibility.
In object-oriented programming, you can define a base class "Animal" with a method "makeNoise" and subclasses with a method "makeNoise" with that will return "bark" if you call a Dog's makeNoise or "meow" if you call a Cat's. When you first defined the Animal's "makeNoise" method you didn't need to know how anything about the subclasses that would eventually implement it. Your algorithms could depend on "makeNoise" returning the noise specific to the animal in question.
Multimethods are a functional approach to polymorphism without a class/prototype hierarchy. The second example in the post shows how you might implement a multimethod that calculates the area of shapes. Perhaps a separate module introduces new kinds of shapes (like new kinds of subclasses in OO). These shapes can register their area implementations with the 'area' multimethod. Other algorithms that use the 'area' multimethod will now be able to operate on these new kinds of shapes. Multimethods provide a means to polymorphism while keeping data and functionality decomposed.
Like swannodette says more beautifully and concisely, though, it's an even more generic/flexible dispatch than thinking in terms of OO polymorphism.