Jayadeep Jayaraman
Jayadeep Jayaraman

Reputation: 2825

Scala Implicit conversion for Lambdas

I am trying to understand the implicit function types from the link - http://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html and below is a sample code as example. In the below code we first create a class Transaction.

class Transaction {
  private val log = scala.collection.mutable.ListBuffer.empty[String]
  def println(s: String): Unit = log += s

  private var aborted = false
  private var committed = false

  def abort(): Unit = { aborted = true }
  def isAborted = aborted

  def commit(): Unit =
  if (!aborted && !committed) {
     Console.println("******* log ********")
     log.foreach(Console.println)
     committed = true
  }
}

Next I define two methods f1 and f2 as shown below

def f1(x: Int)(implicit thisTransaction: Transaction): Int = {
  thisTransaction.println(s"first step: $x")
  f2(x + 1)
}
def f2(x: Int)(implicit thisTransaction: Transaction): Int = {
  thisTransaction.println(s"second step: $x")
  x
}

Then a method is defined to invoke the functions

def transaction[T](op: Transaction => T) = {
  val trans: Transaction = new Transaction
  op(trans)
  trans.commit()
}

Below lambda is used to invoke the code

transaction {
    implicit thisTransaction =>
      val res = f1(3)
      println(if (thisTransaction.isAborted) "aborted" else s"result: $res")
}  

My question is if I change the val trans: Transaction = new Transaction to implicit val thisTransaction = new Transaction and change op(trans) to op it is not working.

I am not able to understand why even if thisTransaction of type Transaction is present in the scope it is not being used?

Upvotes: 0

Views: 405

Answers (3)

Andrey Tyukin
Andrey Tyukin

Reputation: 44967

This here compiles just fine with dotty 0.4.0-RC1:

def transaction[T](op: implicit Transaction => T) = {
  implicit val trans: Transaction = new Transaction
  op
  trans.commit()
}

I think it should be clear from the introduction of the blog post that this is a new feature that Odersky invented to eliminate some boilerplate in the implementation of the Dotty compiler, quote:

For instance in the dotty compiler, almost every function takes an implicit context parameter which defines all elements relating to the current state of the compilation.

This seems to be currently not available in the mainstream versions of Scala.


EDIT

(answer to follow-up question in the comment)

If I understood the blog post correctly, it is desugared into something like

transaction(
  new ImplicitFunction1[Transaction, Unit] {
    def apply(implicit thisTransaction: Transaction): Unit = {
      val res = f1(args.length)(implicit thisTransaction:Transaction) 
      println(if (thisTransaction.isAborted) "aborted" else s"result: $res")
    }
  } 
)

the new ImplicitFunction1[...]{} is an anonymous local class. The base class ImplicitFunction1 is this new feature, which is similar to the Function for ordinary lambdas, but with implicit arguments.

Upvotes: 1

Alexey Romanov
Alexey Romanov

Reputation: 170899

Implicit function types are planned for a future version of Scala. As far as I know, not even the next version (2.13).

For now, you can only use them in Dotty.

Upvotes: 2

Steve Waldman
Steve Waldman

Reputation: 14083

op is of type Transaction => T, not (and I don't think is possible to specify this, unfortunately) implicit Transaction => T.

So its argument of type Transaction can't be supplied implicitly. It must be an explicit argument. (Only arguments to a function in an argument list marked implicit can be supplied implicitly.)

Upvotes: 1

Related Questions