Skip to content

Instantly share code, notes, and snippets.

@tkellogg
Created April 17, 2016 10:14
Show Gist options
  • Save tkellogg/59d29579e33f30b42092f7855f3e1e65 to your computer and use it in GitHub Desktop.
Save tkellogg/59d29579e33f30b42092f7855f3e1e65 to your computer and use it in GitHub Desktop.
Scala's lazy val is not thread safe. See line 65, I don't see anything related to synchronization.
~> scala
Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_66).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class Foo { lazy val bar = 2 }
defined class Foo
scala> :javap Foo
Size 831 bytes
MD5 checksum 14727318592c9c4a86120db0d8e942af
Compiled from "<console>"
public class Foo
minor version: 0
major version: 50
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Utf8 Foo
#2 = Class #1 // Foo
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 <console>
#6 = Utf8 bar
#7 = Utf8 I
#8 = Utf8 bitmap$0
#9 = Utf8 Z
#10 = Utf8 bar$lzycompute
#11 = Utf8 ()I
#12 = NameAndType #8:#9 // bitmap$0:Z
#13 = Fieldref #2.#12 // Foo.bitmap$0:Z
#14 = NameAndType #6:#7 // bar:I
#15 = Fieldref #2.#14 // Foo.bar:I
#16 = Utf8 scala/runtime/BoxedUnit
#17 = Class #16 // scala/runtime/BoxedUnit
#18 = Utf8 UNIT
#19 = Utf8 Lscala/runtime/BoxedUnit;
#20 = NameAndType #18:#19 // UNIT:Lscala/runtime/BoxedUnit;
#21 = Fieldref #17.#20 // scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
#22 = Utf8 this
#23 = Utf8 LFoo;
#24 = Utf8 java/lang/Throwable
#25 = Class #24 // java/lang/Throwable
#26 = NameAndType #10:#11 // bar$lzycompute:()I
#27 = Methodref #2.#26 // Foo.bar$lzycompute:()I
#28 = Utf8 <init>
#29 = Utf8 ()V
#30 = NameAndType #28:#29 // "<init>":()V
#31 = Methodref #4.#30 // java/lang/Object."<init>":()V
#32 = Utf8
#33 = Class #32 //
#34 = Utf8 $line3/$read
#35 = Class #34 // $line3/$read
#36 = Utf8
#37 = Utf8
#38 = Class #37 //
#39 = Utf8 Foo
#40 = Utf8 Code
#41 = Utf8 LocalVariableTable
#42 = Utf8 LineNumberTable
#43 = Utf8 StackMapTable
#44 = Utf8 SourceFile
#45 = Utf8 InnerClasses
#46 = Utf8 Scala
{
public int bar();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #13 // Field bitmap$0:Z
4: ifeq 14
7: aload_0
8: getfield #15 // Field bar:I
11: goto 18
14: aload_0
15: invokespecial #27 // Method bar$lzycompute:()I
18: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 19 0 this LFoo;
LineNumberTable:
line 7: 0
StackMapTable: number_of_entries = 2
frame_type = 14 /* same */
frame_type = 67 /* same_locals_1_stack_item */
stack = [ int ]
public Foo();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #31 // Method java/lang/Object."<init>":()V
4: return
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LFoo;
LineNumberTable:
line 11: 0
}
SourceFile: "<console>"
InnerClasses:
public static #36= #33 of #35; //=class of class $line3/$read
public static #36= #38 of #33; //=class of class
public static #39= #2 of #38; //Foo=class Foo of class
Error: unknown attribute
Scala: length = 0x0
@runarorama
Copy link

class Something {
  lazy val foo = getFoo
  def getFoo = "foo!"
}

Using procyon-decompiler, this produces the following:

import scala.reflect.*;
import scala.runtime.*;

//
// Decompiled by Procyon v0.5.30
//

@ScalaSignature(bytes = "\u0006\u0001\u00012A!\u0001\u0002\u0001\u000b\tI1k\\7fi\"Lgn\u001a\u0006\u0002\u0007\u00059A(Z7qift4\u0001A\n\u0003\u0001\u0019\u0001\"a\u0002\u0006\u000e\u0003!Q\u0011!C\u0001\u0006g\u000e\fG.Y\u0005\u0003\u0017!\u0011a!\u00118z%\u00164\u0007\"B\u0007\u0001\t\u0003q\u0011A\u0002\u001fj]&$h\bF\u0001\u0010!\t\u0001\u0002!D\u0001\u0003\u0011!\u0011\u0002\u0001#b\u0001\n\u0003\u0019\u0012a\u00014p_V\tA\u0003\u0005\u0002\u001655\taC\u0003\u0002\u00181\u0005!A.\u00198h\u0015\u0005I\u0012\u0001\u00026bm\u0006L!a\u0007\f\u0003\rM#(/\u001b8h\u0011!i\u0002\u0001#A!B\u0013!\u0012\u0001\u00024p_\u0002BQa\b\u0001\u0005\u0002M\taaZ3u\r>|\u0007")
public class Something
{
    private String foo;
    private volatile boolean bitmap$0;

    private String foo$lzycompute() {
        synchronized (this) {
            if (!this.bitmap$0) {
                this.foo = this.getFoo();
                this.bitmap$0 = true;
            }
            final BoxedUnit unit = BoxedUnit.UNIT;
            return this.foo;
        }
    }

    public String foo() {
        return this.bitmap$0 ? this.foo : this.foo$lzycompute();
    }

    public String getFoo() {
        return "foo!";
    }
}

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