I’m beginning to think that predicate-dispatch generic functions capture something really fundamental about computation, or that at least they’re much more fundamental than interfaces or adaptation. As useful as interfaces and adaptation are, they’re actually pretty cumbersome compared to generic functions.
For example, in peak.web I’d put together a framework with many Zope 3-like capabilities, that was nonetheless a lot more lightweight. It incoprorates dozens of interfaces, but far fewer than are used in Zope X3 for the same features. Today, I took a look at several aspects of the framework, and it’s looking to me like I could encapsulate something like 80% of its non-XML-related functionality in maybe half a dozen generic functions: one to respond to HTTP requests, one to traverse names in URL paths, one to get an object’s URL, one to do any special handling needed upon arriving at a particular traversal location (like requiring a login or starting a session), and one to handle formatting and/or reporting of exceptions.
In the process, I’d be doing away with at least as many interfaces, and probably that many more concrete classes. And, it would be a lot more obvious if you wanted to change some behavior, where to change it. That is, just add a method to the right generic function. No need to figure out what interface to implement or base class to subclass, just add code that says, “if this happens, do that”. So simple, so basic. Yet at the same time, more flexible!
Like peak.security before it, peak.web was built on an interlocking collection of interfaces and adaptations in order to make it flexible. But, it’s only flexible at the places where I figured out that “joints” were needed. Generic functions are more like octopus tentacles, they bend wherever you want them to bend, because you can add “joints” at runtime. So, instead of having to bend and stretch oddly to deal with the limitations of a particular set of joints, you just do your thing and move on.
So far, in fact, there is only one thing that I’ve found really sucks about generic functions, and that’s the name. Not only is it too “generic”, but in the vast majority of languages that have generic functions currently, they don’t do all the things that predicate-dispatched generic functions do. But even saying “generic functions” is bad enough without having to say “symmetrical predicate-dispatched generic functions” in order to explain how they’re different from say, CLOS or Dylan generic functions.
Maybe I should start calling them “dispatch functions” or “extensible functions” or “rule functions” or “modular functions” or something else like that. Anybody got any ideas?