Skip to content

Instantly share code, notes, and snippets.

@arnolddevos
Last active November 11, 2017 19:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arnolddevos/6a00fd0a9e096eeead94eb6931f27718 to your computer and use it in GitHub Desktop.
Save arnolddevos/6a00fd0a9e096eeead94eb6931f27718 to your computer and use it in GitHub Desktop.
Implicit Functions Example in plain scala 2.12
import scala.collection.mutable.ListBuffer
object implicex {
trait ImplicitFunction1[-A, +B] {
def apply()(implicit a: A): B
}
def fn[A, B](f: A => B): ImplicitFunction1[A, B] = new ImplicitFunction1[A, B] {
def apply()(implicit a: A): B = f(a)
}
class Transaction {
private val log = new ListBuffer[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
}
}
type Transactional[T] = ImplicitFunction1[Transaction, T]
def f1(x: Int): Transactional[Int] = fn { implicit thisTransaction =>
thisTransaction.println(s"first step: $x")
f2(x + 1)()
}
def f2(x: Int): Transactional[Int] = fn { implicit thisTransaction =>
thisTransaction.println(s"second step: $x")
f3(x * x)()
}
def f3(x: Int): Transactional[Int] = fn { implicit thisTransaction =>
thisTransaction.println(s"third step: $x")
if (x % 2 != 0) thisTransaction.abort()
x
}
def transaction[T](op: Transactional[T]) = {
implicit val trans: Transaction = new Transaction
op()
trans.commit()
}
def main(args: Array[String]) = {
transaction {
fn { implicit thisTransaction =>
val res = f1(args.length)()
println(if (thisTransaction.isAborted) "aborted" else s"result: $res")
}
}
}
}
// from Martin's implicit function post:
def thisTransaction: Transactional[Transaction] = implicitly[Transaction]
def f1(x: Int): Transactional[Int] = {
thisTransaction.println(s"first step: $x")
f2(x + 1)
}
def f2(x: Int): Transactional[Int] = {
thisTransaction.println(s"second step: $x")
f3(x * x)
}
def f3(x: Int): Transactional[Int] = {
thisTransaction.println(s"third step: $x")
if (x % 2 != 0) thisTransaction.abort()
x
}
@arnolddevos
Copy link
Author

This is Martin Odersky's implicit functions example [1] rewritten in plain scala without the implicit function support. This is just for exploration and illustration. Compare the Transactionals f1, f2, and f3 here to Martin's example and you can see the they have extra boilerplate on definition implicit thisTransaction => and on invocation there is an extra operator () .

There is a parallel here to the Reader monad. I like this post about Reader [2] by Jason Arhart because he follows the same path as Martin, beginning with a solution using just implicit parameters and trying to improve on it.

[1] http://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html
[2] http://blog.originate.com/blog/2013/10/21/reader-monad-for-dependency-injection/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment