|
I think you've misunderstood the design pattern dichotomy. The idea of design patterns is recognising similar problems and solving them in the same way every time instead of re-inventing the wheel (which usually yields inferior results). What PG is arguing for is that you need to take this one step further: when you've observed a pattern and implemented it more than once, your language should help you as much as possible to solve it generally by implementing the pattern itself only once. The wheel analogy breaks down here: a wheel that can be cloned for free, yet customised as needed. This sometimes works with Java-style object models[1], but most of the time you fall flat on your face, having to manually use filler code to make the abstraction work under your circumstances. You then end up with the situation where your code volume didn't change significantly moving from specific implementation to reusable abstraction + filler. As far as I can tell, PG is arguing that we should be trying to reduce the filler. Another way to look at this issue is that the people who talk about design patterns and their use in Java, etc. usually focus on a particular level of abstraction (relatively high). I suspect the reason for this is that such languages tend to have an expressiveness trough between the micro and macro levels of abstraction. I think the design patterns people (I'm failing to come up with a better term here, sorry) have developed a blind spot for this mid-level where syntactic macros and similar mechanisms operate, simply because they can't express themselves at that level in their languages of choice. [1] I'm specifically avoiding talking about static vs dynamic typing - that's NOT what this is about, which is also why Java/C# generics and C++ templates don't help that much. Dynamic languages tend to be better at this, but Haskell, ML, etc. show that that's not a necessary condition. What seems to be more important are cheap (syntax-wise) lambdas, and for certain types of problems, a way of influencing which subexpressions are evaluated and which aren't. (in Lisp, etc: macros, in certain other languages: lazy evaluation) I just realized I phrased it as "evaluating subexpressions", not "executing blocks of statements", even though the two are equivalent in different kinds of languages, yet examples of controlling execution of the latter are rare for some reason. |