Use of pattern matching to implement standard design patterns affects extensibility

Oct 18, 2011 at 12:34 PM

Hi,

I'm an avid F# 2.0 user as well as some prior experiences with Java, where I used design patterns quite aggressively. 

While looking at the design patterns proposed in this project, I see that most of them (if not all of them) are implemented using pattern matching. While this might seem natural and easy to read in a language like F#, it is generally not recommended when designing software in general, since pattern matching violates the open/closed principle (see http://en.wikipedia.org/wiki/Open/closed_principle).

For instance, the command pattern example posted in this project (http://fsharp3sample.codeplex.com/wikipage?title=Command%20pattern) defines a CommandType as an enumerate with two values Deposit and Withdraw. The Do and Undo functions pattern match on these enumerate values to decide what to do.

While this achieves the desired functionality, it provides no extensibility at all. If I wanted to add a third operation (say PrintBalance), I would have to manually change all of the places where the CommandType is pattern matched (I have to admit that the F# compiler would warn if one such pattern matching expression is not updated, but still..). 

In my opinion, this design pattern would be better implemented if the TCommand type is defined as follows:

type TCommand =
   { Amount : int
      Do: int -> int -> int;
      Undo: int -> int -> int;
      Name: string }

let withdraw x = { Amount = x; Do = (-); Undo = (+); Name = "Withdraw" }

let deposit x = { Amount = x; Do = (+); Undo = (-); Name = "deposit" }

let operate (balance: int) (c: TCommand) =
  printfn "Doing a %s operation" c.Name
  let newBalance = c.Do c.Amount balance
  printfn "New balance is %O" newBalance 
  newBalance

Excuse me if it does not compile, I have no access to an F# compiler right now (not even http://www.tryfsharp.org, due to browser plug-in requirements).

Thanks,

Guido

Mar 27, 2012 at 4:01 AM
Edited Mar 27, 2012 at 4:03 AM


Design Patterns are common "best practice" ways to manage object-oriented problems that doesn't exist in functional language. While it is nice to have some sample code here, I think OO-patterns may noy be the best thing.


Why would you use ICommand anyway? Next you need some IHasPermission to check that no-one can't inject your code. And so on. While you could use the function as type in the first place.

Or if you absolutely want to just execute:

let Do f = f()

(silly method) or maybe:

let Do hasPermissions f = 
    if hasPermissions() then f()

Generally I would say extensibility is not the problem in functional programming as it is in OO-world. The reason is that with OO you try to bottom-up model the whole world. In functional programming you can use partial application and compose things with top-down design.

I could make:

let myProcess = Save >> Validate >> Send

without even yet defining the parameter, the object x, when in OO I should first define every property of this x.


Usually business logic is messy unstructured if-jungle.
You can solve this with pattern matching which keeps your complex logic clean.

I discussed this with a Java-architect and here are some examples of his sample Java-code as F#:
http://pastebin.com/2uKMDRsx
http://pastebin.com/BQfCu0fS

 

Coordinator
Apr 30, 2012 at 4:05 AM

Great suggestion, Gdecaso.. 

we will make a change according to your suggestion.