Wai Yip Tung - 1 year ago 69
Scala Question

Idiomatic way to perform a conditional transformation

I have an object

`x`
. I am going to perform a series of transformation on it. This can easily be expressed as

``````x.transformA.transformB.transformC
``````

However, before each transformation, I should also check for a condition. Only if the condition is true should I perform the transformation. I have two way to express this. The first is to define x as a var.

``````var x = anObject
if (x.condA) x = x.transformA
if (x.condB) x = x.transformB
if (x.condC) x = x.transformC
// final result in x
``````

Alternatively, to avoid var, I define a series of intermediate variables

``````val x0 = anObject
val x1 = if (x0.condA) x0.transformA else x0
val x2 = if (x1.condB) x1.transformB else x1
val x3 = if (x2.condC) x2.transformC else x2
// final result in x3
``````

This seems to be quite cumbersome, even error prone when I cut and paste the lines. Is there a more idiomatic way to express this?

It's possible to express a series of conditional transformations as a composition of `Function`s. That way each transformation can be declared independently, and reused to build new tranformations.

As an example:

``````val ta: MyClass => MyClass = {case x if x.condA => x.transformA
case x => x}
val tb: MyClass => MyClass = {case x if x.condB => x.transformB
case x => x}
val tc: MyClass => MyClass = {case x if x.condC => x.transformC
case x => x}
``````

Then we can compose those to form our transformation:

``````val transformation = ta andThen tb andThen tc
val transformedObj =  transformation(x)
``````

We can see above that we are repeating the same pattern over and over again. To avoid that, we could make a function that creates our partial functions, reducing the boilerplate code:

``````def mkTf[T](cond: T => Boolean, transf: T => T): T => T = {
case x if cond(x) => transf(x)
case x => x
}
``````

Then we can rewrite our composition as:

``````val transformation = mkTf[MyClass](_.condA,_.transformA) andThen
mkTf[MyClass](_.condB,_.transformB) andThen
mkTf[MyClass](_.condC,_.transformC)
``````
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download