Skip to content

Instantly share code, notes, and snippets.

@densh
Last active October 18, 2020 17:02
Show Gist options
  • Save densh/75d2d3063571d89ee34e161b4a61c74a to your computer and use it in GitHub Desktop.
Save densh/75d2d3063571d89ee34e161b4a61c74a to your computer and use it in GitHub Desktop.
Scoped Implicit Lifetimes

Scoped Implicit Lifetimes

All things considered, our experience in Scala Native has shown that resource management in Scala is way harder than it should be. This gist presents a simple design pattern that makes it resource management absolutely hassle-free: scoped implicit lifetimes.

The main idea behind it is to encode resource lifetimes through a concept of an implicit scope. Scopes are necessary to acquire resources. They are responsible for disposal of the resources once the evaluation exits the demarkated block in the source code.

Use cases

  • File handles
  • Network connections
  • Locks
  • Off-heap memory allocations
  • Thread pools
  • Actor systems
  • OpenGL Contexts
  • ...
import java.io.Closeable
import Resourceful._
object Resourceful {
type Resource = AutoCloseable
@annotation.implicitNotFound(msg = "Resource acquisition requires a scope.")
final class Scope extends Resource {
private[this] var resources: List[Resource] = Nil
final def acquire(res: Resource): Unit = {
resources ::= res
}
final def close(): Unit = resources match {
case Nil =>
()
case first :: rest =>
resources = rest
try first.close()
finally close()
}
}
object Scope {
def apply[T](f: Scope => T): T = {
val scope = new Scope
try f(scope)
finally scope.close()
}
}
def acquire[R <: Resource](res: R)(implicit in: Scope): R = {
in.acquire(res)
res
}
}
class SafeWriter(path: String)(implicit in: Scope) extends Resource {
acquire(this)
println(s"acquired $path")
private val writer = new java.io.PrintWriter(path)
def write(value: String) = writer.write(value)
def close(): Unit = { println(s"releasing $path"); writer.close() }
}
object MyApp extends App {
Scope { implicit in =>
val w1 = new SafeWriter("file1.txt")
w1.write("hello, world!")
val w2 = new SafeWriter("file2.txt")
w2.write("hello, world!")
}
}
@SethTisue
Copy link

anyone interested in this will likely also be interested in
https://github.com/scala/scala/blob/2.13.x/src/library/scala/util/Using.scala

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