A scala macro for reasonable lazy semantics
Scala
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
macros/src/main/scala Merge branch 'master' of https://github.com/runarorama/lazifed Apr 17, 2016
project
tests/src/main/scala
.gitignore
.travis.yml
LICENSE
README.md
build.sbt

README.md

Latr

A scala macro for reasonable lazy semantics.

This library provides three annotation macros:

@lazify: Rewrites a def or val so that its evaluation is delayed and memoized. Does not synchronize or attempt to share the memo between threads. If two threads call the unevaluated expression at the same time, the evaluation will happen twice.

@lazifyPessimistic: Rewrites a def or val to something similar to a lazy val, except instead of locking the whole object while evaluating, it locks only while checking if evaluation has already happened. Essentially implements SIP-20 Version V2. Performs best if the expected thread contention is low.

@lazifyOptimistic: Rewrites a def or val to an atomic memory cell that uses compare-and-swap to share the memo among multiple threads. Performs better than the pessimistic version when contention is high, but worse when contention is low. Essentially implements SIP-20 Version V4.

Setup

Latr requires the macro paradise compiler plugin. Follow the instructions there to set up the plugin. If you're using SBT, you should just need a line like this in your build.sbt:

addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)

If you're using SBT 0.13.6 or better, you can get Latr from Bintray thusly:

resolvers += Resolver.bintrayRepo("runarorama", "maven")

libraryDependencies += "com.higher-order" %% "latr" % "0.3.0"

With older versions of SBT you'll need this instead:

resolvers += Resolver.url("runarorama bintray", url("http://dl.bintray.com/runarorama/maven"))

Usage

Wherever you would otherwise say something like this in Scala:

lazy val x: Int = {
  println("I will only print once and block the world while doing it!")
  10
}

You can instead say:

import latr._

@lazify val x: Int = {
  println("I may print multiple times under thread contention, but I'm super cheap!")
  10
}

Or:

@lazifyOptimistic val x: Int = {
  println("I will only print once, using fancy atomic stuff!")
  10
}

Or:

@lazifyPessimistic val x: Int = {
  println("I will only print once, using good old-fashioned synchronized blocks!")
  10
}