Previously, pattern matching was discussed as a mechanism by which data could be interrogated to ascertain whether it adhered to particular constraints, in order to conditionally branch to alternative behaviors. Partially missing from this discussion is one key aspect of pattern matching: deep (tree-/structure-focused) comparisons, which allow the code to ask questions about quite complex data. This allows branches to be quite specific—and confident—about the data they are handling.
As an alternative to (and in some languages, in addition to) pattern matching, consider behavior contextually more bound to function definition: dispatch. It is possible, in many languages, to polymorphically overload a given function name to respond to different types—or more contextually specific constraints—of data, and have the system automatically forward the function invocation to the appropriate overload when given supported data. Via either binding dispatch to specific ownership classes (such as in OOP), or by static, compile time linkages, the system intuits which function overload handles a given request.
However, it is also possible to determine this sort of behavior off of more information, contextually, dynamically, at run-time, and often off of larger sets of parameters. Such systems are said to have dynamic multiple dispatch, or multimethods. In languages which provide this sort of support, the overload which receives a given invocation of a function call is determined at run-time, rather than at compile-time, and usually requires some degree of contextual analysis—such as run-time type information—about the data being passed as arguments to the function call.
Such systems can be very flexible and versatile when needing to select specific branches to conditionally execute when given multiple inputs to consider. They also loan themselves well to certain types of programmatic modularity, such as passing new functionality as callbacks to a HOF. In general, multimethods will attempt to match the first implementation which has conditional constraints which satisfy the data passed to the function, which can allow for both a default fallback case, as well as a series of specific overrides for known exceptions.
JavaScript and TypeScript do not, as of yet, have language-level support for multimethods. However, various libraries do have implementations of this functionality. This series will focus on @arrows/multimethod, but such functionality likely exists in other libraries.
This library has a lot of interesting functionality, some of which will be touched upon over the next article. Reading through its documentation is suggested to get a full feel for its utility. However, to whet the appetite, consider the pattern matching example from the previous article: the exact same behavior is presented—absent typing—in this article's attached source.
The next article will cover some of the highlights of @arrows/multimethod
, and touch upon making it more type-safe to use.