Injecting functions

Let’s say we have two ways of getting the same information. We’ll use one or the other depending of the context of our code; and there is no guarantee that a third way won’t appear.

So, this is our scenario, it could’ve been written in Java:

//Returns "12" when the parameter v is "a",
//"3" if v is "b"
//and "-1" otherwise.
def fetch_info(v: String) = v match {
 case "a" => "12"
 case "b" => "3"
 case _ => "-1"
}
//concatenates the string parameters
def action1(param1: String, param2: String, common: String) =
 param1 + param2 + common
//with the first parameter, retrieves a string from fetch_info
//and concatenates it with the common parameter
def action2(param1: String, common: String) =
 fetch_info(param1) + common

val param3 = fetch_info("b")
//both return "123"
action1("1", "2", param3) == action2("a", param3)

As I said, we have two ways of getting the same information. In one case, the processing is straightforward, just concatenates the Strings. The second case could happen when this Strings are not at hand, so we need to call fetch_info to gather the missing information.

We could realize that the common operation is the concatenation of the common parameter with either the result of fetch_info or the concatenation of  param1 and param2. So we can create two functions, both use common_action to create the final result.


//common operation
def common_action(param1: String, common: String) =
 param1 + common
//concatenates the the string parameters
def action1_common(param1: String, param2: String, common: String) =
 common_action(param1 + param2, common)
//with the first parameter, retrieves a string from fetch_info
//and concatenates it with the common parameter
def action2_common(param1: String, common: String) =
 common_action(fetch_info(param1), common)
val param3 = fetch_info("b")
//both return "123"
action1_common("1", "2", param3) == action2_common("a", param3)

We could leave it there; but what if we know that a third kind of action could come up? We could implement the Bridge Pattern and/or the Adapter Pattern — hence the title of the post, the Bridge Pattern uses Dependency Injection;  but with Scala there is a another option, a functional one.


//takes two parameters and returns a function that takes a String
//and returns a String
def action1_2(param1: String, param2: String): (String) => String =
 (c) => param1 + param2 + c
//takes one parameter and returns a function that takes a String
//and returns a String
def action2_2(param1: String): (String) => String =
 (c) => fetch_info(param1) + c

val param3 = fetch_info("b")
//both return "123"
action1_2("1", "2")(param3) == action2_2("a")(param3)

I know that looks a little useless, but is good to understand what’s happening.

Both action1_2 and action2_2 return a function that takes a String and returns a String. That means that action1_2(“1”, “2”) and action2_2(“a”)  actually return functions of the form:

(String) => String

That’s why we use these closures, they create the functions we need.

(c) => param1 + param2 + c
(c) => fetch_info(param1) + c

We kind of “normalized” the operation. Now we can pass the resulting function around, gaining abstraction. That means we can do something like this:

//this operation takes a param for retrieving the "3" and
// then applies the "action" to get the final result
def big_operation(param: String, action: (String) => String): String =
 action(fetch_info(param))
//both return "123"
big_operation("b", action1_2("1", "2")) == big_operation("b", action2_2("a"))

big_operation is isolated from the function that obtains the information big_operation needs. Which means that if a third way of getting “123” appears, big_operation wouldn’t have to change(we are assuming that big_operation is big, with a lot of logic).

But how to reason about this? Is no like we want to keep refactoring code for the rest of our life; well, we will, but the refactorization could be reduced if we came up something like big_operation since the beginning.

In this case, the best way of finding a pattern is to find the common operation:

def common_action(param1: String, common: String) =
 param1 + common

Not the actual function of course, but the pattern of having one common element that has to be used with some other calculable element. Meaning:


(common) => param1 + common

Assuming we have param1 in scope. Which we have in action1_2(“1”, “2”) and action2_2(“a”). That usually means that we can “bind” the common parameter as dependency to partial operations. That sounded weird, but it implies that we need to return a function that takes common as a parameter. I said “partial”,  because we are actually returning a function that has already a few parameters applied, but still need another(s) to return a proper result.

That’s why we returned the closures, and that’s a cool way of doing Dependency Injection (-ish) with Functional Programming

Is not a bad idea to take a look to:  The Neophyte’s Guide to Scala Part 11: Currying and Partially Applied Functions. And the whole series for that matter.

 

Advertisements

Grasping immutability

I work in a Scala shop. We are a small start-up. When I arrived, the CTO was the only developer on the back-end and  we were inheriting a large ill-written ruby codebase. Fortunately, the CTO told me that the first “task” was to rewrite everything in Scala. So we did, and now we are an Scala shop.

Our lifes are fulfilled with happiness; but that’s not true for the new members of the team. The company is in South Florida, a place were only old people and spring-break-teens want to move in. So we pick developers that are smart and eager to learn, even if they don’t have any experience with Scala or functional programming in general, which they never have.

The new members learn as they go, since we can’t wait for them to be comfortable with Scala. This has gave me the opportunity of witnessing all kinds of code: from the carefully crafted that our CTO produces, to the crude, and often pragmatic, that our less experienced developers write.

One concern of theirs is that they might not be writing a “worthy” code. I also had that problem when I started. I have come to consider that craving for the “right’ code, is one of the worst dangers when learning Scala. There are too many ways of doing it right, the doubt can be paralyzing.

One of the developers asked me if I was OK with his code having vars. I told him I didn’t really care, but he should be careful about passing those vars around, they should have a limited scope; then I gave him a little talk about immutability and its benefits. This happened a few times. Of course, what he understood each time was that vars were OK, and he just kept going on with his work. Eventually he hit a wall. His code had a bug, one of those hard to grasp. His code worked well when testing under controlled conditions, but always failed when the concurrent reality was added into the mix.

Then something happened that made all those little talks to worth their while: I suggested him to look for shared state somewhere. He found the bug, and I could see right there, when he was telling me about his findings, that he finally understood the benefits of immutability.

 

 

Functions that return functions, how I reason about it

Since I started to learn and work with Scala and functional programming in general, there has been one thing I never really got my head around.

Why would I want to make a function that returns a function?

Funny enough I found the answer in a Clojure book[1]; I was reading a chapter about creating a minimalistic logging framework. I was assuming that all I was being told was old news, and then I got my enlightenment: it is awesome that functions can return functions.

Anyway, for those who haven’t got it yet, here is why you would want to have functions returning functions, the code is in Scala:

def optimist(a: Int, b: Int): Int = a + b
def pessimist(a: Int, b: Int): Int = a - b

def choose_operation(feeling_good: Boolean): (Int, Int) => Int =
 if (feeling_good) optimist else pessimist

val a = 2
val b = 1

val operation_good = choose_operation(feeling_good = true)
operation_good(a, b) == 3

val operation_bad = choose_operation(feeling_good = false)
operation_bad(a,b) == 1

So, a little detail about what just happened.

Our code has to possible operations: optimist, pessimist

They both take two integers as parameters, do something with them and return a result.

The function choose_operation, based on the parameter feeling_good, returns a function that takes two integers, do something with them and returns a result.

So, we evaluate choose_operation, and we use what ever it returns to calculate the result of a and b.

In this manner we can “configure” how certain operations are perform, based on some initial context. In other words, the fact that functions can return functions, is another way to get rid off the need of passing objects with some state in them.