6 ms·
Years ago, I maintained (tongue in cheek) that OOP was a great paradigm not because it was inherently better, but because it was so bad that you had to rewrite
by kabdib 6y ago
Years ago, I maintained (tongue in cheek) that OOP was a great paradigm not because it was inherently better, but because it was so bad that you had to rewrite your code several times to make it work. And once you've written something three or four times you begin to figure out your mistakes.
Then that Gang-of-Four "Design Patterns" book became popular and really screwed things up. I swear I didn't see factories-making-factories-making-factories until that thing was published, then I couldn't go a day without encountering yet another SingletonFactoryWorkerVisitor or whatever was cool that week, ugh.
I'm joking, of course. Except about Gang-of-four. And rewriting your code.
- pwdisswordfish6 6y ago> I swear I didn't see factories-making-factories-making-factories until that thing was published No? That's a pretty good description of the sort of metaprogramming that Lisp gives you, and Lispers are really enthusiastic about that kind of thing. People will dispute the parallels, but the real difference comes down to: - non-Lisp languages being significantly less powerful - Lisp's veneer of respectability ... which shouldn't be all that odd, considering the person who gave us "design patterns" was Dick Gabriel, a Lisper. At least the "SingletonFactoryWorkerVisitor" programmers use a nomenclature that reflects the ontology the object is supposed to fit into.
- kabdib 6y agoMy guess is that LISP programmers are largely a self-selected group of pretty decent hackers. I'm basing this on some exposure to Lisp Machines in the 1980s, and some Common LISP stuff in the 90s. Generally adults. LISP is my favorite language I'll never ship a product in (well, okay, after SmallTalk :-) ). The Gang-of-Four-driven stuff I saw in C++ and Visual Basic (late 90s and early 00s) still gives me the shivers. Like, "Hey, factories are cool, let's make a bunch of them for no reason because we might need the flexibility someday." Sigh.
- marcosdumay 6y agoThere is an effect where some things work well on some languages, but fail completely when translated to others because of superficially unrelated features. Compile and run time code generation seem to be one of those things. Having a mostly pure language (even when there aren't guarantees) makes them much saner. 1 - Pre-compile time generation, by its turn seems to never work very well. And if there is developer interaction between the code generation and compiling, than it's always a disaster.
- fsckboy 6y agobut lisp has homoiconicity so lisp factories create 1st class objects at runtime, including new 1st class lisp factory factories.
- kragen 6y agoWell goodness, I wrote a factory factory factory in OCaml only eight days ago: (* A goal that succeeds if v is one of `terms` *) let rec amb (terms : term list) (v : term) = match terms with | [] -> null | term::ts -> disj (match_goal v term) (amb ts v) and null (s : state) = Mzero (* a goal that always fails *) and ... For those who don't speak OCaml (whose syntax is really quite unintuitive), that's a function named `amb` which takes a parameter called `terms` of type `term list` (in C++ syntax, that would be list<term>). It returns an anonymous function that takes a parameter called `v` of type `term`. This function may call `disj`, or it may return `null`, which is not a keyword, but actually another function I defined; it takes a parameter named `s`, which is of type `state`, and returns Mzero, which is at long last an honest-to-God singleton constant. (Of the parametric type `α stream`, as it happens, but let's not get distracted with that.) So `amb` is, in object-oriented parlance, a state stream factory factory factory. Upon being passed a `term list`, it returns a factory, which, upon being passed a `term`, returns a factory, which, upon being passed a `state`, returns a `stream`. (I only traced the `null` path in this comment, but the `disj` path also returns a stream, specifically a `state stream`—OCaml's static type checking guarantees that both return paths return compatible types.) You might think that isn't the way it's actually used, but my example code uses it in precisely that way: dump_stream (call_fresh (amb [Const 17; Pair(Const 20, Const 20); Const 11]) empty_state) ;; Here `amb` is being invoked with just a `term list`. (OCaml separates list items with semicolons, so that commas always make tuples.) So I think factory factory factories are very useful, but also I think they're really hard to keep under mental control without a functional language with a strong static type system. How on earth would you translate those four lines of code above into Java? With four inner classes, maybe, nested eight levels deep with {{}}? If you're interested, I was translating μKanren, a Prolog-like logic-programming language originally written in 39 lines of Scheme, into OCaml: http://canonical.org/~kragen/sw/dev3/mukanren.ml http://canonical.org/~kragen/sw/dev3/mukanren.ml
- lmm 6y agoA factory factory factory would be a bag of hidden mutable state that could construct another bag of hidden mutable state that could construct another bag of hidden mutable state that could construct another bag of hidden mutable state, making it virtually impossible to track down where anything in the final result had come from - things could come from any mutation to the final result, or some but not all mutations to any of the intermediate results. Without the mutable state it's not a factory, it's just a function, and there's no confusion and no problem.
- inopinatus 6y agoI think Design Patterns is often painfully misunderstood and misconstrued. My idea of using the factory pattern, for example, is not to write a MarriageFactory class, but to write a Celebrant class, and we may recognise that it embodies the factory pattern if that is helpful to the comprehension or authoring of the code. And so it goes with the others, many of which I use extensively in my own work, but at most there's a comment at the top saying, for example "this business rules structure is in the chain-of-responsibility pattern". That is the material use of patterns, they are not abstract frameworks. Naming things makes a difference: encouraging a taxonomy of purpose, rather than of form, goes a long way to re-orienting a programmer towards problem-solving with concretions rather than abstractions. As a consequence, Design Patterns, along with Refactoring and PoEAA, continues to serve as one my most-thumbed indexes of solution ideas.
- watwut 6y agoThe only thing that changed after that book is that people started to put "Factory" into the name of factories and "Decorator" into the names of decorators. Both existed for a long time before, but did not had names that would clearly instantly made them recognizable as such.
- marcosdumay 6y agoThe funny thing is that rewriting your code a lot is much easier on FP with flexible types. You just need to not pay any attention to design and start coding right away. Then you'll rewrite your FP code even more than you did for your OOP code, and still have an easier time overall. In all seriousness, I've found that a very nice way to develop FP code. It always looks good at the end anyway, and there's no risk of getting into astronaut mode.