
Does Functional Programming Replace GoF Design Patterns? - tkellogg
http://stackoverflow.com/q/327955/503826
======
calpaterson
It's very common for people to repeat that claim that Peter Norvig gave in
that presentation that design patterns are work arounds for language
shortcoming. This is only true for some patterns. MVC, Facade, Composite and
others are obviously applicable in most paradigms. Moreover, some patterns are
obviated by library improvements, such as Singleton.

The truth is that modern OOP (even in Java) doesn't many of the patterns in
the GoF book any longer. That's not much of a surprise though: GoF is 18 years
old. Approaches to problems have changed and the patterns used are a bit
different.

Idiomatic Haskell is full of design patterns. Here's a few of the popular
ones: monads, composition (of functions, not objects), maybe. When I stopped
use Haskell actively, they were just getting a handle on the overuse of
monads. Pattern overuse had occurred, just as in Java. It seems that pattern
popularity follows the Hype Cycle (<http://en.wikipedia.org/wiki/Hype_cycle>)

~~~
lmm
Composite is often a work around for poor support for delegation in the
language; so too is Facade to some extent. The language feature that will make
MVC obsolete is less obvious, but I have confidence that one will arise.

>The truth is that modern OOP (even in Java) doesn't many of the patterns in
the GoF book any longer.

Oh how I wish I shared your optimism. You still _need_ Visitors and Factories
and Singletons in Java, because the language still doesn't provide the
features that replace them. At least with java 8 we'll finally be getting
lambda.

~~~
jrajav
Isn't MVC a specific case of "make your code modular"? I don't have as much
confidence that I can imagine a language getting rid of that.

~~~
lmm
It is, but most patterns are like that to a certain extent. I'm not thinking
of a language that eliminates MVC so much as one where MVC is so easy and
natural that it's not even a concept that needs a name. (Just like passing a
function as a parameter doesn't really replace the Command pattern, it just
means it's so normal and obvious that you don't think of it as a pattern).

~~~
jrajav
I'm not sure this discussion applies to MVC as easily as you're making out.
It's a design pattern, not a code pattern. Let's make it more general, though.
How would a language that "gets rid" of the problem of modular code look like?
That is, a language that makes it natural to organize your code based on high-
level functionality, responsibility, and/or dependency? It seems to me that
such a language would have to bring in arbitrary limits and introduce a lot
more problems than it would solve, assuming it's feasible at all. I'm not
saying this is something I've given a lot of thought to, it just has a
"concept smell" to me.

There are cross-cutting concerns in software development that don't have an
obvious technical solution. Modular code is one of them. There's no logical
reason for us to organize code in such a roundabout way, it's only to help us
measly humans reason about it more efficiently during the process of software
development. So, there's unlikely to be a way to unproblematically translate
that process into something logical.

~~~
lmm
A lot of the reason for MVC is to avoid mixing business logic and data. So
maybe one route to making it redundant is to have the language make more of a
distinction between data objects and logic objects. Scala's case classes give
you a slight nudge in this direction - after a while you become uneasy at
seeing a complex function on a case class, or a non-case class with lots of
data members - but it's quite subtle; maybe a future language could make it
harder to do these two things.

I think there's this constant tension in language design between giving you
the power to do really cool things (python) and the constraints to stop you
screwing up (java). But I think that more modern languages are getting further
down the funnel, combining the advantages of both.

------
toolslive
GOF patterns are indeed language agnostic, as long as you work within the OO
paradigm.

You can indeed apply the same pattern (fe visitor) in Python, Java, C++, Go.
This is also the reason why it isn't that difficult to move from one OO
language to another.

Functional programming languages fall within another paradigm. You do have
patterns like 'fold', 'map', or 'nexus' but in general, they tend to be very
small. This is because functions allow both more strict and more flexible
composition than objects. Again, once you know Lisp, or Scheme or ML you can
jump from one language to another, although from Scheme to Haskell will be a
larger jump (purity & laziness) than from Scheme to Erlang.

Two final remarks: _) The declarative paradigm (Prolog, Mercury, ...) seems to
be out of flavour these days.

_ ) Every self respecting developer should have mastered at least 1 language
in every paradigm.

~~~
fuzzix
"GOF patterns are indeed language agnostic"

I enjoyed this series of articles published some years ago making the case
that many of the useful design patterns are built into Perl already:

<http://www.perl.com/pub/2003/06/13/design1.html>

