Functional SOLID – Open/Closed Principle

Continuing on the series about SOLID principles on functional programming, the next one is the Open/Closed Principle. The definition from the Wikipedia:

The open/closed principle states “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”; that is, such an entity can allow its behavior to be extended without modifying its source code.

This is kinda interesting on its own way: what’s an “extension”? Considering the context when it was written, and future interpretations of the principle, the idea is that any program should not be re-compiled (re-written, modified, etc) to be extended. The idea of this principle is that local changes should not propagate to other parts of the program: make entities as self-contained as possible, write then in a way that extensions would not depend on modifications on these entities, then “close” then to modifications. I can see two cases for the “open-closed principle” violation, and the first one is the most common:

(defn as-int [some-str]
  (when (re-matches #"\d+" some-str)
    (Integer/parseInt some-str)))

This code returns an Integer if it can parse a string as a number, and nil if it can’t. Now, suppose we want to “extend” this functionality by accepting other objects like Double (truncates to integer) or nil (returns 0). The only way to do it is to change the when to a case, but that means that for every new implementation I’ll have to change this function. Now, a better way is to use protocols:
(more…)