3 ms·
I have heard this said, mainly because some patterns can be made unnecessary with first-class functions and pattern matching. Closures are emulated with explici
by trealira 2y ago
I have heard this said, mainly because some patterns can be made unnecessary with first-class functions and pattern matching. Closures are emulated with explicit objects, and the visitor pattern is equivalent to pattern matching. Something that's pretty interesting, though, is that it's a transform called defunctionalization. There's an article about it [1] that has been shared before on HN.
One form of defunctionalization is the well-known transformation of a recursive function into one that uses an explicit stack.
The thing is, I don't think defunctionalization (from the equivalent functional form) present in object-oriented languages is strictly worse. Defining things with explicit objects may sometimes be more understandable, and more extensible; for example, the command pattern could be implemented as a closure, but then you can't later add an "undo" method to it later.
Here's an example where defunctionalization makes the code more readable, not less.
Haskell has a difference list [0] data structure; the purpose of it is that you can concatenate two difference lists in constant time, and then turn it into one long normal linked list in O(n) time. This gives much better performance than concatenating lists directly all the time. It's a lot like a rope, except for lists, not strings, and it's immutable.
But the code is somewhat cryptic; it makes use of partial application and stores the tree in terms of partially applied functions. The "Demystifying DList" [0] article I shared shows a defunctionalized form explicitly defined as a tree in concrete data types.
To those interested in it, if you're familiar with the syntax of ML-like languages, I'd recommend the papers [2], [3], and [4].
[0]: http://h2.jaguarpaw.co.uk/posts/demystifying-dlist/ http://h2.jaguarpaw.co.uk/posts/demystifying-dlist/
[1]: https://blog.sigplan.org/2019/12/30/defunctionalization-everybody-does-it-nobody-talks-about-it/ https://blog.sigplan.org/2019/12/30/defunctionalization-ever...
[2]: "Defunctionalization at work": https://www.cs.purdue.edu/homes/suresh/502-Fall2008/papers/defunctionalization.pdf https://www.cs.purdue.edu/homes/suresh/502-Fall2008/papers/d...
[3]: "Refunctionalization at work": https://www.brics.dk/RS/07/7/BRICS-RS-07-7.pdf https://www.brics.dk/RS/07/7/BRICS-RS-07-7.pdf
[4]: "Continuation-Passing Style, Defunctionalization, Accumulations,
and Associativity": https://www.cs.ox.ac.uk/jeremy.gibbons/publications/continued.pdf https://www.cs.ox.ac.uk/jeremy.gibbons/publications/continue...
- lmm 2y agoThere are definitely cases where a structured value is clearer than a function. But at that point you're just modelling your domain and it's not really a "command pattern" at all. The point of the command pattern is that you have an object that really and truly is just a function, you're only representing it as an object because you need to pass it around - but in that case it really is just a workaround for your language lacking first-class functions. A good language makes it easy to use both functions-as-values and structured-objects-as-callables, and use whichever representation is appropriate to the situation.
- trealira 2y agoThat's a fair point; not having first-class functions is a flaw for a high-level programming language, and the command pattern is just making up for a deficiency in the case that it would never need to be anything more than a closure in a language that does have one.