timvw
timvw

Reputation: 346

Scala: Composition with parameterless method

I am trying to use function composition, but I am not sure how to make this work with parameterless methods.

The following code functionally does what I need it to do:

import org.joda.time.DateTime

def buildWeekReport(forDay: DateTime, where: String) = {

  case class ReportPeriod(from: DateTime, to: DateTime)

  def calculateLastWeek(day: DateTime) = ReportPeriod(day.minus(7), day)

  def renderPeriod(period: ReportPeriod) = s" we pretend to store $period to $where"

  (calculateLastWeek _ andThen renderPeriod)(forDay)
}

Here is how I would like to express that functionality:

def buildWeekReport3(forDay: DateTime, where: String) = {

  case class ReportPeriod(from: DateTime, to: DateTime)

  def calculateLastWeek() = ReportPeriod(forDay.minus(7), forDay)

  def renderPeriod(period: ReportPeriod) = s" we pretend to store $period to $outputPath"

  calculateLastWeek _ andThen renderPeriod
}

buildWeekReport3(DateTime.now, "c:/temp")

Perhaps my question should be, why is there no andThen method defined on Function0?

As suggested, changing the signature to a Function1 (by using a unit: Unit parameter) seems like the least involved "fix".

Another, more involved workaround, would have been something such as:

case class MyFunction0[+R](val fn0: Function0[R]) {
  def andThen[A](g: (R) ⇒ A): () ⇒ A = () => g(fn0())
}

implicit def fn0ToMyFn0[R](fn0: Function0[R]) = new MyFunction0(fn0)

def buildWeekReport4(forDay: DateTime, where: String) = {

  case class ReportPeriod(from: DateTime, to: DateTime)

  def calculateLastWeek = ReportPeriod(forDay.minus(7), forDay)

  def renderPeriod(period: ReportPeriod) = s" we pretend to store $period to $where"


  (calculateLastWeek _ andThen renderPeriod)()
}

buildWeekReport4(DateTime.now, "c:/temp4") 

Upvotes: 1

Views: 213

Answers (3)

vvg
vvg

Reputation: 6385

andThen is the function that accepts two arguments of Function1 type, so you have to represent you functions as Function1

It can be done by redefining calculateLastWeek as

def calculateLastWeek = (z: Unit) => ReportPeriod(forDay.minus(7), forDay)

then you can write

  val x = calculateLastWeek andThen renderPeriod
  x()

Upvotes: 1

Pim Verkerk
Pim Verkerk

Reputation: 1066

Perhaps my question should be, why is there no andThen method defined on Function0?

andThen is only defined on Function1 because it uses the outcome of the first function as an argument to the second. If Function0 would have an andThen method the result of the first method would be lost.

Upvotes: 1

Jasper-M
Jasper-M

Reputation: 15086

Are you not just looking for renderPeriod(calculateLastWeek)? Unless this is for some kind of DSL.

Upvotes: 1

Related Questions