1

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?

  • 11
    What makes you think any of this code is functional? – Robert Harvey Jan 15 '18 at 4:05
  • 1
    Your question is about how to separate methods into classes or traits. I think this is unrelated to "functional" or not, so I would say all options are equally functional. Which option is best is a different question. – JacquesB Jan 15 '18 at 8:29
  • i'd suggest that the functional approach would probably involve passing f2 and f3 in as functions, but I think it will rather depend on what they all do. fir instance at the moment f1 = flip const - but i'm guessing your real f1 doesnt – jk. Jan 15 '18 at 9:09
  • actually misread it composes f2 and f3 but same point stands – jk. Jan 15 '18 at 9:28
  • 1
    might also like this blog.ploeh.dk/2017/01/27/… – jk. Jan 15 '18 at 9:29
6

Functional programming is about minimizing states and all that comes with that. Any and all information that would normally be provided by class members is instead provided through parameters.

It stands to reason that using classes in general is somewhat not functional as it allows you to have states. However, if you are avoiding class members, it makes no difference if you inherit or use traits as pure functions will continue to behave in the same way throughout the program.

In other words, the only reason you should think that you're moving away from a functional design is when the behavior of a function/method changes based on information which doesn't come from the parameters themselves or if the result of a given function/method cannot be unconditionally predetermined by the parameters passed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.