Kotlin Code Generation Alec Strong & Jake Wharton public - - PowerPoint PPT Presentation

kotlin code generation
SMART_READER_LITE
LIVE PREVIEW

Kotlin Code Generation Alec Strong & Jake Wharton public - - PowerPoint PPT Presentation

Kotlin Code Generation Alec Strong & Jake Wharton public final class User { data class User( private final String firstName; private final String lastName; val firstName: String, private final int age; public User(String firstName,


slide-1
SLIDE 1

Kotlin Code Generation

Alec Strong & Jake Wharton

slide-2
SLIDE 2

public final class User { private final String firstName; private final String lastName; private final int age; public User(String firstName, String lastName, int age) { this.firstName = firstName; this.lastName = lastName; this.age = age; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getAge() { return age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return age == user.age && Objects.equals(firstName, user.firstName) && Objects.equals(lastName, user.lastName); } @Override public int hashCode() { return Objects.hash(firstName, lastName, age); } @Override public String toString() { return "User{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", age=" + age + '}'; } }

data class User( val firstName: String, val lastName: String, val age: Int )

slide-3
SLIDE 3

Bytecode

slide-4
SLIDE 4

Protocol Buffers

slide-5
SLIDE 5

Protocol Buffers SQL

slide-6
SLIDE 6

Protocol Buffers SQL Swagger

slide-7
SLIDE 7

Protocol Buffers SQL Swagger Android XML

slide-8
SLIDE 8

Protocol Buffers SQL Swagger Android XML YAML

slide-9
SLIDE 9

Protocol Buffers SQL Swagger Android XML YAML Mirrors/Elements

slide-10
SLIDE 10

SQL Swagger Android XML YAML Mirrors/Elements PSI

slide-11
SLIDE 11

Swagger Android XML YAML Mirrors/Elements PSI UAST

slide-12
SLIDE 12

Android XML YAML Mirrors/Elements PSI UAST ???

slide-13
SLIDE 13

Protocol Buffers SQL Swagger Android XML YAML Mirrors/Elements PSI UAST ???

slide-14
SLIDE 14

Protocol Buffers

slide-15
SLIDE 15

syntax = "proto2"; package com.sample; message Ogre { required string name = 1; repeated int32 layers = 2;

  • ptional string swamp = 3;

}

slide-16
SLIDE 16

public final String name; public final List<Integer> layers; public final String swamp; public Ogre(String name, List<Integer> layers, String swamp) { this(name, layers, swamp, ByteString.EMPTY); } public Ogre(String name, List<Integer> layers, String swamp, ByteString unknownFields) { super(ADAPTER, unknownFields); this.name = name; this.layers = Internal.immutableCopyOf("layers", layers); this.swamp = swamp; }

slide-17
SLIDE 17

public final String name; public final List<Integer> layers; public final String swamp; public Ogre(String name, List<Integer> layers, String swamp) { this(name, layers, swamp, ByteString.EMPTY); } public Ogre(String name, List<Integer> layers, String swamp, ByteString unknownFields) { super(ADAPTER, unknownFields); this.name = name; this.layers = Internal.immutableCopyOf("layers", layers); this.swamp = swamp; } public final String name; public final List<Integer> layers; public final String swamp; this.name = name; this.layers = Internal.immutableCopyOf("layers", layers); this.swamp = swamp;

slide-18
SLIDE 18

public final String name; public final List<Integer> layers; public final String swamp; public Ogre(String name, List<Integer> layers, String swamp) { this(name, layers, swamp, ByteString.EMPTY); } public Ogre(String name, List<Integer> layers, String swamp, ByteString unknownFields) { super(ADAPTER, unknownFields); this.name = name; this.layers = Internal.immutableCopyOf("layers", layers); this.swamp = swamp; } ByteString.EMPTY ByteString unknownFields

slide-19
SLIDE 19

public final String name; public final List<Integer> layers; public final String swamp; public Ogre(String name, List<Integer> layers, String swamp) { this(name, layers, swamp, ByteString.EMPTY); } public Ogre(String name, List<Integer> layers, String swamp, ByteString unknownFields) { super(ADAPTER, unknownFields); this.name = name; this.layers = Internal.immutableCopyOf("layers", layers); this.swamp = swamp; } Internal.immutableCopyOf("layers", layers)

slide-20
SLIDE 20

public final String name; public final List<Integer> layers; public final String swamp; public Ogre(String name, List<Integer> layers, String swamp) { this(name, layers, swamp, ByteString.EMPTY); } public Ogre(String name, List<Integer> layers, String swamp, ByteString unknownFields) { super(ADAPTER, unknownFields); this.name = name; this.layers = Internal.immutableCopyOf("layers", layers); this.swamp = swamp; } String name String swamp String name String swamp String name String swamp

slide-21
SLIDE 21

public final String name; public final List<Integer> layers; public final String swamp; public Ogre(String name, List<Integer> layers, String swamp) { this(name, layers, swamp, ByteString.EMPTY); } public Ogre(String name, List<Integer> layers, String swamp, ByteString unknownFields) { super(ADAPTER, unknownFields); this.name = name; this.layers = Internal.immutableCopyOf("layers", layers); this.swamp = swamp; }

slide-22
SLIDE 22

class Ogre @JvmOverloads constructor( val name: String, val layers: List<Int>, val swamp: String?, unknownFields: ByteString = ByteString.EMPTY ) : Message<Ogre, Ogre.Builder>(ADAPTER, unknownFields)

slide-23
SLIDE 23

class Ogre @JvmOverloads constructor( val name: String, val layers: List<Int>, val swamp: String?, unknownFields: ByteString = ByteString.EMPTY ) : Message<Ogre, Ogre.Builder>(ADAPTER, unknownFields) val name: String, val layers: List<Int>, val swamp: String?, Ogre shrek = new Ogre("Shrek", Arrays.asList(1, 2), null); System.out.println(shrek.getSwamp()); s

slide-24
SLIDE 24

class Ogre @JvmOverloads constructor( @JvmField val name: String, @JvmField val layers: List<Int>, @JvmField val swamp: String?, unknownFields: ByteString = ByteString.EMPTY ) : Message<Ogre, Ogre.Builder>(ADAPTER, unknownFields) @JvmField val name: String, @JvmField val layers: List<Int>, @JvmField val swamp: String?, Ogre shrek = new Ogre("Shrek", Arrays.asList(1, 2), null); System.out.println(shrek.swamp); Se

slide-25
SLIDE 25
  • verride fun equals(other: Any?): Boolean {

if (other === this) return true if (other !is OgreKt) return false val o = other as OgreKt? return (unknownFields() == o!!.unknownFields() && name == o.name && layers == o.layers && Internal.equals(swamp, o.swamp)) }

  • verride fun hashCode(): Int {

var result = super.hashCode if (result == 0) { result = unknownFields().hashCode() result = result * 37 + name.hashCode() result = result * 37 + layers.hashCode() result = result * 37 + (swamp?.hashCode() ?: 0) super.hashCode = result } return result }

  • verride fun toString(): String {

val builder = StringBuilder() builder.append(", name=").append(name) if (!layers.isEmpty()) builder.append(", layers=").append(layers) if (swamp != null) builder.append(", swamp=").append(swamp) return builder.replace(0, 2, "Ogre{").append('}').toString() }

slide-26
SLIDE 26

class Ogre @JvmOverloads constructor( @JvmField val name: String, @JvmField val layers: List<Int>, @JvmField val swamp: String?, unknownFields: ByteString = ByteString.EMPTY ) : Message<Ogre, Ogre.Builder>(ADAPTER, unknownFields)

slide-27
SLIDE 27

data class Ogre @JvmOverloads constructor( @JvmField val name: String, @JvmField val layers: List<Int>, @JvmField val swamp: String?, unknownFields: ByteString = ByteString.EMPTY ) : Message<Ogre, Ogre.Builder>(ADAPTER, unknownFields)

slide-28
SLIDE 28

data class Ogre @JvmOverloads constructor( @JvmField val name: String, @JvmField val layers: List<Int>, @JvmField val swamp: String?, unknownFields: ByteString = ByteString.EMPTY ) : Message<Ogre, Ogre.Builder>(ADAPTER, unknownFields) data class Ogre unknownFields: ByteString = ByteString.EMPTY

slide-29
SLIDE 29

data class Ogre @JvmOverloads constructor( @JvmField val name: String, @JvmField val layers: List<Int>, @JvmField val swamp: String?, private val unknownFields: ByteString = ByteString.EMPTY ) : Message<Ogre, Ogre.Builder>(ADAPTER, unknownFields) data class Ogre private val unknownFields: ByteString = ByteString.EMPTY

slide-30
SLIDE 30

class Ogre @JvmOverloads constructor( @JvmField val name: String, @JvmField val layers: List<Int>, @JvmField val swamp: String?, unknownFields: ByteString = ByteString.EMPTY ) : Message<Ogre, Ogre.Builder>(ADAPTER, unknownFields)

slide-31
SLIDE 31

public static final class Builder extends Message.Builder<Ogre, Builder> { public String name; public List<Integer> layers; public String swamp; public Builder() { layers = Internal.newMutableList(); } public Builder name(String name) { this.name = name; return this; } public Builder layers(List<Integer> layers) { Internal.checkElementsNotNull(layers); this.layers = layers; return this; } public Builder swamp(String swamp) { this.swamp = swamp; return this; } @Override public Ogre build() { if (name == null) { throw Internal.missingRequiredFields(name, "name"); } return new Ogre(name, layers, swamp, super.buildUnknownFields()); } }

slide-32
SLIDE 32

public static final class Builder extends Message.Builder<Ogre, Builder> { public String name; public List<Integer> layers; public String swamp; public Builder() { layers = Internal.newMutableList(); } public Builder name(String name) { this.name = name; return this; } public Builder layers(List<Integer> layers) { Internal.checkElementsNotNull(layers); this.layers = layers; return this; } public Builder swamp(String swamp) { this.swamp = swamp; return this; } @Override public Ogre build() { if (name == null) { throw Internal.missingRequiredFields(name, "name"); } return new Ogre(name, layers, swamp, super.buildUnknownFields()); } } Internal.checkElementsNotNull(layers); if (name == null) { throw Internal.missingRequiredFields(name, "name"); }

slide-33
SLIDE 33

public static final class Builder extends Message.Builder<Ogre, Builder> { public String name; public List<Integer> layers; public String swamp; public Builder() { layers = Internal.newMutableList(); } public Builder name(String name) { this.name = name; return this; } public Builder layers(List<Integer> layers) { Internal.checkElementsNotNull(layers); this.layers = layers; return this; } public Builder swamp(String swamp) { this.swamp = swamp; return this; } @Override public Ogre build() { if (name == null) { throw Internal.missingRequiredFields(name, "name"); } return new Ogre(name, layers, swamp, super.buildUnknownFields()); } }

slide-34
SLIDE 34

class Ogre @JvmOverloads constructor( @JvmField val name: String, @JvmField val layers: List<Int> @JvmField val swamp: String? unknownFields: ByteString = ByteString.EMPTY ) : Message<Ogre, Ogre.Builder>(ADAPTER, unknownFields) @JvmField val name: String, @JvmField val layers: List<Int> = emptyList(), @JvmField val swamp: String? = null,

slide-35
SLIDE 35

val shrek = Ogre( name = "shrek", layers = listOf(1, 2), swamp = null )

slide-36
SLIDE 36

Ogre shrek = new Ogre();

slide-37
SLIDE 37

Ogre shrek = new Ogre("Shrek", Arrays.asList(1, 2), "Shrek");

slide-38
SLIDE 38

Java Interop

slide-39
SLIDE 39

class Ogre( @JvmField val name: String, @JvmField val layers: List<Int> = emptyList(), @JvmField val swamp: String? = null ) interface @JvmField val name: String, @JvmField val layers: List<Int> = emptyList(), @JvmField val swamp: String? = null

slide-40
SLIDE 40

interface Ogre { val name: String val layers: List<Int> val swamp: String? }

slide-41
SLIDE 41

interface Ogre { val name: String val layers: List<Int> val swamp: String? } shrek.getLayers();

slide-42
SLIDE 42

inline fun <reified T> Ogre.findFriendOfType(): T? { for (friend in friends()) { if (friend is T) return friend } return null }

slide-43
SLIDE 43

inline fun <reified T> Ogre.findFriendOfType(): T? { for (friend in friends()) { if (friend is T) return friend } return null }
 
 shrek.findFriendOfType<Donkey>()

slide-44
SLIDE 44

inline fun <reified T> Ogre.findFriendOfType(): T? { for (friend in friends()) { if (friend is T) return friend } return null }
 
 shrek.findFriendOfType<Donkey>() shrek.<Donkey>findFriendOfType();

slide-45
SLIDE 45

inline fun <reified T> Ogre.findFriendOfType(): T? { for (friendain friends()) { if (friend is T) return friend }Y returnbnull }Z

slide-46
SLIDE 46

fun <T> Ogre.findFriendOfType(type: Class<T>): T? { for (friend in friends()) { if (type.isInstance(friend)) return friend as T? }B return null }A inline fun <reified T> Ogre.findFriendOfType(): T? { for (friendain friends()) { if (friend is T) return friend }Y returnbnull }Z findFriendOfType( ::class.java)

slide-47
SLIDE 47

fun <T> Ogre.findFriendOfType(type: Class<T>): T? { for (friend in friends()) { if (type.isInstance(friend)) return friend as T? }B return null }A inline fun <reified T> Ogre.findFriendOfType(): T? { returnbfindFriendOfType(T::class.java) }Z

slide-48
SLIDE 48

interface SwampChangedListener { fun swampChanged(newSwamp: String) } fun addSwampChangedListener(listener: SwampChangedListener) = …

slide-49
SLIDE 49

interface SwampChangedListener { fun swampChanged(newSwamp: String) }A fun addSwampChangedListener(listener: SwampChangedListener) = … shrek.addSwampChangedListener(new SwampChangedListener() { @Override public void swampChanged(@NotNull String newSwamp) {P System.out.println("What are you doing in " + newSwamp); } });

slide-50
SLIDE 50

interface SwampChangedListener { fun swampChanged(newSwamp: String) }A fun addSwampChangedListener(listener: SwampChangedListener) = … shrek.addSwampChangedListener(newSwamp -> {P System.out.println("What are you doing in " + newSwamp); });

slide-51
SLIDE 51

interface SwampChangedListener { fun swampChanged(newSwamp: String) } fun addSwampChangedListener(listener: SwampChangedListener) = …

slide-52
SLIDE 52

interface SwampChangedListener { fun swampChanged(newSwamp:(String): Unit } fun addSwampChangedListener(listener: SwampChangedListener) = … shrek.addSwampChangedListener(object : SwampChangedListener {

  • verride fun swampChanged(newSwamp: String) {

System.out.println("What are you doing in $newSwamp") } })

KT-7770

slide-53
SLIDE 53

fun addSwampChangedListener(listener: (String) -> Unit) = …

slide-54
SLIDE 54

fun addSwampChangedListener(listener: (String) -> Unit) = … shrek.addSwampChangedListener { newSwamp -> System.out.println("What are you doing in $newSwamp") }

slide-55
SLIDE 55

fun addSwampChangedListener(listener: (String) -> Unit) = … shrek.addSwampChangedListener { newSwamp -> System.out.println("What are you doing in $newSwamp") } shrek.addSwampChangedListener(newSwamp -> { System.out.println("What are you doing in " + newSwamp); return Unit.INSTANCE; });

KT-21018

slide-56
SLIDE 56

fun addSwampChangedListener(listener: SwampChangedListener) = … public interface SwampChangedListener { void swampChanged(String newSwamp); }Z

slide-57
SLIDE 57

fun addSwampChangedListener(listener: SwampChangedListener) = … shrek.addSwampChangedListener(SwampChangedListener { newSwamp -> System.out.println("What are you doing in $newSwamp") }) public interface SwampChangedListener { void swampChanged(String newSwamp); }Z

slide-58
SLIDE 58

fun addSwampChangedListener(listener: SwampChangedListener) = … public interface SwampChangedListener { void swampChanged(String newSwamp); }Z shrek.addSwampChangedListener(newSwamp -> { System.out.println("What are you doing in " + newSwamp); }); shrek.addSwampChangedListener(SwampChangedListener { newSwamp -> System.out.println("What are you doing in $newSwamp") })

slide-59
SLIDE 59

sealed class Optional<T : Any> data class Some<T : Any>(val value: T): Optional<T>()

  • bject None : Optional<Nothing>()
slide-60
SLIDE 60

sealed class Optional<T : Any> data class Some<T : Any>(val value: T): Optional<T>()

  • bject None : Optional<Nothing>()

fun <T : Any> T?.asOptional() = if (this == null) None else Some(this)

slide-61
SLIDE 61

@file:JvmName("Optionals") sealed class Optional<T : Any> data class Some<T : Any>(val value: T): Optional<T>()

  • bject None : Optional<Nothing>()

@JvmName("ofNullable") fun <T : Any> T?.asOptional() = if (this == null) None else Some(this)

slide-62
SLIDE 62

sealed class Optional<T : Any> { companion object { @JvmName("ofNullable") @JvmStatic fun <T : Any> T?.asOptional() = if (this == null) None else Some(this) }Y }Z data class Some<T : Any>(val value: T): Optional<T>()

  • bject None : Optional<Nothing>()

KT-15286

@file:JvmName("Optionals")

slide-63
SLIDE 63

sealed class Optional<T : Any> { companion object { @JvmStatic fun <T : Any> ofNullable(value: T?) = value.asOptional() }Y }Z data class Some<T : Any>(val value: T): Optional<T>()

  • bject None : Optional<Nothing>()

fun <T : Any> T?.asOptional() = if (this == null) None else Some(this)

KT-15286

@JvmName

slide-64
SLIDE 64

@file:JvmName("-Optionals") sealed class Optional<T : Any> { companion object { @JvmStatic fun <T : Any> ofNullable(value: T?) = value.asOptional() }Y }Z data class Some<T : Any>(val value: T): Optional<T>()

  • bject None : Optional<Nothing>()

fun <T : Any> T?.asOptional() = if (this == null) None else Some(this)

KT-15286

slide-65
SLIDE 65

class Foo ( val bar: Nothing, val listBar: List<Nothing> )

slide-66
SLIDE 66

class Foo ( val bar: Nothing, val listBar: List<Nothing> ) Void bar = foo.getBar(); List listBar = foo.getListBar();

slide-67
SLIDE 67

KotlinPoet

slide-68
SLIDE 68

Type

slide-69
SLIDE 69

Type Class

slide-70
SLIDE 70

Type Class Parameterized Type

slide-71
SLIDE 71

Type

String Map<String,Int>

slide-72
SLIDE 72

val stringClass: KClass<String> = String::class

slide-73
SLIDE 73

val stringClass: KClass<String> = String::class val stringName: ClassName = stringClass.asClassName()

slide-74
SLIDE 74

val stringClass: KClass<String> = String::class val stringName: ClassName = stringClass.asClassName() import kotlin.String val foo: String = ""

slide-75
SLIDE 75

val stringClass: KClass<String> = String::class val stringName: ClassName = stringClass.asClassName() import kotlin.String val foo: String = "" class String

slide-76
SLIDE 76

val stringClass: KClass<String> = String::class val stringName: ClassName = stringClass.asClassName() class String { val foo: kotlin.String = "" }

slide-77
SLIDE 77

val stringClass: KClass<String> = String::class val stringName: ClassName = stringClass.asClassName()

slide-78
SLIDE 78

val stringClass: KClass<String> = String::class val stringName: ClassName = stringClass.asClassName() val mapStringToInt = ParameterizedTypeName.get( Map::class.asTypeName(), stringName, Int::class.asTypeName())

slide-79
SLIDE 79

val stringClass: KClass<String> = String::class val stringName: ClassName = stringClass.asClassName() val mapStringToInt = ParameterizedTypeName.get( Map::class.asTypeName(), stringName, Int::class.asTypeName()) val nullableMap = mapStringToInt.asNullable()

slide-80
SLIDE 80

val foo = PropertySpec.builder("foo", String::class) .initializer("%S", "foo") .build()

slide-81
SLIDE 81

val foo = PropertySpec.builder("foo", String::class) .initializer("%S", "foo") .build() String::class

slide-82
SLIDE 82

val foo = PropertySpec.builder("foo", String::class) .initializer("%S", "foo") .build() "%S", "foo"

slide-83
SLIDE 83

val foo = PropertySpec.builder("foo", String::class) .initializer("%S", "foo") .build()

slide-84
SLIDE 84

val foo = PropertySpec.builder("foo", String::class) .initializer("%S", "foo") .build() println(foo) val foo: kotlin.String = "foo"X

slide-85
SLIDE 85

val foo = PropertySpec.builder("foo", String::class) .initializer("%S", "foo\tbar") .build() println(foo) val foo: kotlin.String = "foo\tbar"X

slide-86
SLIDE 86

val foo = PropertySpec.builder("foo", String::class) .initializer("%S", "foo\tbar") .build() println(foo) val foo: kotlin.String = "foo\tbar"X kotlin.String

slide-87
SLIDE 87

val foo = PropertySpec.builder("foo", String::class) .initializer("%S", "foo\tbar") .build() val file = FileSpec.builder("com.example", "KotlinConf.kt") .addProperty(foo) .build() println(file) package com.example import kotlin.String val foo: String = "foo\tbar"X foo

slide-88
SLIDE 88

PropertySpec.builder("foo", String::class) .initializer("%S", "foo\tbar") .build() package com.example import kotlin.String val foo: String = "foo\tbar"X

slide-89
SLIDE 89

FunSpec.builder("main") .addParameter("args", String::class, VARARG) .build() package com.example import kotlin.String fun main(vararg args: String) { }

slide-90
SLIDE 90

TypeSpec.classBuilder("User") .addModifiers(DATA) .build() package com.example data class User

slide-91
SLIDE 91

TypeSpec.classBuilder("User") .addModifiers(DATA) .build() package com.example data class User

slide-92
SLIDE 92

TypeSpec.classBuilder("User") .addModifiers(DATA) .addProperty(PropertySpec.builder("name", String::class).build()) .build()Z package com.example data class User {Y val name: String }X

slide-93
SLIDE 93

TypeSpec.classBuilder("User") .addModifiers(DATA) .addProperty(PropertySpec.builder("name", String::class).build()) .primaryConstructor(FunSpec.constructorBuilder() .addParameter("name", String::class) .build())A .build()Z package com.example data class User(name: String)G{Y val name: String }X

slide-94
SLIDE 94

name: String TypeSpec.classBuilder("User") .addModifiers(DATA) .addProperty(PropertySpec.builder("name", String::class) .initializer("name") .build())B .primaryConstructor(FunSpec.constructorBuilder() .addParameter("name", String::class) .build())A .build() package com.example data class User(val name: String)G

slide-95
SLIDE 95

TypeSpec.classBuilder("User") .addModifiers(DATA) .addProperty(PropertySpec.builder("name", String::class) .initializer("name.toLowerCase()") .build())B .primaryConstructor(FunSpec.constructorBuilder() .addParameter("name", String::class) .build())A .build() package com.example data class User(name: String)G{ val name: String = name.toLowerCase() }X

slide-96
SLIDE 96

FunSpec.builder("seconds") .receiver(Long::class) .returns(Duration::class) .addStatement("return %T.ofSeconds(this)", Duration::class) .build() package com.example import java.time.Duration import kotlin.Long fun Long.seconds(): Duration = Duration.ofSeconds(this)

slide-97
SLIDE 97

FunSpec.builder("seconds") .receiver(Long::class) .returns(Duration::class) .addStatement("require(this >= 0L)") .addStatement("return %T.ofSeconds(this)", Duration::class) .build() package com.example import java.time.Duration import kotlin.Long fun Long.seconds(): Duration { require(this >= 0L) return Duration.ofSeconds(this) }

slide-98
SLIDE 98

FunSpec.builder("seconds") .receiver(Long::class) .returns(Duration::class) .addStatement("require(this >= 0L)") .addStatement("return %T.ofSeconds(this)", Duration::class) .build()

slide-99
SLIDE 99

val longSeconds = FunSpec.builder("seconds") .receiver(Long::class) .returns(Duration::class) .addStatement("require(this >= 0L)") .addStatement("return %T.ofSeconds(this)", Duration::class) .build()

slide-100
SLIDE 100

val longSeconds = FunSpec.builder("seconds") .receiver(Long::class) .returns(Duration::class) .addStatement("require(this >= 0L)") .addStatement("return %T.ofSeconds(this)", Duration::class) .build() FunSpec.builder("main") .addParameter("args", String::class, VARARG) .addStatement("println(%L.%N())", 2L, longSeconds) .build()

slide-101
SLIDE 101

val longSeconds = FunSpec.builder("seconds") .receiver(Long::class) .returns(Duration::class) .addStatement("require(this >= 0L)") .addStatement("return %T.ofSeconds(this)", Duration::class) .build() FunSpec.builder("main") .addParameter("args", String::class, VARARG) .addStatement("println(%L.%N())", 2L, longSeconds) .build() %N longSeconds

slide-102
SLIDE 102

val longSeconds = FunSpec.builder("seconds") .receiver(Long::class) .returns(Duration::class) .addStatement("require(this >= 0L)") .addStatement("return %T.ofSeconds(this)", Duration::class) .build() FunSpec.builder("main") .addParameter("args", String::class, VARARG) .addStatement("println(%L.%N())", 2L, longSeconds) .build() fun main(vararg args: String) { println(2L.seconds()) }

slide-103
SLIDE 103

val code = CodeBlock.builder()

slide-104
SLIDE 104

val code = CodeBlock.builder() code.addStatement("val foo = %T.MIN_VALUE", Int::class)

slide-105
SLIDE 105

val code = CodeBlock.builder() code.addStatement("val foo = %T.MIN_VALUE", Int::class) code.add("val bar = ") when (answer) { YES -> code.add("0L") NO -> code.add("%T.MIN_VALUE", Int::class) } code.add(".toString()\n")

slide-106
SLIDE 106

val code = CodeBlock.builder() code.addStatement("val foo = %T.MIN_VALUE", Int::class) code.add("val bar = ") when (answer) { YES -> code.add("0L") NO -> code.add("%T.MIN_VALUE", Int::class) } code.add(".toString()\n") code.beginControlFlow("if (bar.isEmpty())") .addStatement("println(%S)", "Empty!") .nextControlFlow("else") .addStatement("println(bar)") .endControlFlow()

slide-107
SLIDE 107

val intMin = CodeBlock.of("%T.MIN_VALUE", Int::class) val intMax = CodeBlock.of("%T.MAX_VALUE", Int::class) val longMin = CodeBlock.of("%T.MIN_VALUE", Long::class) val longMax = CodeBlock.of("%T.MAX_VALUE", Long::class) val values = listOf(intMin, intMax, longMin, longMax)

slide-108
SLIDE 108

val intMin = CodeBlock.of("%T.MIN_VALUE", Int::class) val intMax = CodeBlock.of("%T.MAX_VALUE", Int::class) val longMin = CodeBlock.of("%T.MIN_VALUE", Long::class) val longMax = CodeBlock.of("%T.MAX_VALUE", Long::class) val values = listOf(intMin, intMax, longMin, longMax) // elsewhere val list = values.joinToCode(prefix = "listOf(", suffix = ")")

slide-109
SLIDE 109

val intMin = CodeBlock.of("%T.MIN_VALUE", Int::class) val intMax = CodeBlock.of("%T.MAX_VALUE", Int::class) val longMin = CodeBlock.of("%T.MIN_VALUE", Long::class) val longMax = CodeBlock.of("%T.MAX_VALUE", Long::class) val values = listOf(intMin, intMax, longMin, longMax) // elsewhere val list = values.joinToCode(prefix = "listOf(", suffix = ")") listOf(Int.MIN_VALUE, Int.MAX_VALUE, Long.MIN_VALUE, Long.MAX_VALUE)

slide-110
SLIDE 110

inline fun <reified T, R : CharSequence> (String.() -> R).crazy(noinline foo: T.(R?) -> Unit) where T : Runnable, T : Closeable = 42L

slide-111
SLIDE 111

val typeT = TypeVariableName("T", Runnable::class, Closeable::class) val typeR = TypeVariableName("R", CharSequence::class) val stringExtToR = LambdaTypeName.get(String::class.asClassName(), returnType = typeR) val tRtoUnit = LambdaTypeName.get(typeT, parameters = typeR.asNullable(), returnType = UNIT) val crazy = FunSpec.builder("crazy") .addModifiers(INLINE) .receiver(stringExtToR) .addTypeVariable(typeT.reified()) .addTypeVariable(typeR) .addParameter("foo", tRtoUnit, NOINLINE) .addStatement("return 42L") .build()

inline fun <reified T, R : CharSequence> (String.() -> R).crazy(noinline foo: T.(R?) -> Unit) where T : Runnable, T : Closeable = 42L

slide-112
SLIDE 112

Kotlin Compatible Code

slide-113
SLIDE 113

@Nullable public String getSwamp() { return swamp; }

slide-114
SLIDE 114

@Nullable public String getSwamp() { return swamp; } val swamp: String? = shrek.swamp

slide-115
SLIDE 115

Bytecode

Build tool

slide-116
SLIDE 116

Bytecode

Build tool

slide-117
SLIDE 117

interface Foo { val bar: String }

slide-118
SLIDE 118

public abstract interface com/sample/Foo { // access flags 0x401 public abstract getBar()Ljava/lang/String; @Lorg/jetbrains/annotations/NotNull;() // invisible LOCALVARIABLE this Lcom/sample/Foo; L0 L1 0 @Lkotlin/Metadata;(
 mv={1, 1, 7},
 bv={1, 0, 2},
 k=1,
 d1={“…”},
 d2={"Lcom/sample/Foo;", "", "bar", "", “getBar" }
 ) // compiled from: Foo.kt }

slide-119
SLIDE 119

public abstract interface com/sample/Foo { // access flags 0x401 public abstract getBar()Ljava/lang/String; @Lorg/jetbrains/annotations/NotNull;() // invisible LOCALVARIABLE this Lcom/sample/Foo; L0 L1 0 @Lkotlin/Metadata;(
 mv={1, 1, 7},
 bv={1, 0, 2},
 k=1,
 d1={“…”},
 d2={"Lcom/sample/Foo;", "", "bar", "", “getBar" }
 ) // compiled from: Foo.kt }

goo.gl/GcT9gz

slide-120
SLIDE 120

github.com/Takhion/kotlin-metadata

  • rg.jetbrains.kotlin.serialization.ProtoBuf.Class
slide-121
SLIDE 121

github.com/Takhion/kotlin-metadata

  • rg.jetbrains.kotlin.serialization.ProtoBuf.Class
slide-122
SLIDE 122

github.com/Takhion/kotlin-metadata

  • rg.jetbrains.kotlin.serialization.ProtoBuf.Class
slide-123
SLIDE 123

github.com/Takhion/kotlin-metadata

  • rg.jetbrains.kotlin.serialization.ProtoBuf.Class
slide-124
SLIDE 124

github.com/Takhion/kotlin-metadata

  • rg.jetbrains.kotlin.serialization.ProtoBuf.Class
slide-125
SLIDE 125

github.com/Takhion/kotlin-metadata

  • rg.jetbrains.kotlin.serialization.ProtoBuf.Class
slide-126
SLIDE 126

public abstract interface com/sample/Foo { // access flags 0x401 public abstract getBar()Ljava/lang/String; @Lorg/jetbrains/annotations/NotNull;() // invisible LOCALVARIABLE this Lcom/sample/Foo; L0 L1 0 @Lkotlin/Metadata;(
 mv={1, 1, 7},
 bv={1, 0, 2},
 k=1,
 d1={“…”},
 d2={"Lcom/sample/Foo;", "", "bar", "", “getBar" }
 ) // compiled from: Foo.kt }

slide-127
SLIDE 127

Bytecode

slide-128
SLIDE 128

Bytecode

slide-129
SLIDE 129

public abstract interface com/sample/Foo { // access flags 0x401 public abstract getBar()Ljava/lang/String; @Lorg/jetbrains/annotations/NotNull;() // invisible LOCALVARIABLE this Lcom/sample/Foo; L0 L1 0 @Lkotlin/Metadata;(
 mv={1, 1, 7},
 bv={1, 0, 2},
 k=1,
 d1={“…”},
 d2={"Lcom/sample/Foo;", "", "bar", "", “getBar" }
 )g // compiled from: Foo.kt }A

slide-130
SLIDE 130 public abstract interface com/sample/Foo { // access flags 0x401 public abstract getBar()Ljava/lang/String; @Lorg/jetbrains/annotations/NotNull;() // invisible LOCALVARIABLE this Lcom/sample/Foo; L0 L1 0 @Lkotlin/Metadata;(
 mv={1, 1, 7},
 bv={1, 0, 2},
 k=1,
 d1={“…”},
 d2={"Lcom/sample/Foo;", "", "bar", "", “getBar" }
 )g // compiled from: Foo.kt }A
slide-131
SLIDE 131 public abstract interface com/sample/Foo { // access flags 0x401 public abstract getBar()Ljava/lang/String; @Lorg/jetbrains/annotations/NotNull;() // invisible LOCALVARIABLE this Lcom/sample/Foo; L0 L1 0 @Lkotlin/Metadata;(
 mv={1, 1, 7},
 bv={1, 0, 2},
 k=1,
 d1={“…”},
 d2={"Lcom/sample/Foo;", "", "bar", "", “getBar" }
 ) // compiled from: Foo.kt } {A AnnotationVisitor av1 = av0.visitArray("d2"); av1.visit(null, "Lcom/sample/Foo;"); av1.visit(null, ""); av1.visit(null, "bar"); av1.visit(null, ""); av1.visit(null, "getBar"); av1.visit(null, "()I"); av1.visitEnd(); }B {C mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "getBar", "()I", null, null); mv.visitEnd(); }D
slide-132
SLIDE 132

{A AnnotationVisitor av1 = av0.visitArray("d2"); av1.visit(null, "Lcom/sample/Foo;"); av1.visit(null, ""); av1.visit(null, "bar"); av1.visit(null, ""); av1.visit(null, "getBar"); av1.visit(null, "()I"); av1.visitEnd(); }B {C mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "getBar", "()I", null, null); mv.visitEnd(); }D b b

slide-133
SLIDE 133

{A AnnotationVisitor av1 = av0.visitArray("d2"); av1.visit(null, "Lcom/sample/Foo;"); av1.visit(null, ""); av1.visit(null, "bar"); av1.visit(null, ""); av1.visit(null, "bar"); av1.visit(null, "()I"); av1.visitEnd(); }B {C mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "bar", "()I", null, null); mv.visitEnd(); }D

slide-134
SLIDE 134 {A AnnotationVisitor av1 = av0.visitArray("d2"); av1.visit(null, "Lcom/sample/Foo;"); av1.visit(null, ""); av1.visit(null, "bar"); av1.visit(null, ""); av1.visit(null, "bar"); av1.visit(null, "()I"); av1.visitEnd(); }B {C mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "bar", "()I", null, null); mv.visitEnd(); }D
slide-135
SLIDE 135 { AnnotationVisitor av1 = av0.visitArray("d2"); av1.visit(null, "Lcom/sample/Foo;"); av1.visit(null, ""); av1.visit(null, "bar"); av1.visit(null, ""); av1.visit(null, "bar"); av1.visit(null, "()I"); av1.visitEnd(); } { mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "bar", "()I", null, null); mv.visitEnd(); } public abstract interface com/sample/Foo { // access flags 0x401 public abstract bar()Ljava/lang/String; @Lorg/jetbrains/annotations/NotNull;() // invisible LOCALVARIABLE this Lcom/sample/Foo; L0 L1 0 @Lkotlin/Metadata;(
 mv={1, 1, 7},
 bv={1, 0, 2},
 k=1,
 d1={“…”},
 d2={"Lcom/sample/Foo;", "", "bar", "", “bar” }
 ) // compiled from: Foo.kt }
slide-136
SLIDE 136

class KotlinFoo(override val bar: Int): Foo
 
 class JavaFoo implements Foo { @Override public int bar() { return 0; } }

slide-137
SLIDE 137

void setPadding(int l, int t, int r, int b) { // … }

slide-138
SLIDE 138

void setPadding(int l, int t, int r, int b) { // … }z view.setPadding(10, 0, 0, 10)

slide-139
SLIDE 139

void setPadding(int l, int t, int r, int b) { // … }z view.setPadding(left = 10, bottom = 10)

slide-140
SLIDE 140

Bytecode

slide-141
SLIDE 141

Multiplatform

slide-142
SLIDE 142

Bytecode

slide-143
SLIDE 143

Bytecode

slide-144
SLIDE 144

Bytecode

LLVM

slide-145
SLIDE 145

enum class Direction { NORTH, SOUTH, EAST, WEST } class GamePeice( movement: Set<Direction> = EnumSet.of(Direction.NORTH) )Z

slide-146
SLIDE 146

enum class Direction { NORTH, SOUTH, EAST, WEST } class GamePeice( movement: Set<Direction> = EnumSet.of(Direction.NORTH) )Z EnumSet.of

slide-147
SLIDE 147

import java.util.EnumSet enum class Direction { NORTH, SOUTH, EAST, WEST } class GamePeice( movement: Set<Direction> = EnumSet.of(Direction.NORTH) )Z s O EnumSet.of

slide-148
SLIDE 148

enum class Direction { NORTH, SOUTH, EAST, WEST } class GamePeice( movement: Set<Direction> = setOf(Direction.NORTH) )Z S o

slide-149
SLIDE 149

import com.google.common.collect @AutoImplement interface Party { val people: ImmutableList<Person> }

slide-150
SLIDE 150

import com.google.common.collect @AutoImplement interface Party { val people: ImmutableList<Person> } import com.google.common.collect @Generated class AutoParty(override val people: ImmutableList<Person>) : Party

slide-151
SLIDE 151

CREATE TABLE user( name TEXT NOT NULL, location TEXT AS android.location.Location )

slide-152
SLIDE 152

CREATE TABLE user( name TEXT NOT NULL, location TEXT AS android.location.Location ) import android.location.Location data class User( val name: String, val location: Location )

slide-153
SLIDE 153

@file:JvmName("ByteStrings") @JvmName("from") fun ByteArray.asByteString(): ByteString = …

slide-154
SLIDE 154

@file:JvmName("ByteStrings") @JvmName("from") fun ByteArray.asByteString(): ByteString = … byte[] bytes = … ByteString b = ByteStrings.from(bytes);

slide-155
SLIDE 155

@file:JvmName("ByteStrings") @JvmName("from") fun ByteArray.asByteString(): ByteString = … byte[] bytes = … ByteString b = ByteStrings.from(bytes); Cannot access 'JvmName': it is internal in 'kotlin.jvm'

KT-19507

s

slide-156
SLIDE 156

@JsName("from") fun ByteArray.asByteString(): ByteString = … @file:JvmName("ByteStrings")

slide-157
SLIDE 157

@JsName("from") fun ByteArray.asByteString(): ByteString = … @file:JvmName("ByteStrings")

KT-19508

slide-158
SLIDE 158

Verbosity is okay. API is the #1 priority.

slide-159
SLIDE 159

Verbosity is okay. API is the #1 priority. If you do any kind of Java codegen, keep Kotlin in mind.

slide-160
SLIDE 160

Verbosity is okay. API is the #1 priority. If you do any kind of Java codegen, keep Kotlin in mind. Don’t depend on platform types unless the user does.

slide-161
SLIDE 161

KotlinPoet 0.6.0 released!

slide-162
SLIDE 162

@Strongolopolis & @JakeWharton

Kotlin Code Generation