scala variables lazy-evaluation scala-2.10

¿Cómo se implementan las variables de clase valiosa perezosa en Scala 2.10?



lazy-evaluation scala-2.10 (2)

Actualización Scala 2.12.1 (diciembre de 2016, tres años después).

Después de PR 5294 (la fase de los campos expande completamente los módulos y valores perezosos) , puede leer en la confirmación 743f0d2 :

Lazy val sin local.

Ahora que se synchronized se borra especialmente para evitar el boxeo, podemos soltar ese problema.

Tenga en cuenta que esto agrega una llamada extra de conversión y conversión en la ruta lenta, pero eso probablemente no importa.

class C { def foo = {lazy val x = {println("a"); "A" }; x } }

se convierte en:

def foo(): String = { lazy <artifact> val x$lzy: scala.runtime.LazyRef[String] = new scala.runtime.LazyRef[String](); <artifact> private def x$lzycompute(): String = x$lzy.synchronized[String]{ if (x$lzy.initialized()) x$lzy.value() // NOTE: gets an `.asInstanceOf[String]` after erasure else { x$lzy.value_=({ scala.Predef.println("a"); "A" }); x$lzy.initialized_=(true); x$lzy.value() // NOTE: gets an `.asInstanceOf[String]` after erasure } } lazy def x(): String = if (x$lzy.initialized()) x$lzy.value() // NOTE: gets an `.asInstanceOf[String]` after erasure else x$lzycompute(); x() }

Esta respuesta a ¿Cuál es el costo (oculto) del valor perezoso de Scala? Muestra cómo se implementaron en Scala 2.7. Pero como dicen los comentarios, esto debe haber cambiado desde entonces, así que tengo curiosidad, ¿cuál es la implementación actual (2.10) de las variables de clase de lazy val ?


Compilado esto con scala 2.10.2:

class Foo { lazy val bar = math.pow(5, 3) }

Luego descompila el resultado con JD-GUI:

import scala.math.package.; import scala.reflect.ScalaSignature; @ScalaSignature(bytes="/006/001e1A!/001/002/001/013/t/031ai//8/013/003/r/tq/001P3naRLhh/001/001/024/005/0011/001CA/004/013/033/005A!/"A/005/002/013M/034/027/r//1/n/005-A!AB!osJ+g/rC/003/016/001/021/005a/"/001/004=S:LGO/020/013/002/037A/021/001/003A/007/002/005!A!/003/001EC/002/023/0051#A/002cCJ,/022/001/006/t/003/017UI!A/006/005/003/r/021{WO/0317f/021!A/002/001#A!B/023!/022/001/0022be/002/002") public class Foo { private double bar; private volatile boolean bitmap$0; private double bar$lzycompute() { synchronized (this) { if (!this.bitmap$0) { this.bar = package..MODULE$.pow(5.0D, 3.0D); this.bitmap$0 = true; } return this.bar; } } public double bar() { return this.bitmap$0 ? this.bar : bar$lzycompute(); } }

Editar - Esto es lo que parece para tres campos:

class Foo { lazy val a = math.pow(5, 1) lazy val b = math.pow(5, 2) lazy val c = math.pow(5, 3) }

Descompilado

import scala.math.package.; import scala.reflect.ScalaSignature; @ScalaSignature(bytes="/006/001/0052A!/001/002/001/013/t/031ai//8/013/003/r/tq/001P3naRLhh/001/001/024/005/0011/001CA/004/013/033/005A!/"A/005/002/013M/034/027/r//1/n/005-A!AB!osJ+g/rC/003/016/001/021/005a/"/001/004=S:LGO/020/013/002/037A/021/001/003A/007/002/005!A!/003/001EC/002/023/0051#A/001b+/005!/002CA/004/026/023/t1/002B/001/004E_V/024G./032/005/t1/001A/t/021)Q/005)/005/021/021/r/t/005/t5/001A)/031!C/001''/005/t!/r/003/005/035/001!/005/t/025)/003/025/003/t/021/007/005/003/005/037/001!/025/r/021/"/001/024/003/005/031/007/002/003/021/001/021/003/005/013/025/002/013/002/005/r/004/003") public class Foo { private double a; private double b; private double c; private volatile byte bitmap$0; private double a$lzycompute() { synchronized (this) { if ((byte)(this.bitmap$0 & 0x1) == 0) { this.a = package..MODULE$.pow(5.0D, 1.0D); this.bitmap$0 = ((byte)(this.bitmap$0 | 0x1)); } return this.a; } } private double b$lzycompute() { synchronized (this) { if ((byte)(this.bitmap$0 & 0x2) == 0) { this.b = package..MODULE$.pow(5.0D, 2.0D); this.bitmap$0 = ((byte)(this.bitmap$0 | 0x2)); } return this.b; } } private double c$lzycompute() { synchronized (this) { if ((byte)(this.bitmap$0 & 0x4) == 0) { this.c = package..MODULE$.pow(5.0D, 3.0D); this.bitmap$0 = ((byte)(this.bitmap$0 | 0x4)); } return this.c; } } public double a() { return (byte)(this.bitmap$0 & 0x1) == 0 ? a$lzycompute() : this.a; } public double b() { return (byte)(this.bitmap$0 & 0x2) == 0 ? b$lzycompute() : this.b; } public double c() { return (byte)(this.bitmap$0 & 0x4) == 0 ? c$lzycompute() : this.c; } }