Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin: Uncovered - November 2017

Kotlin: Uncovered - November 2017

Kotlin does a lot for us in the way of reducing boilerplate. But what is it really doing? We will be inspecting some decompiled Kotlin to discover how it does its job. By looking underneath at how it handles data classes, lambdas, and delegation, we can better understand how the language executes what we write. If you’re curious about the language, or already using it in production, you should walk away from this investigation with a deeper understanding of Kotlin, and some tools for continued exploration.

Victoria Gonda

November 06, 2017
Tweet

More Decks by Victoria Gonda

Other Decks in Programming

Transcript

  1. collectiveidea.com @TTGonda Menu > Tools > Kotlin > Show Kotlin

    Bytecode or CMD+SHFT+A and search “Show Kotlin Bytecode”
  2. collectiveidea.com @TTGonda package com.victoriagonda.v2; import kotlin.Metadata; import kotlin.jvm.internal.Intrinsics; import org.jetbrains.annotations.NotNull;

    import org.jetbrains.annotations.Nullable; @Metadata( mv = {1, 1, 7}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0002\b\b\u0018\u00002\u00020\u0001B\u0017\u0012\ u0006\u0010\u0002\u001a\u00020\u0003\u0012\b\u0010\u0004\u001a\u0004\u0018\u00010\u0003¢ \u0006\u0002\u0010\u0005R\u0011\u0010\u0002\u001a\u00020\u0003¢ \u0006\b\n\u0000\u001a\u0004\b\u0006\u0010\u0007R\u001c\u0010\u0004\u001a\u0004\u0018\u00010\u0003X\u0086\u000e¢ \u0006\u000e\n\u0000\u001a\u0004\b\b\u0010\u0007\"\u0004\b\t\u0010\n¨\u0006\u000b"}, d2 = {"Lcom/victoriagonda/v2/Cupcake;", "", "flavor", "", "icing", "(Ljava/lang/String;Ljava/lang/String;)V", "getFlavor", "()Ljava/lang/String;", "getIcing", "setIcing", "(Ljava/lang/String;)V", "production sources for module app"} ) public final class Cupcake { @NotNull private final String flavor; @Nullable private String icing; @NotNull public final String getFlavor() { return this.flavor; } @Nullable public final String getIcing() { return this.icing; } public final void setIcing(@Nullable String var1) { this.icing = var1; } public Cupcake(@NotNull String flavor, @Nullable String icing) { Intrinsics.checkParameterIsNotNull(flavor, "flavor"); super(); this.flavor = flavor; this.icing = icing;
  3. collectiveidea.com @TTGonda public final class Cupcake { @NotNull private final

    String flavor; @Nullable private String icing; @NotNull public final String getFlavor() { return this.flavor; } @Nullable public final String getIcing() { return this.icing; } public final void setIcing(@Nullable String var1) { this.icing = var1; } public Cupcake(@NotNull String flavor, @Nullable String icing) { Intrinsics.checkParameterIsNotNull(flavor, "flavor"); super(); this.flavor = flavor; this.icing = icing; } }
  4. collectiveidea.com @TTGonda public final class Cupcake { @NotNull private final

    String flavor; @Nullable private String icing; @NotNull public final String getFlavor() { return this.flavor; } @Nullable public final String getIcing() { return this.icing; } public final void setIcing(@Nullable String var1) { this.icing = var1; } public Cupcake(@NotNull String flavor, @Nullable String icing) { Intrinsics.checkParameterIsNotNull(flavor, "flavor");
  5. collectiveidea.com @TTGonda public final class Cupcake { @NotNull private final

    String flavor; @Nullable private String icing; @NotNull public final String getFlavor() { return this.flavor; } @Nullable public final String getIcing() { return this.icing; } public final void setIcing(@Nullable String var1) { this.icing = var1; } public Cupcake(@NotNull String flavor, @Nullable String icing) { Intrinsics.checkParameterIsNotNull(flavor, "flavor");
  6. collectiveidea.com @TTGonda public final class Cupcake { @NotNull private final

    String flavor; @Nullable private String icing; @NotNull public final String getFlavor() { return this.flavor; } @Nullable public final String getIcing() { return this.icing; } public final void setIcing(@Nullable String var1) { this.icing = var1; } public Cupcake(@NotNull String flavor, @Nullable String icing) { Intrinsics.checkParameterIsNotNull(flavor, "flavor");
  7. collectiveidea.com @TTGonda private String icing; @NotNull public final String getFlavor()

    { return this.flavor; } @Nullable public final String getIcing() { return this.icing; } public final void setIcing(@Nullable String var1) { this.icing = var1; } public Cupcake(@NotNull String flavor, @Nullable String icing) { Intrinsics.checkParameterIsNotNull(flavor, "flavor"); super(); this.flavor = flavor; this.icing = icing; } }
  8. collectiveidea.com @TTGonda public final class Cupcake { @NotNull private final

    String flavor; @Nullable private String icing; @NotNull public final String getFlavor() { return this.flavor; } @Nullable public final String getIcing() { return this.icing; } public final void setIcing(@Nullable String var1) { this.icing = var1; } public Cupcake(@NotNull String flavor, @Nullable String icing) { Intrinsics.checkParameterIsNotNull(flavor, "flavor"); super(); this.flavor = flavor; this.icing = icing; } @NotNull public final String component1() { return this.flavor; } @Nullable public final String component2() { return this.icing; } @NotNull public final Cupcake copy(@NotNull String flavor, @Nullable String icing) { Intrinsics.checkParameterIsNotNull(flavor, "flavor"); return new Cupcake(flavor, icing); } // $FF: synthetic method // $FF: bridge method @NotNull public static Cupcake copy$default(Cupcake var0, String var1, String var2, int var3, Object var4) { if((var3 & 1) != 0) { var1 = var0.flavor; } if((var3 & 2) != 0) { var2 = var0.icing; } return var0.copy(var1, var2); } public String toString() { return "Cupcake(flavor=" + this.flavor + ", icing=" + this.icing + ")"; } public int hashCode() { return (this.flavor != null?this.flavor.hashCode():0) * 31 + (this.icing != null?this.icing.hashCode():0); } public boolean equals(Object var1) { if(this != var1) { if(var1 instanceof Cupcake) { Cupcake var2 = (Cupcake)var1; if(Intrinsics.areEqual(this.flavor, var2.flavor) && Intrinsics.areEqual(this.icing, var2.icing)) { return true; } } return false; } else { return true; } } }
  9. collectiveidea.com @TTGonda @NotNull public final String component1() { return this.flavor;

    } @Nullable public final String component2() { return this.icing; } @NotNull public final Cupcake copy( @NotNull String flavor, @Nullable String icing) { Intrinsics.checkParameterIsNotNull(flavor, "flavor"); return new Cupcake(flavor, icing); } // $FF: synthetic method // $FF: bridge method @NotNull public static Cupcake copy$default( Cupcake var0, String var1, String var2, int var3, Object var4) { if((var3 & 1) != 0) { var1 = var0.flavor; }
  10. collectiveidea.com @TTGonda @NotNull public final Cupcake copy( @NotNull String flavor,

    @Nullable String icing) { Intrinsics.checkParameterIsNotNull(flavor, "flavor"); return new Cupcake(flavor, icing); } // $FF: synthetic method // $FF: bridge method @NotNull public static Cupcake copy$default( Cupcake var0, String var1, String var2, int var3, Object var4) { if((var3 & 1) != 0) { var1 = var0.flavor; } if((var3 & 2) != 0) { var2 = var0.icing; } return var0.copy(var1, var2); } public String toString() { return "Cupcake(flavor=" +
  11. collectiveidea.com @TTGonda val cupcake = Cupcake("Chocolate", "Peanut Butter”)
 val copy

    = cupcake.copy()
 val noIcing = cupcake.copy(icing = null)
 val vanilla = cupcake.copy(flavor = “Vanilla")
 val banana = cupcake.copy(
 flavor = "Banana", 
 icing = "Chocolate")
  12. collectiveidea.com @TTGonda @NotNull public static Cupcake copy$default( Cupcake var0, String

    var1, String var2, int var3, Object var4) { if((var3 & 1) != 0) { var1 = var0.flavor; } if((var3 & 2) != 0) { var2 = var0.icing; } return var0.copy(var1, var2); } public String toString() { return "Cupcake(flavor=" + this.flavor + ", icing=" + this.icing + ")"; } public int hashCode() { return (this.flavor != null?this.flavor.hashCode():0) * 31 + (this.icing != null?this.icing.hashCode():0); }
  13. collectiveidea.com @TTGonda ")"; } public int hashCode() { return (this.flavor

    != null?this.flavor.hashCode():0) * 31 + (this.icing != null?this.icing.hashCode():0); } public boolean equals(Object var1) { if(this != var1) { if(var1 instanceof Cupcake) { Cupcake var2 = (Cupcake)var1; if(Intrinsics.areEqual(this.flavor, var2.flavor) && Intrinsics.areEqual(this.icing, var2.icing)) { return true; } } return false; } else { return true; } } }
  14. collectiveidea.com @TTGonda public final class Cupcake { @NotNull private final

    String flavor; @Nullable private String icing; @NotNull public final String getFlavor() { return this.flavor; } @Nullable public final String getIcing() { return this.icing; } public final void setIcing(@Nullable String var1) { this.icing = var1; } public Cupcake(@NotNull String flavor, @Nullable String icing) { Intrinsics.checkParameterIsNotNull(flavor, "flavor"); super(); this.flavor = flavor; this.icing = icing; } @NotNull public final String component1() { return this.flavor; } @Nullable public final String component2() { return this.icing; } @NotNull public final Cupcake copy(@NotNull String flavor, @Nullable String icing) { Intrinsics.checkParameterIsNotNull(flavor, "flavor"); return new Cupcake(flavor, icing); } // $FF: synthetic method // $FF: bridge method @NotNull public static Cupcake copy$default(Cupcake var0, String var1, String var2, int var3, Object var4) { if((var3 & 1) != 0) { var1 = var0.flavor; } if((var3 & 2) != 0) { var2 = var0.icing; } return var0.copy(var1, var2); } public String toString() { return "Cupcake(flavor=" + this.flavor + ", icing=" + this.icing + ")"; } public int hashCode() { return (this.flavor != null?this.flavor.hashCode():0) * 31 + (this.icing != null?this.icing.hashCode():0); } public boolean equals(Object var1) { if(this != var1) { if(var1 instanceof Cupcake) { Cupcake var2 = (Cupcake)var1; if(Intrinsics.areEqual(this.flavor, var2.flavor) && Intrinsics.areEqual(this.icing, var2.icing)) { return true; } } return false; } else { return true; } } }
  15. collectiveidea.com @TTGonda Reminder @NotNull public final String component1() { return

    this.flavor; } @Nullable public final String component2() { return this.icing; }
  16. collectiveidea.com @TTGonda val cupcake = Cupcake("Vanilla", “Chocolate") val (flavor, icing)

    = cupcake return "$flavor cake with $icing icing” // Vanilla cake with Chocolate icing
  17. collectiveidea.com @TTGonda Cupcake cupcake = new Cupcake("Vanilla", “Chocolate"); String flavor

    = cupcake.component1(); String icing = cupcake.component2(); return "" + flavor + "cake with" + icing + “icing"; // Vanilla cake with Chocolate icing
  18. collectiveidea.com @TTGonda Iterable $receiver$iv = (Iterable)cupcakes; Iterator var2 = $receiver$iv.iterator();

    while(var2.hasNext()) { Object element$iv = var2.next(); Cupcake $flavor_icing = (Cupcake)element$iv; String flavor = $flavor_icing.component1(); String icing = $flavor_icing.component2(); String var7 = "" + flavor + ' ' + icing; System.out.println(var7); }
  19. collectiveidea.com @TTGonda Iterable $receiver$iv = (Iterable)cupcakes; Iterator var2 = $receiver$iv.iterator();

    while(var2.hasNext()) { Object element$iv = var2.next(); Cupcake $flavor_icing = (Cupcake)element$iv; String flavor = $flavor_icing.component1(); String icing = $flavor_icing.component2(); String var7 = "" + flavor + ' ' + icing; System.out.println(var7); }
  20. collectiveidea.com @TTGonda public final class Cupcake { @NotNull private static

    final String FLAVOR_VANILLA = "Vanilla"; @NotNull private static final String FLAVOR_CHOCOLATE = "Chocolate"; public static final Cupcake.Companion Companion = new Cupcake.Companion((DefaultConstructorMarker)null); public static final class Companion { @NotNull public final String getFLAVOR_VANILLA() { return Cupcake.FLAVOR_VANILLA; } @NotNull public final String getFLAVOR_CHOCOLATE() { return Cupcake.FLAVOR_CHOCOLATE; } private Companion() { } } }
  21. collectiveidea.com @TTGonda public final class Cupcake { @NotNull private static

    final String FLAVOR_VANILLA = "Vanilla"; @NotNull private static final String FLAVOR_CHOCOLATE = "Chocolate"; public static final Cupcake.Companion Companion = new Cupcake.Companion((DefaultConstructorMarker)null); public static final class Companion { @NotNull public final String getFLAVOR_VANILLA() { return Cupcake.FLAVOR_VANILLA; } @NotNull public final String getFLAVOR_CHOCOLATE() { return Cupcake.FLAVOR_CHOCOLATE; } private Companion() { } } }
  22. collectiveidea.com @TTGonda public final class Cupcake { @NotNull private static

    final String FLAVOR_VANILLA = "Vanilla"; @NotNull private static final String FLAVOR_CHOCOLATE = "Chocolate"; public static final Cupcake.Companion Companion = new Cupcake.Companion((DefaultConstructorMarker)null); public static final class Companion { @NotNull public final String getFLAVOR_VANILLA() { return Cupcake.FLAVOR_VANILLA; } @NotNull public final String getFLAVOR_CHOCOLATE() { return Cupcake.FLAVOR_CHOCOLATE; } private Companion() { } } }
  23. collectiveidea.com @TTGonda class Cupcake() { companion object { const val

    FLAVOR_VANILLA = "Vanilla" const val FLAVOR_CHOCOLATE = "Chocolate" } }
  24. collectiveidea.com @TTGonda public final class Cupcake { @NotNull public static

    final String FLAVOR_VANILLA = "Vanilla"; @NotNull public static final String FLAVOR_CHOCOLATE = "Chocolate"; public static final Cupcake.Companion Companion = new Cupcake.Companion((DefaultConstructorMarker)null); public static final class Companion { private Companion() { } } }
  25. collectiveidea.com @TTGonda IceCream var10000 = icecream; if(icecream == null) {

    Intrinsics.throwNpe(); } return var10000.getFlavor(); !! Operator
  26. collectiveidea.com @TTGonda IceCream var10000 = icecream; String var0; if(icecream !=

    null) { var0 = var10000.getFlavor(); if(var0 != null) { return var0; } } var0 = "Chocolate Chip"; return var0; Elvis Operator
  27. collectiveidea.com @TTGonda return icecream?.let({ nonNullIceCream ->
 nonNullIceCream.flavor })
 return icecream?.let({

    it.flavor })
 return icecream?.let { it.flavor }
 return icecream?.let(IceCream::flavor) Null Safe Scoping
  28. collectiveidea.com @TTGonda IceCream var10000 = icecream; String var3; if(icecream !=

    null) { IceCream var0 = var10000; var3 = var0.getFlavor(); } else { var3 = null; } return var3; Null Safe Scoping
  29. collectiveidea.com @TTGonda inline fun makePie(prepareFilling: () -> Filling) { makeCrust()

    val filling = prepareFilling() addFilling(filling) bakePie() }
  30. collectiveidea.com @TTGonda public static final void makePie( @NotNull Function0 prepareFilling)

    { Intrinsics.checkParameterIsNotNull( prepareFilling, “prepareFilling”); makeCrust(); Filling filling = (Filling)prepareFilling.invoke(); addFilling(filling); bakePie(); }
  31. collectiveidea.com @TTGonda public static final void makeApplePie() { makeCrust(); Filling

    filling$iv = (new Apples()).cut().addSpices().toFilling(); addFilling(filling$iv); bakePie(); }
  32. collectiveidea.com @TTGonda fun makePie(prepareFilling: () -> Filling) { makeCrust() val

    filling = prepareFilling() addFilling(filling) bakePie() }
  33. collectiveidea.com @TTGonda LINENUMBER 43 L6 NEW com/victoriagonda/v2/Apples DUP INVOKESPECIAL com/victoriagonda/v2/Apples.<init>

    ()V L7 LINENUMBER 44 L7 INVOKEVIRTUAL com/victoriagonda/v2/Apples.cut ()Lcom/victoriagonda/v2/Apples; L8 LINENUMBER 45 L8 INVOKEVIRTUAL com/victoriagonda/v2/Apples.addSpices ()Lcom/victoriagonda/v2/Apples; L9 LINENUMBER 46 L9 INVOKEVIRTUAL com/victoriagonda/v2/Apples.toFilling ()Lcom/victoriagonda/v2/Filling; L10 ARETURN L11 LOCALVARIABLE this Lcom/victoriagonda/v2/LambdasKt$makeApplePie$1; L0 L11 0 MAXSTACK = 2 MAXLOCALS = 1 // access flags 0x19 public final static Lcom/victoriagonda/v2/LambdasKt$makeApplePie$1; INSTANCE // access flags 0x8 static <clinit>()V NEW com/victoriagonda/v2/LambdasKt$makeApplePie$1 DUP INVOKESPECIAL com/victoriagonda/v2/LambdasKt$makeApplePie$1.<init> ()V PUTSTATIC com/victoriagonda/v2/LambdasKt$makeApplePie$1.INSTANCE : Lcom/victoriagonda/v2/LambdasKt$makeApplePie$1; RETURN MAXSTACK = 2 MAXLOCALS = 0
  34. collectiveidea.com @TTGonda final class com/victoriagonda/v2/LambdasKt$makeApplePie$1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function0 {

    // access flags 0x11 public final invoke()Lcom/victoriagonda/v2/Filling; @Lorg/jetbrains/annotations/NotNull;() // invisible L0 LINENUMBER 43 L0 L1 LINENUMBER 46 L1 L2 LINENUMBER 43 L2 L3 LINENUMBER 45 L3 L4 LINENUMBER 43 L4 L5 LINENUMBER 44 L5 L6 LINENUMBER 43 L6 NEW com/victoriagonda/v2/Apples DUP INVOKESPECIAL com/victoriagonda/v2/Apples.<init> ()V L7 LINENUMBER 44 L7 INVOKEVIRTUAL com/victoriagonda/v2/Apples.cut ()Lcom/victoriagonda/v2/Apples; L8 LINENUMBER 45 L8 INVOKEVIRTUAL com/victoriagonda/v2/Apples.addSpices ()Lcom/victoriagonda/v2/Apples;
  35. collectiveidea.com @TTGonda final class com/victoriagonda/v2/LambdasKt$makeApplePie$1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function0 {

    // access flags 0x11 public final invoke()Lcom/victoriagonda/v2/Filling; @Lorg/jetbrains/annotations/NotNull;() // invisible L0 LINENUMBER 43 L0 L1 LINENUMBER 46 L1 L2 LINENUMBER 43 L2 L3 LINENUMBER 45 L3 L4 LINENUMBER 43 L4 L5 LINENUMBER 44 L5 L6 LINENUMBER 43 L6 NEW com/victoriagonda/v2/Apples DUP INVOKESPECIAL com/victoriagonda/v2/Apples.<init> ()V L7 LINENUMBER 44 L7 INVOKEVIRTUAL com/victoriagonda/v2/Apples.cut ()Lcom/victoriagonda/v2/Apples; L8 LINENUMBER 45 L8 INVOKEVIRTUAL com/victoriagonda/v2/Apples.addSpices ()Lcom/victoriagonda/v2/Apples;
  36. collectiveidea.com @TTGonda final class com/victoriagonda/v2/LambdasKt$makeApplePie$1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function0 {

    // access flags 0x11 public final invoke()Lcom/victoriagonda/v2/Filling; @Lorg/jetbrains/annotations/NotNull;() // invisible L0 LINENUMBER 43 L0 L1 LINENUMBER 46 L1 L2 LINENUMBER 43 L2 L3 LINENUMBER 45 L3 L4 LINENUMBER 43 L4 L5 LINENUMBER 44 L5 L6 LINENUMBER 43 L6 NEW com/victoriagonda/v2/Apples DUP INVOKESPECIAL com/victoriagonda/v2/Apples.<init> ()V L7 LINENUMBER 44 L7 INVOKEVIRTUAL com/victoriagonda/v2/Apples.cut ()Lcom/victoriagonda/v2/Apples; L8 LINENUMBER 45 L8 INVOKEVIRTUAL com/victoriagonda/v2/Apples.addSpices ()Lcom/victoriagonda/v2/Apples;
  37. collectiveidea.com @TTGonda L2 LINENUMBER 43 L2 L3 LINENUMBER 45 L3

    L4 LINENUMBER 43 L4 L5 LINENUMBER 44 L5 L6 LINENUMBER 43 L6 NEW com/victoriagonda/v2/Apples DUP INVOKESPECIAL com/victoriagonda/v2/Apples.<init> ()V L7 LINENUMBER 44 L7 INVOKEVIRTUAL com/victoriagonda/v2/Apples.cut ()Lcom/victoriagonda/v2/Apples; L8 LINENUMBER 45 L8 INVOKEVIRTUAL com/victoriagonda/v2/Apples.addSpices ()Lcom/victoriagonda/v2/Apples; L9 LINENUMBER 46 L9 INVOKEVIRTUAL com/victoriagonda/v2/Apples.toFilling ()Lcom/victoriagonda/v2/Filling; L10 ARETURN L11 LOCALVARIABLE this Lcom/victoriagonda/v2/LambdasKt$makeApplePie$1; L0 L11 0 MAXSTACK = 2 MAXLOCALS = 1 // access flags 0x19 public final static Lcom/victoriagonda/v2/LambdasKt$makeApplePie$1; INSTANCE
  38. collectiveidea.com @TTGonda L7 LINENUMBER 44 L7 INVOKEVIRTUAL com/victoriagonda/v2/Apples.cut ()Lcom/victoriagonda/v2/Apples; L8

    LINENUMBER 45 L8 INVOKEVIRTUAL com/victoriagonda/v2/Apples.addSpices ()Lcom/victoriagonda/v2/Apples; L9 LINENUMBER 46 L9 INVOKEVIRTUAL com/victoriagonda/v2/Apples.toFilling ()Lcom/victoriagonda/v2/Filling; L10 ARETURN L11 LOCALVARIABLE this Lcom/victoriagonda/v2/LambdasKt$makeApplePie$1; L0 L11 0 MAXSTACK = 2 MAXLOCALS = 1 // access flags 0x19 public final static Lcom/victoriagonda/v2/LambdasKt$makeApplePie$1; INSTANCE // access flags 0x8 static <clinit>()V NEW com/victoriagonda/v2/LambdasKt$makeApplePie$1 DUP INVOKESPECIAL com/victoriagonda/v2/LambdasKt$makeApplePie$1.<init> ()V PUTSTATIC com/victoriagonda/v2/LambdasKt$makeApplePie$1.INSTANCE : Lcom/victoriagonda/v2/LambdasKt$makeApplePie$1; RETURN MAXSTACK = 2 MAXLOCALS = 0
  39. collectiveidea.com @TTGonda Code > Convert Java File to Kotlin File

    or CMD+SHFT+A and search “Convert Java File to Kotlin File”