2016/11/26(土)のKotlin Internal勉強会の資料です
#kotlin_internal
https://connpass.com/event/40360/
KotlinͱJavaͱnullͷϥΠτͳ@RyotaMurohoshi2016/11/26()(Kotlin(internal(ษڧձ
View Slide
͜Μͳ͜ͱ͠·͢• nullʹ·ͭΘΔKotlinݴޠ༷ͷ֬ೝ• όΠτίʔυͱσίϯύΠϧͨ͠JavaͲ͏ͳΔʁ• ͪΐͬͱ͚ͩίϯύΠϥͷίʔυݟΔ
ࣗݾհ• ྄ࣨଠ(ΉΖ΄͠)• @RyotaMurohoshi• ࣄͰKotlin+Android• झຯͰC#+UnityͰήʔϜ։ൃ
ͱ͜ΖͰɺ࠷ۙʹͨ͠هࣄͱ͔
ʰnull$ͱϓϩάϥϛϯάݴޠʱ
ʰnull͕;ΜͪΌ͔ʱ
ʰnull͕͋ΔϓϩάϥϛϯάݴޠͳΜͪΌΒʱ
ۤ͠ΜͰΔ͔ΒΈΜͳnullͷ͖
KotlinͷnullΛ͓͞Β͍
String?Λฦؔ͢((Kotlinͷίʔυ)fun returnStringNullableKotlin(): String? = null
͜ΕΛ͏ͱ!(Kotlinͷίʔυ)val str = returnNullableStringKotlin()// ͜ΕOK// val str : String? = returnNullableStringKotlin()// ͜ΕίϯύΠϧΤϥʔ Type Mismatch// val str : String = returnNullableStringKotlin()// println(str.length) // ίϯύΠϧΤϥʔprintln(str?.length) // ͜ΕͳΒOK
͞Α͏ͳΒnullʂʂʂ
ຊʹʁ
ݱ࣮ͦΜͳʹ͘ͳ͍
Kotlin͚ͩͰίʔυΛॻ͖͖ΕΔΘ͚Ͱͳ͍ͦ͏ɺJavaͷίʔυΛݺͼग़͞ͳ͍ͱ͍͚ͳ͍ͦͷ߹nullɺNullableʁ
StringΛฦؔ͢'(Javaͷίʔυ)public class Utility {public static String returnNullableStringJava() {return null;}}
͜ΕΛ͏ͱ!(JavaͷίʔυΛKotlinͷίʔυ͔ΒݺͿ)val str = Utility.returnNullableStringJava()// ͜ΕOK// val str : String? = Utility.returnNullableStringJava()// ʂʂʂ// ͜ΕOKʂʂ ʂ// val str : String = Utility.returnNullableStringJava()
JavaͰॻ͍ͨStringΛฦ͢ϝιουͷฦΓɺStringܕʹString?ܕʹೖͰ͖ΔStringͱString?ͬͯҧ͏ܕͩͬͨͣͳͷʹʁ
ʲ࠶ܝʳ͜ΕΛ͏ͱ!(Kotlinͷίʔυ)val str = returnNullableStringKotlin()// ͜ΕOK// val str : String? = returnNullableStringKotlin()// ͜ΕίϯύΠϧΤϥʔ Type Mismatch// val str : String = returnNullableStringKotlin()// println(str.length) // ίϯύΠϧΤϥʔprintln(str?.length) // ͜ΕͳΒOK
Pla$orm(TypeU"lity.returnNullableStringJava()ͷฦΓPla6orm9Type
• JavaͷࢀরܕͷϝιουͷฦΓͳͲɺPla'orm+Typeʹ• IDEͷ্ͰɺString!ͱ͔Person!ͱ͔ͬͯද͢• ͚ͲίʔυͰɺString!ͱॻ͚ͳ͍
ܕΛ໌ࣔతʹॻ͍ͨΒͲ͏ͳΔʁ
U"lity.returnNullableStringJava()ͷฦΓStringܕʹೖͨ͠ΒҎޙɺStringܕͱͯ͠ѻ͏͠String?ܕʹೖͨ͠ΒҎޙɺString?ܕͱͯ͠ѻ͏
JavaͷίʔυΛKotlinͷίʔυ͔ΒݺΜͰString?ʹೖval str : String? = Utility.returnNullableStringJava()println(str?.length)// ίϯύΠϧΤϥʔ// println(str.length)
JavaͷίʔυΛKotlinͷίʔυ͔ΒݺΜͰStringʹೖval str : String = Utility.returnNullableStringJava()println(str.length) // ίϯύΠϧΤϥʔʮͰʯͳ͍͚Ͳ// ͦΕඞཁͳ͍Αͬͯɺܯࠂ͕ग़Δ// println(str?.length)
JavaͷίʔυΛKotlinͷίʔυ͔ΒݺΜͰܕΛ໌ࣔ͠ͳ͍ͱval str = Utility.returnNullableStringJava()// ͜ΕOKprintln(str?.length)// ͜ΕOKʁ(ίϯύΠϧΤϥʔʮͰʯͳ͍)println(str.length)
ͳΔ΄ͲɺΊͰͨ͠ΊͰͨ͠ʁ
ʹͳΒͳ͍ղઆΛޙճ͠ʹ͕ͨ͠ʮ2ͭʯʂ
ʲ࠶ܝʳStringΛฦؔ͢'(Javaͷίʔυ)public class Utility {public static String returnNullableStringJava() {return null;}}
͍ͭ͜nullฦͧ͢ʂ
JavaͷίʔυΛKotlinͷίʔυ͔ΒݺΜͰܕΛ໌ࣔ͠ͳ͍ͱval str = Utility.returnNullableStringJava()// ͜ΕOKprintln(str?.length)// ίϯύΠϧΤϥʔͰͳ͍͚ΕͲɺ// ࣮ߦ࣌ʹʮjava.lang.NullPointerExceptionʯprintln(str.length)
͵ΔΆग़Δ͡ΌΜʂPla$orm(TypeͰɺʮNullPointerExcep5onʯͳ͛͏Δ
͏ͻͱͭ
ʲ࠶ܝʳJavaͷίʔυΛKotlinͷίʔυ͔ΒݺΜͰStringʹೖval str : String = Utility.returnNullableStringJava()println(str.length) // ίϯύΠϧΤϥʔʮͰʯͳ͍͚Ͳ// ͦΕඞཁͳ͍Αͬͯɺܯࠂ͕ग़Δ// println(str?.length)
ͩΊͦ͏U"lity.returnNullableStringJava()nullΛฦ͢͜ΕΛɺStringܕʹೖͯ͠ී௨ʹϝϯόʹΞΫηεͯ͠͠·͍ͬͯΔ
ɺͲ͏ͳΔʁ• ϝϯόʹΞΫηεͨ͠λΠϛϯάͰNullPointerExcep0on• ͦΕҎ֎ʢԿ͔ͷλΠϛϯάͰͳΜ͔ͷྫ֎Λ͛Δʣ
ਖ਼ղɺʰͦΕҎ֎ʱϝϯόʹΞΫηε͢Δલʹྫ֎Λ͛Δ
ʲ࠶ܝʳJavaͷίʔυΛKotlinͷίʔυ͔ΒݺΜͰStringʹೖval str : String = Utility.returnNullableStringJava()println(str.length) // ίϯύΠϧΤϥʔʮͰʯͳ͍͚Ͳ͜ͷίʔυΛ࣮ߦ͢Δͱ...
java.lang.IllegalStateExcep0onΛ͛ΔU"lity.returnNullableStringJava()5must5not5be5null
NullPointerExcep/onͰͳͯ͘IllegalStateExcep/onͱ͍͏͜ͱɺίϯύΠϥ͕Կ͔͍ͯ͠ΔͣʂݟͯΈΑ͏
ʲ࠶ܝʳJavaͷίʔυΛKotlinͷίʔυ͔ΒݺΜͰStringʹೖval str : String = Utility.returnNullableStringJava()println(str.length) // ίϯύΠϧΤϥʔʮͰʯͳ͍͚Ͳ͜ͷByte%CodeΛΈͯΈΔIDEAͰɺTools)>)Kotlin)>)Show)Kotlin)Bytecode
L0LINENUMBER 73 L0INVOKESTATIC com/muhron/kotlin_java_interpolator/Utility.returnNullableStringJava ()Ljava/lang/String;DUPLDC "Utility.returnNullableStringJava()"INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkExpressionValueIsNotNull (Ljava/lang/Object;Ljava/lang/String;)VASTORE 0L1LINENUMBER 74 L1ALOAD 0INVOKEVIRTUAL java/lang/String.length ()IISTORE 1NOPL2GETSTATIC java/lang/System.out : Ljava/io/PrintStream;ILOAD 1INVOKEVIRTUAL java/io/PrintStream.println (I)VL3͜ΕΛ͞ΒʹDecompoleʂ
KotlinΛBytecodeʹͯ͠ɺͦΕΛ͞ΒʹDecompileString var10000 = Utility.returnNullableStringJava();Intrinsics.checkExpressionValueIsNotNull(var10000, "Utility.returnNullableStringJava()");String str = var10000;int var1 = str.length();System.out.println(var1);
ϙΠϯτʮIntrinsics.checkExpressionValueIsNotNullʯϝϯόʹΞΫηε͢Δલʹɺ͜Ε͕ݺΕ͍ͯΔʂ
ίʔυΛݟͯΈ·͠ΐ͏ʂIntrinsics.checkExpressionValueIsNotNull
h"ps://github.com/JetBrains/kotlin/blob/1.0.5/core/run;me.jvm/src/kotlin/jvm/internal/Intrinsics.java#L86package kotlin.jvm.internal;@SuppressWarnings("unused")public class Intrinsics {private Intrinsics() {}/*ུ*/public static void checkExpressionValueIsNotNull(Object value, String expression) {if (value == null) {throw sanitizeStackTrace(new IllegalStateException(expression + " must not be null"));}}/*ུ*/}
ͳΔ΄Ͳɺ͔֬ʹnullͩͬͨΒIllegalStateExcep.on͍͛ͯΔ
Ͱɺ͜Ε୭͕Αͼ͍ͩͯ͠Δͷ͔ʁʮcheckExpressionValueIsNotNullʯͰ୳͢
h"ps://github.com/JetBrains/kotlin/blob/1.0.5/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmU?l.java#L650AsmU%lͱ͍͏தͰݺͼग़͍ͯ͠Δʂʂʂ͞ΒʹಡΈਐΊΔͱ
ExpressionCodegen#genQualifiedh"ps://github.com/JetBrains/kotlin/blob/1.0.5/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java#L291ͱFunc%onCodegen#genDelegateh"ps://github.com/JetBrains/kotlin/blob/1.0.5/compiler/backend/src/org/jetbrains/kotlin/codegen/Func>onCodegen.java#L1029
ͳΔ΄Ͳ
ͯ͞ɺKotlinͰίʔυΛॻ͚ΔͱݴͬͯJavaͱͷ૬ޓӡ༻ඞਢʂnullͱͷઓ͍ͭͮ͘ͷͰ͋ͬͨ
͚ͲͳΜͱ͔͍ͨ͠
@NotNullͱ@Nullable
@NotNull
Javaͷίʔυ// ΞϊςʔγϣϯΛ͚ͭΔ@NotNullpublic static String returnStringWithNotNullAnnotation() {return "";}
@NotNullͳJavaͷίʔυΛKotlinͷίʔυ͔ΒݺΜͰ// IDEɺฦΓܕ͕Stringͬͯڭ͑ͯ͘ΕΔʢString!Ͱͳ͍ʣval str = Utility.returnStringWithNotNullAnnotation()// ͜ΕOK// val str : String = Utility.returnStringWithNotNullAnnotation()// ࣮ɺ͜ΕOK//val str : String? = Utility.returnStringWithNotNullAnnotation()println(str?.length) // ܯࠂ͕ͰΔprintln(str.length) // ͜ΕOK
@NotNullͳJavaͷίʔυΛKotlinͷίʔυ͔ΒݺΜͰBytecode()>(JavaͰίϯύΠϧString str = Utility.returnStringWithNotNullAnnotation();int var1 = str.length();System.out.println(var1);
@Nullable
Javaͷίʔυ// ΞϊςʔγϣϯΛ͚ͭΔ@Nullablepublic static String returnStringWithNullableAnnotation() {return "";}
@NullableͳJavaͷίʔυΛKotlinͷίʔυ͔ΒݺΜͰ// IDEɺฦΓܕ͕String?ͬͯڭ͑ͯ͘ΕΔʢString!Ͱͳ͍ʣval str = Utility.returnStringWithNullableAnnotation()// ͜ΕOK//val str : String? = Utility.returnNullableStringJava()// ͜ΕίϯύΠϧΤϥʔ//val str : String = Utility.returnStringWithNullableAnnotation()println(str?.length) // ͜ΕOK// println(str.length) // ͜ΕίϯύΠϧΤϥʔ
@NullableͳJavaͷίʔυΛKotlinͷίʔυ͔ΒݺΜͰBytecode()>(JavaͰίϯύΠϧString str = Utility.returnStringWithNullableAnnotation();Integer var1 = str != null?Integer.valueOf(str.length()):null;System.out.println(var1);
૬ޓӡ༻લఏͷJavaͷίʔυʹɺ@Nullabeͱ@NotNullΛ͚ͭΑ͏
Androiderͷํɺ@Nullabeͱ͍͑ʁ
LombokϢʔβʔͷํɺ@Nullableͱ͍͑ʁ
FindbugsϢʔβʔͷํɺ@Nullableͱ͍͑ʁ
JetBrainsతʹ@Nullabeͱ͍͑ʁ
@NullableΊͬͪΌ͋ΔʂʂʂͲͷNullableͩΑʂʁ
࣮ෳରԠ͍ͯ͠Δ• org.jetbrains.annota.ons.Nullable• android.support.annota.on.Nullable• com.android.annota.ons.Nullable• org.eclipse.jdt.annota.on.Nullable• org.checkerframework.checker.nullness.qual.Nullableh"ps://github.com/JetBrains/kotlin/blob/1.0.5/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnota?onNames.kt
࣮ෳରԠ͍ͯ͠Δʢଓ͖ʣ• javax.annota*on.Nullable• javax.annota*on.CheckForNull• edu.umd.cs.findbugs.annota*ons.CheckForNull• edu.umd.cs.findbugs.annota*ons.Nullable• edu.umd.cs.findbugs.annota*ons.PossiblyNullh"ps://github.com/JetBrains/kotlin/blob/1.0.5/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnota?onNames.kt
͜͜ΒΜOK
ίʔυΛ͍·͠ΐ͏
h"ps://github.com/JetBrains/kotlin/blob/1.0.5/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnota?onNames.ktval NULLABLE_ANNOTATIONS = listOf(JvmAnnotationNames.JETBRAINS_NULLABLE_ANNOTATION,FqName("android.support.annotation.Nullable"),FqName("com.android.annotations.Nullable"),FqName("org.eclipse.jdt.annotation.Nullable"),FqName("org.checkerframework.checker.nullness.qual.Nullable"),FqName("javax.annotation.Nullable"),FqName("javax.annotation.CheckForNull"),FqName("edu.umd.cs.findbugs.annotations.CheckForNull"),FqName("edu.umd.cs.findbugs.annotations.Nullable"),FqName("edu.umd.cs.findbugs.annotations.PossiblyNull"))
typeQualifiers.ktͷதʹ....class JavaTypeQualifiers internal constructor(val nullability: NullabilityQualifier?,val mutability: MutabilityQualifier?,internal val isNotNullTypeParameter: Boolean) {companion object {val NONE = JavaTypeQualifiers(null, null, false)}}ͷnullabilityͷੜʹΘΕ͍ͯΔh"ps://github.com/JetBrains/kotlin/blob/1.0.5/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeQualifiers.kt#L42
·ͱΊ• Pla%orm)TypeΛཧղ͠Α͏• Javaͱͷ૬ޓӡ༻ՕॴͰɺNullPointetExcep8onIllegalStateExcep8onՄೳੑ͋Γ• JavaͷϥΠϒϥϦʹɺ@Nullableͱ@NotNull͚ͭΑ͏
NextΞΫγϣϯίϯύΠϥɺJavaTypeQualifiersΛ༻͍ͯAsmU%l͕Intrinsicsݺͼग़͢ίʔυΛు͍͍ͯΔͱࢥΘΕΔͷͰɺௐࠪ
͋Γ͕ͱ͏͍͟͝·ͨ͠
ؔ࿈ɾࢀߟ• Calling(Java(code(from(Kotlinh5ps://kotlinlang.org/docs/reference/java=interop.html• Kotlin(M9ͰՃ͞ΕͨPlaAorm(Typeͷh5p://taro.hatenablog.jp/entry/2014/10/16/233702• ʲίʔυϦʔσΟϯάʳKotlin(to(JavaScriptίϯύΠϥϝϞh5p://yyyank.blogspot.jp/2015/05/kotlinkotlin=to=javascript.html