Skip to content

Instantly share code, notes, and snippets.

@cb372
Last active February 18, 2022 13:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cb372/dc0753567ae53f49d78d2e34fe25ea75 to your computer and use it in GitHub Desktop.
Save cb372/dc0753567ae53f49d78d2e34fe25ea75 to your computer and use it in GitHub Desktop.
Explaining default args using javap
import java.time.Instant
object Foo {
case class Timers(
timer1: Long,
timer2: Long = Instant.now().toEpochMilli,
timer3: Long
)
val a = Timers(
timer1 = Instant.now().toEpochMilli,
timer3 = Instant.now().toEpochMilli
)
}
$ javap -c 'Foo$.class'
Compiled from "Foo.scala"
public final class Foo$ {
public static final Foo$ MODULE$;
public static {};
Code:
0: new #2 // class Foo$
3: dup
4: invokespecial #22 // Method "<init>":()V
7: putstatic #24 // Field MODULE$:LFoo$;
10: invokestatic #30 // Method java/time/Instant.now:()Ljava/time/Instant;
13: invokevirtual #34 // Method java/time/Instant.toEpochMilli:()J
16: lstore_0
17: invokestatic #30 // Method java/time/Instant.now:()Ljava/time/Instant;
20: invokevirtual #34 // Method java/time/Instant.toEpochMilli:()J
23: lstore_2
24: getstatic #37 // Field Foo$Timers$.MODULE$:LFoo$Timers$;
27: invokevirtual #40 // Method Foo$Timers$.apply$default$2:()J
30: lstore 4
32: new #7 // class Foo$Timers
35: dup
36: lload_0
37: lload 4
39: lload_2
40: invokespecial #43 // Method Foo$Timers."<init>":(JJJ)V
43: putstatic #45 // Field a:LFoo$Timers;
46: return
public Foo$Timers a();
Code:
0: getstatic #45 // Field a:LFoo$Timers;
3: areturn
}
$ javap -c 'Foo$Timers$.class'
Compiled from "Foo.scala"
public class Foo$Timers$ extends scala.runtime.AbstractFunction3<java.lang.Object, java.lang.Object, java.lang.Object, Foo$Timers> implements java.io.Serializable {
public static final Foo$Timers$ MODULE$;
...
public long apply$default$2();
Code:
0: invokestatic #31 // Method java/time/Instant.now:()Ljava/time/Instant;
3: invokevirtual #34 // Method java/time/Instant.toEpochMilli:()J
6: lreturn
...
}
@cb372
Copy link
Author

cb372 commented Feb 18, 2022

val a is initialized when the Foo$ class is loaded, in the public static {} method. This method does the following:

  1. (invokestatic + invokevirtual) call Instant.now().toEpochMilli
  2. (lstore_0) save the resulting long to local variable 0 (it will use it later as the first argument to the Timers constructor)
  3. (invokestatic + invokevirtual) call Instant.now().toEpochMilli again
  4. (lstore_2) save the result to local variable 2 (it will use it later as the third argument to the constructor)
  5. (getstatic + invokevirtual) call Foo$Timers$.apply$default$2 (which in turn calls Instant.now().toEpochMilli and returns the result)
  6. (lstore 4) save the result to local variable 4 (it will use it later as the second argument to the constructor)
  7. (new + dup) create a new (uninitialized) Timers instance
  8. (lload_0) push local variable 0 onto the stack for use as the first argument to the Timers constructor
  9. (lload 4) push local variable 4 onto the stack for use as the second argument
  10. (lload_2) push local variable 2 onto the stack for use as the third argument
  11. (invokespecial) call the Timers constructor, which pops the 3 args off the stack
  12. (putstatic) save the Timers instance to the field a

So in summary, Instant.now.toEpochMilli is called 3 times, once for each constructor arg, so the values could all be different.

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