<http://www.perl.com/pub/2003/08/07/design2.html>

<http://www.perl.com/pub/2003/08/15/design3.html>

The take-away point being "If a pattern is really valuable, then it should be
part of the core language". Perl, of course, has very strong functional
features, as described in Higher Order Perl:

<http://hop.perl.plover.com/>

~~~
kamaal
>>"If a pattern is really valuable, then it should be part of the core
language"

I think this is what has caused so many misunderstandings people have about
Perl over time. Perl has so many of such patterns built which solve many
problems with default. In fact most people fall in love with Perl for these
reasons. To understand why that is important you need to recognize such
patterns in your problems, if you don't see any you will feel the solutions
contained in a language as rubbish.

The entire Unix command line toolset is entirely about this thing. Unless you
learn how to reduce a problem to a text processing problem, you will never
learn to appreciate it.

------
sold
I have some objections.

If monads are design patterns, then why not rings (Num typeclass), which allow
to use addition and multiplication in different contexts? If function
composition is a design pattern, then why not function application? If
chaining with '>>=' is a design pattern, then is using a semicolon a pattern
too? If 'fold', 'map' are patterns, then why not 'sin' and 'cos' are? What is
the difference? There's a "pattern" that after sine you put a number; there is
also a "pattern" that after a fold you put a function. Thinking that higher-
order functions are special is contrary to the spirit of functional
programming. Functions and numbers are the same class of citizens, and a
function taking a function should not be treated differently from one that
takes a number.

Bare names of often-used library functions or language constructs should not
be considered patterns, unless they occur as parts of repeating snippets. In
this case, you should refactor or encapulate. If you cannot, this is a
language flaw. It sucks if you have to type "x = new T(); try { ... } finally
{ delete x; }" each time. If your language allows to write "using (x = new
T()) { ... }" then the pattern is eliminated.

Perhaps there are some "design patterns" in FP, but examples I find often are
very weak. One thing that I would count as a pattern is "lift . lift . lift"
used in Haskell in monad transformers.

~~~
crntaylor
I agree with you in spirit, but I think your argument for why design patterns
aren't present in functional languages can also be used to argue that there
are no design patterns in object oriented languages, just by replacing the
word "function" with the word "object". Witness:

 _Thinking that objects are special is contrary to the spirit of object-
oriented programming. Objects and numbers are the same class of citizens, and
a method taking an object should not be treated differently from one that
takes a number._

Would you also argue that there are no (or very few) design patterns in object
oriented languages?

~~~
sold
I was trying to say that using higher-order functions (or functions taking
objects) is not automatically a design pattern; a pattern must consist of a
larger group of code. Patterns show up where abstractions provided by language
are not powerful enough to capture analogies.

------
dschiptsov
<http://norvig.com/design-patterns/>

The short answer is - no Java - no problem.)

The longer answer is:

 _Any sufficiently complicated C or Fortran program contains an ad-hoc,
informally-specified, bug-ridden, slow implementation of half of CommonLisp._

<http://c2.com/cgi/wiki?GreenspunsTenthRuleOfProgramming>

~~~
wtetzner
>Any sufficiently complicated C or Fortran program contains an ad-hoc,
informally-specified, bug-ridden, slow implementation of half of CommonLisp.

"Including Common Lisp." - Robert Morris

<http://paulgraham.com/quotes.html>

~~~
pdonis
My take on this was along similar lines. To me, the presence of a "design
pattern" means the language you're using isn't powerful enough to just
_encode_ the pattern in a reusable way; i.e., a design pattern is what you get
when your language won't let you just write a library function.

It's a bit interesting that Norvig talks (some) about design patterns in Lisp,
since the whole _point_ of Lisp, and particularly Lisp macros, is to be able
to rewrite the language itself, so if you find yourself wanting to use a
design pattern, you just write the macro that implements it for you.

------
hendzen
There's definitely a few design patterns that aren't applicable in functional
languages.

For example, the Visitor pattern can be naturally replaced with map and fmap
in Haskell, which are far more powerful.

~~~
scscsc
Negative, the Visitor pattern cannot be naturally replaced with map and fmap.
Read up on double dispatch at e.g.:
<http://en.wikipedia.org/wiki/Double_dispatch>

~~~
chongli
Maybe not in Haskell, but Clojure's multimethods handle this just fine.

~~~
Peaker
Haskell's type classes generalize further than multi methods do. You get
dispatch based on any part of the type signature, not just the arguments.

