Felix Mulder
- 2004-01-20 by Martin Odersky
By-name Parameters
def foo(i: => Int): Int = {
if (true) 0
else i
}
Parameterless methods
def length: Int = ???
Always eta-expanded partially applied functions:
def map(f: Int => Int)(xs: Iterable[Int]) = ???
val square = map(x => x * x)
Surprising behaviour:
println("wat".length)
// res: <function>
()
if reference is to a nullary functionMissing parameters are specified with "_
"
val square = map(x => x * x)(_)
implicit, match, requires
private[X]
classOf[X]
protected[X]
unapply
private[this]
Early initialization
trait T { val x: Int; println(x) }
class C extends { val x = 5 } with T
new C // res: 5
@specialized
Adoption
- people asked for features
It was developed at a University
- PhD students wanted to see their work applied
$ brew install lampepfl/brew/dotty
$ sbt new lampepfl/dotty.g8
trait List[+A] {
def foldRight[B](z: B)(f: (A, B) => B): B = ???
}
List(1, 2, 3).foldRight(List.empty)(_ :: _) // scalac: nope
// dotty: yep
implicit A => B
sealed trait Exp[T]
final case class Add[T](t1: T, t2: T) extends Exp[T]
final case class Lit[T](i: Int) extends Exp[T]
implicit val evalInt: Eval[Int] = new Eval[Int] {
def apply(exp: Exp[Int])): Int = exp match {
case Add(t1, t2) => apply(t1) + apply(t2)
case Lit(const) => const
}
}
// 8 + (2 + 2 + 2)
def expr1[T](implicit eval: Eval[T]): T =
eval(Add(Lit(8), Add(Lit(2), Add(Lit(2), Lit(2)))))
sealed trait Exp[T]
final case class Add[T](t1: T, t2: T) extends Exp[T]
final case class Mul[T](i: Int) extends Exp[T]
final case class Lit[T](i: Int) extends Exp[T]
implicit val evalInt: Eval[Int] = new Eval[Int] {
def apply(exp: Exp[Int])): Int = exp match {
case Add(t1, t2) => apply(t1) + apply(t2)
case Mul(t1, t2) => apply(t1) * apply(t2)
case Lit(const) => const
}
}
// 8 + (2 + 2 + 2)
def expr1[T](implicit eval: Eval[T]): T =
eval(Add(Lit(8), Add(Lit(2), Add(Lit(2), Lit(2)))))
def expr2[T](implicit eval: Eval[T]): T =
eval(Add(Lit(8), Mul(Lit(2), Lit(3))))
trait Exp[T] {
def add(t1: T, t2: T): T
def lit(i: Int) = T
}
implicit val intExp: Exp[Int] = new Exp[Int] {
def add(t1: Int, t2: Int) = t1 + t2
def lit(i: Int) = i
}
// 8 + (2 + 2 + 2)
def expr1[T](implicit e: Exp[T]) =
e.add(e.lit(8), e.add(e.lit(2), e.add(e.lit(2), e.lit(2))))
object ExpSyntax {
def lit[T](i: Int)(implicit e: Exp[T]): T = e.lit(i)
def add[T](l: T, r: T)(implicit e: Exp[T]): T = e.add(l, r)
}
import ExpSyntax._
trait Exp[T] {
def add(t1: T, t2: T): T
def lit(i: Int) = T
}
implicit val intExp: Exp[Int] = new Exp[Int] {
def add(t1: Int, t2: Int) = t1 + t2
def lit(i: Int) = i
}
// 8 + (2 + 2 + 2)
def expr1[T: Exp] =
add(lit(8), add(lit(2), add(lit(2), lit(2))))
trait Mul[T] {
def mul(t1: T, t2: T): T
}
implicit val intMul: Mul[Int] = new Mul[Int] {
def mul(i1: Int, i2: Int) = i1 * i2
}
// 8 + 3 * 2
def expr2[T : Exp : Mul] =
add(lit(8), mul(lit(3), lit(2)))
type Ring[T] = implicit (Exp[T], Mul[T]) => T
// 8 + 3 * 2
def expr2: Ring[T] =
add(lit(8), mul(lit(3), lit(2)))
Revisiting Tagless Final Interpreters - Olivier Blanvillain