Last active
November 11, 2017 19:45
-
-
Save arnolddevos/6a00fd0a9e096eeead94eb6931f27718 to your computer and use it in GitHub Desktop.
Implicit Functions Example in plain scala 2.12
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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/