kotlin gets reflection - oracle€¦ · // corresponding kotlin class foo { fun getfirstname():...

36
KOTLIN GETS REFLECTION [email protected]

Upload: others

Post on 31-May-2020

18 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

KOTLIN GETS REFLECTION

[email protected]

Page 2: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

Introspection is examination of one's own conscious thoughts and feelings.

Schultz, D. P.; Schultz, S. E. (2012).

A history of modern psychology (10th ed.)

Page 3: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

LEGAL

Don’t panic

Relax

Take it easy

Page 4: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

DON’T JUDGE STRICTLY

Your opin

ion

matters

Page 5: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

OUTLINE •  Intro •  Ways of Introspection •  Reflection API

•  Reflection Literals

•  Expression Trees

•  Conclusion

Page 6: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

USE CASES Dependency Injection Data binding

Convention over configuration

Hacks Workarounds

Black Magic

Page 7: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

INTROSPECTION Instances - what is your class? Classes & Types - what are your members? supertypes? create an instance Methods/Fields - what are your parameters/types/etc? run with these args. Expressions - ???

Page 8: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

JAVA.LANG.REFLECT? Top-level functions Default arguments Properties

Nullable types

Special types (Nothing, (Mutable)List, etc)

+ modules (classes in a package)

Page 9: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

METADATA

*.kt

*.class (kotlin)

*.jar (kotlin)

kotlin symbols

kotlin symbols

kotlin symbols

java symbols

kotlinc

Page 10: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

HOW TO STORE METADATA?

*.class

Custom attributes Annotations

Annotate each symbol

One big annotation

Page 11: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

ONE BIG ANNOTATION

*.class

@KotlinClass(“data”)

val/var types defaults …

Java definitions

erased generic annotations …

Page 12: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

RE-USE

j.l.Class

*.kt

*.class

AST

@KotlinClass

Symbols

Page 13: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

DISCREPANCY 1 java.lang.annotation.Annotation

vs

org.jetbrains.kotlin.internal….AnnotationDescriptor

Page 14: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

PURE JAVA CLASSES?

j.l.Class

*.kt

*.class

AST

@KotlinClass

Symbols

*.java

java2k

Page 15: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

DISCREPANCY 2 // Java

class Foo {

@NotNull

String getFirstName() { … }

String getMiddleName() { … }

}

// Corresponding Kotlin

class Foo {

fun getFirstName(): String

fun getMiddleName(): String?

}

Page 16: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

DISCREPANCY 2

j.l.Class

*.class Symbols

*.java

java2k

annotations.xml

Page 17: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

SUMMARY 1 Kotlin-specific reflection API -  works for Java as well Metadata representation -  one big annotation -  re-use code from the compiler Problems -  representing annotations -  nullable/mutable types

Page 18: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

ENTRY POINTS

Page 19: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

SYNTAX (TENTATIVE) Foo::class expr::class

List<String>::member

org.sample.bar::member

expr::member

expr::type (maybe)

Page 20: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

USE CASES: PASSING CODE AROUND list.filter(Item::isValid)

* Why not a lambda?

foo {a, b, c -> bar(a, b, c) }

Page 21: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

USE CASES: CONSTRUCTORS fun <T: Tag> tag( ! create: () -> T, init: T.() -> Unit !) { … } !!!tag(::DIV) { // kara.tags::DIV ! … !} !

Page 22: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

USE CASES: DATA BINDING !class Model { !

"var userName: String by observable() !} !!!bind(view.textField, model::userName) !

Page 23: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

GENERICS? fun foo(s: String): Foo !!

::foo : (String) -> Foo !!!!fun <T> foo(t: T): T { … } !!

::foo : ∀T.(T) -> T !

Page 24: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

RANK-2 POLYMORPHISM interface Function1<P1, R> { R invoke(P1 p1); }

vs

interface GenericFunction1_1<P1, R> { <T> R<T> invoke(P1<T> p1);

}

Page 25: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

ENCODING FOR FUNCTIONS f: (Foo) -> Bar is Function1<Foo, Bar> !""interface Function1<P1, R> { ! R invoke(P1 p1); !} !

Page 26: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

GENERIC FUNCTIONS f: <T>(List<T>) -> T !!•  GenericFunction<List<T>, T> ??? !•  GenericFunction<T, List<T>, T> ??? !

!!interface GenericFunction1_1<P1, R> { ! <T> R<T> invoke(P1<T> p1); !} !

+ Kinds

Page 27: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

GENERICS "class Foo<T> { ! fun <R> bar(t: T): R { … } !} !!!

Foo<T’>::bar<R’> : (T’) -> R’ !

Page 28: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

EXPR::TYPE val x: Any = listOf(1, 2, 3) !x::class -> java.util.ArrayList!x::type -> java.util.ArrayList<Unknown> !!vs

!val x = listOf(1, 2, 3) // x: List<Int> !x::class -> java.util.ArrayList!x::type -> java.util.ArrayList<Int> !

Page 29: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

DELEGATED PROPERTIES val foos: List<Foo> by Lazy { foos.find(…) }"""class Lazy<T>(compute: () -> T) { ! private var value: T? = null "! fun get(me: Any, p: PropertyMetadata): T { ! if (value == null) value = compute() ! return value ! } !} !

Page 30: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

DELEGATED PROPERTIES val foos: List<Foo> by Lazy { foos.find(…) }""::foos::delegate : Lazy<Foo> !::foos : Property<List<Foo>> !"or "::foos.delegate : Lazy<Foo> !::foos : DelegatedProperty< ! List<Foo>, ! Lazy<Foo> ! > !

Page 31: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

SUMMARY 2 Reflection literals -  Static name lookup & typing -  Generics are hard, as usual

Page 32: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

CODE INTROSPECTION

I told you!

Page 33: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

USE CASES: LINQ !!db ! .selectFrom(::User) ! .where { lastName.startsWith(“A”) } ! .orderBy { lastName + firstName } !

Page 34: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

server

client

server

USE CASES: WEB html { ! ! body { ! onLoad { ! ... ! } ! ! ... ! ! } !} !

Page 35: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

EXPRESSION TREES fun onLoad(ast: Expression<() -> Unit>) { ! ...!} !!onLoad { ! ... // compiled to factory calls !} !!

At run time the tree can be translated to JS

Page 36: KOTLIN GETS REFLECTION - Oracle€¦ · // Corresponding Kotlin class Foo { fun getFirstName(): String fun getMiddleName(): String? } DISCREPANCY 2 j.l.Class *.class Symbols *.java

SUMMARY Kotlin’s introspection facilities -  Reflection API

-  Java interop is the hardest issue -  Reflection literals

-  Issues with generics -  Expression trees

-  Compiler as a service