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

解剖Kotlin ~バイトコードを読み解く~

yagi
March 09, 2017

解剖Kotlin ~バイトコードを読み解く~

Kotlinの特徴的な機能としてnull許容型や関数型や拡張関数などがよく取り沙汰されます。null安全だとか高階関数で簡潔に記述だとか拡張関数便利最高といった話は枚挙に暇がありません。確かに言語機能としていろいろとJavaに比べて便利なのは分かるんだけど、でもまぁ別にJavaを使っていてクリティカルに困っているわけではないしな〜学習コストとかチームへの導入コストを考えるとそこまで旨味を感じられるわけでもないしな〜みたいなそんな気分。わかります。

本セッションではKotlinのコードをコンパイルして得られるJavaバイトコードを、可読化したりデコンパイルする事によって、Kotlinの特徴的な言語機能がJavaでどのように表現されているかを読み解いていきます。これによりKotlinが肩代わりしてくれるボイラープレートコード群を明らかにします。Kotlinを使うことで省略できたボイラープレートコードが可読性をどのように高め、設計に影響を与えるのかについても言及します。

yagi

March 09, 2017
Tweet

More Decks by yagi

Other Decks in Technology

Transcript

  1. val nullable: String? = null nullable?.length String nullable = (String)null;

    if(nullable != null) { nullable.length(); } OVMMνΣοΫ͕௥Ճ͞ΕΔ
  2. w ߴ֊ؔ਺Λهड़Ͱ͖Δ ؔ਺ܕͱ͸Կ͔ fun calc( a: Int, b: Int, op:

    (Int, Int) -> Int ): Int { return op(a, b) }
  3. ϥϜμࣜͱ͸Կ͔ calc(1, 2, { a, b -> a + b

    }) *OU *OU *OUܕΛͦͷ৔Ͱهड़Ͱ͖Δ w ؔ਺Ϧςϥϧɻؔ਺ܕͷ࣮૷Λࣜͱ͠ ͯهड़Ͱ͖Δ
  4. ؔ਺ܕͱϥϜμࣜ listOf(1, 2, 3)
 .filter { it % 2 ==

    0 }
 .map { it * 2 } // 4 w ڧྗͳॲཧΛ؆ܿʹهड़Ͱ͖Δ
  5. public interface Function1<in P1, out R> : Function<R> { public

    operator fun invoke(p1: P1): R } 'VODUJPO͸ͨͩͷΠϯλϑΣʔε ؔ਺ܕ͸Ҿ਺ͷ਺ʹԠͯ͡ 'VODUJPO/ʹม׵͞ΕΔ
  6. calc(1, 2, { a, b -> a + b })

    calc(1, 2, (Function2)null.INSTANCE);
  7. calc(1, 2, { a, b -> a + b })

    calc(1, 2, (Function2)null.INSTANCE); ίϯύΠϥ͕ϥϜμࣜΛ੩తͩͱ൑அͨ͠৔߹͸ γϯάϧτϯͷΫϥεΛੜ੒͢Δ
  8. final class call$1 extends kotlin.jvm.internal.Lambda implements Function1 { public call$1()

    { super(2); } public final int invoke(int a, int b) { return a + b; } public final static $call$1 INSTANCE = new call$1(); } खಈͰ௚͢ͱ͜Μͳײ͡
  9. final class call$1 extends kotlin.jvm.internal.Lambda implements Function1 { public call$1()

    { super(2); } public final int invoke(int a, int b) { return a + b; } public final static $call$1 INSTANCE = new call$1(); } -BNCEBΛܧঝ
  10. final class call$1 extends kotlin.jvm.internal.Lambda implements Function1 { public call$1()

    { super(2); } public final int invoke(int a, int b) { return a + b; } public final static $call$1 INSTANCE = new call$1(); } Ҿ਺ͷ਺Λ਌Ϋϥεʹ౉͢ -BNCEBΛܧঝ
  11. final class call$1 extends kotlin.jvm.internal.Lambda implements Function2 { public call$1()

    { super(2); } public final int invoke(int a, int b) { return a + b; } public final static $call$1 INSTANCE = new call$1(); } Ҿ਺ͷ਺Λ਌Ϋϥεʹ౉͢ 'VODUJPOΛ࣮૷ -BNCEBΛܧঝ
  12. final class call$1 extends kotlin.jvm.internal.Lambda implements Function1 { public call$1()

    { super(2); } public final int invoke(int a, int b) { return a + b; } public final static $call$1 INSTANCE = new call$1(); } Ҿ਺ͷ਺Λ਌Ϋϥεʹ౉͢ γϯάϧτϯ 'VODUJPOΛ࣮૷ -BNCEBΛܧঝ
  13. val seed = 10 calc(1, 2, { a, b ->

    a + b + seed }) final byte seed = 10; calc(1, 2, (Function2)(new Function2(2) { public final int invoke(int a, int b) { return a + b + seed; } })); Ϋϩʔδϟͷ৔߹͸ແ໊ΫϥεΛੜ੒͢Δ
  14. var seed = 10 calc(1, 2, { a, b ->

    seed++; a + b }) final IntRef seed = new IntRef(); seed.element = 10; calc(1, 2, (Function2)(new Function2(2) { public final int invoke(int a, int b) { int var3 = seed.element++; return a + b; } })); Ωϟϓνϟͨ͠ม਺Λมߋ͢Δ৔߹͸ 3FGΫϥε͕࢖ΘΕΔ
  15. w ؔ਺ܕΛҾ਺ͷ਺ʹԠͨ͡'VODUJPO/Πϯλ ϑΣʔεʹม׵͢Δ w ϥϜμࣜΛɺ-BNCEBΛܧঝͯ͠'VODUJPO/Λ ࣮૷͢ΔΫϥεʹม׵͢Δ w ϥϜμࣜͷத਎ʹΑͬͯ࠷దͳίʔυΛੜ੒͢Δ w جຊతʹ͸SFUSPMBNCEB΍KBDLͳͲͰͷ+BWB

    ϥϜμࣜαϙʔτͱಉ͡Α͏ͳΞϓϩʔνͰؔ਺ ܕΛ࣮ݱͯ͘͠ΕΔɻࠩ෼ͱͯ͠͸Ϋϩʔδϟ͕ ͪΐͬͱॊೈͱ͍͏͘Β͍ ؔ਺ܕɺϥϜμ͕ࣜ΍͍ͬͯΔ͜ͱ
  16. @NotNull public static final WindowManager getWindowService(@NotNull Context $receiver) { Intrinsics.checkParameterIsNotNull($receiver,

    “$receiver"); Object var10000 = $receiver.getSystemService(“window"); if(var10000 == null) { throw new TypeCastException("null cannot be cast to non-null type android.view.WindowManager”); } else {
 return (WindowManager)var10000;
 } } fun Context.getWindowService() = getSystemService(Context.WINDOW_SERVICE) as WindowManager
  17. public static final WindowManager getWindowService(Context $receiver) { Object var10000 =

    $receiver.getSystemService(“window");
 return (WindowManager)var10000; } fun Context.getWindowService() = getSystemService(Context.WINDOW_SERVICE) as WindowManager ˞γϯϓϧʹͨ͠΋ͷ ର৅ͷΫϥεΛୈҰҾ਺ʹऔΔ੩తؔ਺͕ੜ੒͞ΕΔ
  18. w ΧελϜΞΫηαΛ࣮૷Ͱ͖Δ ϓϩύςΟͱ͸Կ͔ class Product(val id: Int) { var name:

    String = “" get() = field set(value) { field = value } } ϓϩύςΟΞΫηε͸ඞͣΞΫηαΛհ͢ɻ ΞΫηα಺͔ΒͰͷΈΞΫηεͰ͖Δ όοΩϯάϑΟʔϧυͱ͍͏࣮ମ͕͋Δ
  19. private final int id; @NotNull private String name; public final

    int getId() { return this.id; } @NotNull public final String getName() { return this.name; } public final void setName(@NotNull String var1) Intrinsics.checkParameterIsNotNull(var1, “<set-?>"); this.name = var1; } class Product(val id: Int, var name: String)
  20. private final int id; @NotNull private String name; public final

    int getId() { return this.id; } @NotNull public final String getName() { return this.name; } public final void setName(@NotNull String var1) Intrinsics.checkParameterIsNotNull(var1, “<set-?>"); this.name = var1; } class Product(val id: Int, var name: String) QSJWBUFͳϑΟʔϧυ͕એݴ͞ΕΔ
  21. private final int id; @NotNull private String name; public final

    int getId() { return this.id; } @NotNull public final String getName() { return this.name; } public final void setName(@NotNull String var1) Intrinsics.checkParameterIsNotNull(var1, “<set-?>"); this.name = var1; } class Product(val id: Int, var name: String) QSJWBUFͳϑΟʔϧυ͕એݴ͞ΕΔ WBMͷ৔߹HFUUFSͷΈੜ੒͞ΕΔ
  22. private final int id; @NotNull private String name; public final

    int getId() { return this.id; } @NotNull public final String getName() { return this.name; } public final void setName(@NotNull String var1) Intrinsics.checkParameterIsNotNull(var1, “<set-?>"); this.name = var1; } class Product(val id: Int, var name: String) QSJWBUFͳϑΟʔϧυ͕એݴ͞ΕΔ WBMͷ৔߹HFUUFSͷΈੜ੒͞ΕΔ WBSͷ৔߹HFUUFSTFUUFS͕ੜ੒͞ΕΔ
  23. val id = product.id product.name = "meat" int id =

    product.getId(); product.setName("meat");
  24. fun semitransparent(view: View) { view.alpha = 0.5f } val text:

    View? = findViewById(R.id.text) semitransparent(text)
  25. fun semitransparent(view: View) { view.alpha = 0.5f } val text:

    View? = findViewById(R.id.text) semitransparent(text) 5ZQFNJTTNBUDIͰίϯύΠϧΤϥʔ
  26. fun semitransparent(view: View) { view.alpha = 0.5f } val text:

    View? = findViewById(R.id.text) semitransparent(text!!) ةݥͳݺͼग़͠ɻཁվળͷγάφϧ
  27. fun semitransparent(view: View) { view.alpha = 0.5f } val text:

    View? = findViewById(R.id.text) text?.let { semitransparent(it) } OVMM͡Όͳ͚Ε͹࣮ߦɻ
  28. fun semitransparent(view: View) { view.alpha = 0.5f } val text:

    View? = findViewById(R.id.text) text?.let { semitransparent(it) } OVMM͡Όͳ͚Ε͹࣮ߦɻ ͳΜ͔ͩ৑௕ͩ͠ɺͦ΋ͦ΋OVMMͷέʔε͸૝ఆͯ͠ͳ͍ͷͰ͸ʁ
  29. fun semitransparent(view: View) { view.alpha = 0.5f } val text:

    View? = findViewById(R.id.text) text?.let { semitransparent(it) } OVMM͡Όͳ͚Ε͹࣮ߦɻ ͳΜ͔ͩ৑௕ͩ͠ɺͦ΋ͦ΋OVMMͷέʔε͸૝ఆͯ͠ͳ͍ͷͰ͸ʁ %BUB#JOEJOH΍,PUMJO"OESPJE&YUFOTJPOTͷར༻Λݕ౼
  30. inline fun <reified T> Intent.getRequired(key: String): T {
 extras?.get(key).let {


    if (it !is T) {
 throw IllegalArgumentException("$key")
 }
 return it
 } } LFZ͕ͳ͍৔߹ʹྫ֎Λεϩʔ͢Δɺ HFU3FRVJSFEؔ਺Λ*OUFOUʹ௥Ճ͢Δ
  31. ·ͩ·ͩ͋Δ,PUMJOͷػೳ w σϦήʔτϓϩύςΟ w ΦϖϨʔλΦʔόʔϩʔυ w ίϯύχΦϯΦϒδΣΫτ w γʔϧυΫϥε w

    XIFOࣜ w ίϧʔνϯ w λΠϓΤΠϦΞε w ۩৅Խ͞Εͨܕύϥϝʔλ w σʔλΫϥε w ໊લ෇͖Ҿ਺ w εϚʔτΩϟετ w ෼ղએݴ w ϩʔΧϧؔ਺ w ຤ඌ࠶ؼ࠷దԽ w MBUFJOJU w Πϯελϯεͷؔ਺ࢀর FUD