~~~
chongli
Not further than Clojure's multimethods. They dispatch on the value of an
arbitrary function you write. This can be anything; it's not even restricted
to types. Couple this with Clojure's ad hoc hierarchy system and even
Haskell's types seem limited by comparison.

~~~
Peaker
Can you implement the Read class in Clojure?

    
    
      class Read r where read :: String -> r
    

(Let's ignore parse errors for our purposes here)

Haskell supports return-type polymorphism. Clojure, being dynamically typed,
cannot in general support this kind of overloading.

~~~
chongli
Good point, though Clojure's extensible reader takes care of most of the use
for this.

I think it's a trade-off though. Can Haskell dispatch on a value rather than a
type?

~~~
Peaker
Note that this feature is far from being useful only for class Read.

The Monad class actually depends on it too:

    
    
      class Monad m where
        (>>=) :: m a -> (a -> m b) -> m b
        return :: a -> m a
    

The type of "return" can only be expressed with return-type polymorphism.

This means you cannot really implement Haskell-like monads with dynamic
typing. You have to implement them in a less general way.

As for dispatching on runtime values, that is ordinary pattern matching:

    
    
      f (RuntimeValue1 x y) = ... case 1 ...
      f (RuntimeValue2 x y) = ... case 2 ...

~~~
chongli
>This means you cannot really implement Haskell-like monads with dynamic
typing.

Ahh, yeah I've heard this before. It totally slipped my mind.

>As for dispatching on runtime values, that is ordinary pattern matching

Can you extend the patterns of a function at runtime (or even across modules)?

~~~
Peaker
No, you can't write a function spread across modules depending on the value of
its input, short of implementing a dispatch system.

------
raverbashing
As John Carmack said on twitter the other day:

"Finally reading Design Patterns. The cross platform WYSIWYG editor used as an
example doesn't "smell" like something actually implemented."

<https://twitter.com/ID_AA_Carmack/status/257683318907215873>

I had the same impression. How to trust the authors with such unbelievable
example.

~~~
agazso
If you read the replies you can see one from @TonyAlbrecht [1] that states it
was implemented, and it was pretty good at the time.

That said all the programs that used design patterns always seemed too
synthetic for me, as if the main purpose of the programs were generality. I
learned that often it is better to keep other goals in mind, like
practicality, simplicity or maintainability.

[1] <https://twitter.com/TonyAlbrecht/status/257685852153581569>

------
chubbard
For a hot minute this post was right above this post.

[http://doctrina.org/Javascript-Function-Invocation-
Patterns....](http://doctrina.org/Javascript-Function-Invocation-
Patterns.html)

Had to giggle a little over this silly discussion of FP and are there design
patterns or not. A strategy is the same intent whether you use a enclosed
function or an anonymous object as the strategy. Remember the old computer
programmer adage. Objects are the poor man's closure, and closures are the
poor man objects.

------
tel
_But you may have run across monads. What are they, if not a design pattern
for "dealing with global state"?_

This to me belies that the author doesn't actually do much programming with
monads. They're more like the core abstraction of an interpreter or a
sequencing algebra than a design pattern for global state.

Considering functions s -> (a, s) as "global state" is closer to a "design
pattern", though.

------
lelf
_But you may have run across monads. What are they, if not a design pattern
for "dealing with global state"?_

No, monad is a monoid in the category of endofunctors ©

Jokes aside, there are monads for function application, for software
transactional memory, for prolog's backtracking, for call/cc, for quantum
computations and for running BASIC programs. And many more

Can you stop saying “design patterns” please?

------
pella
stackoverflow: "Functional design patterns"

[http://stackoverflow.com/questions/11339637/functional-
desig...](http://stackoverflow.com/questions/11339637/functional-design-
patterns)

------
PaulHoule
I pretty often find myself "functionalizing" design patterns in in Java to
split out the verbose part from the part that is interesting.

For instance, say you have a Log object that has 15 or so Log methods for
different severity levels and signatures and you just want to write something
that prepends something to anything that gets logged.

If you split this to "something that applies a function to any message passed
to the log" and "a function that transforms a message" you get something
that's certainly better if you implement more than one transform and probably
better in the case of just one because the repetitive boilerplate is
physically separated from the "business end".

------
gaustin
What is more interesting to me is the way that the SOLID principles are
expressed in functional languages. They are all still relevant.

