alias blame-lines="git ls-tree -r -z --name-only HEAD -- | egrep -z -Z -E '\.(scala)$'\
| xargs -0 -n1 git blame --line-porcelain | grep "^author "| sort | uniq -c | sort -nr"
author | commits | additions | deletions | blame lines |
Martin Odersky | 2,280 | 146,133 | 85,391 | 66,698 |
Dmitry Petrashko | 628 | 158,249 | 50,201 | 83,713 |
Samuel Gruetter | 19 | 62,324 | 12,510 | 36,615 |
Others | 144 | 5,315 | 2,108 | 4,161 |
Only classes have initialization statements.
They get executed in the order they are written.
object helper {
def init(name: String) = {println(name)}
}
import helper._
class A {
val a = {init("A.a"); 1}
}
class B extends A {
val b = {init("B.b"); 1}
}
A.a
B.b
Multiple inheritance of initialization code.
Order of execution matters
trait A {
val a = { init("A.a"); 1}
}
trait B {
val b = { init("B.b"); 2}
}
class AB extends A with B {}
A.a
B.b
trait A {
val a = { init("A.a"); 1}
}
trait B {
val b = { init("B.b"); 2}
}
class AB extends B with A {}
B.b
A.b
trait A {
val a = { init("A.a"); 1}
}
trait B extends A {
val b = { init("B.b"); 2}
}
class AB extends A with B {}
A.a
B.b
trait A {
val a = { init("A.a"); 1}
}
trait B extends A {
val b = { init("B.b"); 2}
}
class AB extends B with A {}
A.a
B.b
trait A {
val a = { init("A.a"); 1}
}
trait B extends A {
println(a + " " + b)
val b = { init("B.b"); 2}
}
class AB extends B with A {}
A.a
1 0
B.b
trait A {
val a = { init("A.a"); 1}
}
trait B extends A {
val b = { init("B.b"); 2}
println(a + " " + b)
}
class AB extends B with A {}
A.a
B.b
1 2
trait A {
val a = { init("A.a"); 1}
}
trait B extends A{
val b = { init("B.b"); 2}
println(a + " " + b)
}
class AB extends B {
override val b = {init("AB.b"); 3}
}
A.a
B.b
1 0
AB.b
trait A {
val a = { init("A.a"); 1}
}
trait B extends A{
val b = { init("B.b"); 2}
println(a + " " + b)
}
class AB extends B {
override final val b = 3
}
A.a
B.b
1 3
val s = 1
is desugared into
private val s$private = 1
def s = s$private
trait A {
<statements1>
val field1 = <expr1>
<statements2>
val field2 = <expr2>
....
}
is transformed into
intefrace A {
final val field1
final val field2
def <init> = {
<statements1>
field1 = <expr1>
<statements2>
field2 = <expr2>
...
}
}
intefrace A {
def A$field1$setter(value)
def A$field2$setter(value)
def <init> = {
<statements1>
A$field1$setter(<expr1>)
<statements2>
A$field2$setter(<expr2>)
...
}
}
class Implementation extends A {
private A$field1 = _
def A$field1_setter(value) = {A$field1 = value}
private A$field2 = _
def A$field2_setter(value) = {A$field2 = value}
def <init> = {
super[A].<init>
}
}
intefrace A {
def A$field1$initial = {
<statements1>
<expr1>
}
def A$field2$initial = {
<statements2>
<expr2>
}
}
class Implementation extends A {
private final A$field1 = _
private final A$field2 = _
def <init> = {
A$field1 = A$field1$initial
A$field2 = A$field2$initial
}
}
trait A {
val a = { init("A.a"); 1}
}
trait B extends A {
val b = { init("B.b"); 2}
println(a + " " + b)
}
class AB extends B with A {}
A.a
B.b
1 2
trait A {
val a = { init("A.a"); 1}
}
trait B extends A {
println(a + " " + b)
val b = { init("B.b"); 2}
}
class AB extends B with A {}
A.a
1 0
B.b
trait A {
val a = { init("A.a"); 1}
}
trait B extends A{
val b = { init("B.b"); 2}
println(a + " " + b)
}
class AB extends B {
override val b = {init("AB.b"); 3}
}
A.a
B.b
1 0
AB.b
trait A {
val a = { init("A.a"); 1}
}
trait B extends A{
val b = { init("B.b"); 2}
println(a + " " + b)
}
class AB extends B {
override final val b = 3
}
A.a
B.b
1 3
trait Greeting {
val name: String
val msg = "How are you, " + name
}
class C extends Greeting {
lazy val name = "Bob"
println(msg)
}
Initialization on demand.
Every access needs to pay a price: synchronize and check that field is initialized.
May cause deadlocks. For details, see my ScalaWorld2015 presentation.
Lazy vals do not cause spurious deadlocks.
Has both thread-safe and thread-unsafe lazy vals.
On JVM, before calling superconstructor the only thing you can do is to assign&read fields.
trait Greeting {
val name: String
val msg = "How are you, " + name
}
class C extends {
val name = "Bob"
} with Greeting {
println(msg)
}
Spec says: Early definitions are particularly useful for traits, which do not have normal constructor parameters.
trait Greeting(val name: String) {
val msg = "How are you, " + name
}
class C extends Greeting("Bob") {
println(msg)
}
Make val fields behave as if they were lazy during constructor only.