I have the following pure function (f2 and f3 are pure too):
class X { def f1(arg: Type1): Type2 = { val x = f2(arg) val y = f3(x) y } def f2... def f3... }
Now, I would like to move f2 and f3 and can think of 2 options to do so. Wondering if one is more functional than the other?
Option 1
Move f2 and f3 to a new trait and mix the new trait into X like so:
trait T { def f2... // with implementation def f3... } class X extends T { def f1... // same implementation as earlier }
Option 2
Move f2 & f3 to a new trait (but with the implementation in a class) and dependency inject the trait into X like so:
@ImplementedBy(classOf[T1Impl]) trait T { def f2... // No implementation def f3... } @Singleton class TImpl extends T { override def f2... // Implementation here override def f3... } class X @Inject() (t: T) { def f1 ... = { val x = t.f2(arg) val y = t.f3(x) y } }
One half of me thinks option 1 is more functional (involving no OO baggage). The other half (with OOP/Java history I come from) screams that using inheritance for code sharing is a bad idea. Particularly if X and T are un-related then X extends T (X is a T) makes the code look contrived.
Using composition makes the code look more natural (X has a T) but is it less functional?