2. What is Kotlin?
• Statically typed
• JVM-targeted
• general-purpose programming language
• developed by JetBrains
➡ intended for industrial use
• Docs available today
• Public preview version coming soon
2
3. Motivation: our situation
• Huge Java codebase (>50k classes, 10
years old)
• Want a modern expressive language
➡ that's easy to use with what we have
• Need efficient tooling
• None of the existing languages
was a good fit
3
4. Design goals
• Full Java interoperability
• Compiles as fast as Java
• More concise than Java
• Prevents more errors than Java
• Way simpler than Scala
4
5. Innovation
• Not a research project
• Focus on common sence
• Learning from others
➡ Groovy, C#, Scala, Gosu...
5
6. Tooling
• Compiler
➡ Open Source, Apache 2
• IntelliJ IDEA plugin
➡ Developed in parallel with the compiler
➡ Open Source
• Basic Eclipse plugin
➡ Open Source
10
14. join() and iterate()
fun <T> Iterable<T>.join(separator : String) : String {
val names = StringBuilder()
this.iterate { name, hasNext =>
names += name
if (hasNext)
names += separator
}
return names.toString()
}
fun <T> Iterable<T>.iterate(f : fun(T, Boolean)) {
val it = iterator()
while (it.hasNext()) {
f(it.next(), it.hasNext())
}
}
14
15. Null-safety
fun parseInt(s : String) : Int? {
try {
return Integer.parseInt(s)
} catch (e : NumberFormatException) {
return null
}
}
fun main(args : Array<String>) {
val x = parseInt("123")
val y = parseInt("Hello")
print(x?.times(2)) // Can't say: print(x * 2)
if (x != null) {
print(x * 2)
}
}
15
16. Mapping to Java types
Kotlin GEN Java LOAD Kotlin
Any Object Any?
Unit void Unit
Int int Int
Int? Integer Int?
String String String?
Array<Foo> Foo[] Array<Foo?>?
IntArray int[] IntArray?
Nothing - -
Foo Foo Foo?
16
17. Mapping to Java types
Kotlin GEN Java LOAD Kotlin
Any Object Any?
Unit void Unit
Int int Int
Int? Integer Int?
String String String?
Array<Foo> Foo[] Array<Foo?>?
IntArray int[] IntArray?
Nothing - -
Foo Foo Foo?
17
18. Mapping to Java types
Kotlin GEN Java LOAD Kotlin
Any Object Any?
Unit void Unit
Int int Int
Int? Integer Int?
String String String?
Array<Foo> Foo[] Array<Foo?>?
IntArray int[] IntArray?
Nothing - -
Foo Foo Foo?
18
19. Smart casts and When
fun foo(obj : Any?) {
if (obj is String) {
obj.substring(2)
}
when (obj) {
is String => obj[0]
is Int => obj + 1
!is Boolean => null
else => ...
}
}
19
20. More on when-expressions
fun bar(x : Int) {
when (x) {
0 => "Zero"
1, 2, 3 => "1, 2 or 3"
x + 1 => "Really strange"
in 10..100 => "In range"
!in 100..1000 => "Out of range"
}
}
20
21. Classes
open class Parent(p : Bar) {
open fun foo() {}
fun bar() {}
}
class Child(p : Bar) : Parent(p) {
override fun foo() {}
}
• Any is the default supertype
• Constructors must initialize supertypes
• Final by default, explicit override annotations
21
22. Traits
trait T1 : Class1, OtherTrait {
// No state
fun foo() : Int = 1 // open by default
fun bar() : Int // abstract by default
}
class Foo(p : Bar) : Class1(p), T1, T2 {
override fun bar() : Int = foo() + 1
}
22
23. Disambiguation
trait A {
fun foo() : Int = 1
}
open class B() {
open fun foo() : Int = 2
}
class C() : B(), A {
override fun foo() = super<A>.foo()
}
23
24. First-class Delegation
trait List<T> {
fun add(t : T)
fun get(index : Int) : T
}
class ListDecorator<T>(p : List<T>) : List<T> by p {
override fun add(t : T) {
log.message("Added $t")
super.add(t)
}
// override fun get(index : Int) : T = p.get()
}
24
25. First-class functions
• Functions
➡ fun f(p : Int) : String
• Function types
➡ fun (p : Int) : String
➡ fun (Int) : String
• Function literals
➡ {p => p.toString()}
➡ {(p : Int) => p.toString()}
➡ {(p : Int) : String => p.toString()}
25
26. Higher-order functions
fun <T> filter(
c : Iterable<T>,
f : fun(T) : Boolean) : Iterable<T>
• filter(list, {s => s.length < 3})
➡ Sugar: last function literal argument
✦ filter(list) {s => s.length < 3}
➡ Sugar: one-parameter function literal
✦ filter(list) { it.length < 3 }
26
27. Infix function calls & "LINQ"
a.contains(b)
// is the same as
a contains b
users
.filter { it hasPrivilege WRITE }
.map { it => it.fullName }
.orderBy { lastName }
27
30. Lock example (III)
inline fun lock(l : Lock, body : fun () : Unit) {
l.lock()
try {
body()
}
finally {
l.unlock()
}
}
30
31. Extension functions
• Functions
➡ fun Foo.f(p : Int) : String
• Function types
➡ fun Foo.(p : Int) : String
➡ fun Foo.(Int) : String
• Function literals
➡ {Foo.(p : Int) => this.toString()}
➡ {Foo.(p : Int) : String => this.toString()}
31
32. Builders in Groovy
html {
head {
title "XML encoding with Groovy"
}
body {
h1 "XML encoding with Groovy"
p "this format can be used as an alternative markup to XML"
/* an element with attributes and text content */
ahref:'http://groovy.codehaus.org' ["Groovy"]
}
}
32
33. Builders in Kotlin
html {
head {
title { +"XML encoding with Kotlin" }
}
body {
h1 { +"XML encoding with Kotlin" }
p { +"this format is now type-safe" }
/* an element with attributes and text content */
a(href="http://jetbrains.com/kotlin") { +"Kotlin" }
}
}
33
34. Builders: Implementation (I)
• Function definition
fun html(init : fun HTML.() : Unit) : HTML {
val html = HTML()
html.init()
return html
}
• Usage
html {
this.head { ... }
}
34
35. Builders: Implementation (II)
• Function definition
fun html(init : fun HTML.() : Unit) : HTML {
val html = HTML()
html.init()
return html
}
• Usage
html {
head { ... }
}
35
36. Builders: Implementation (III)
abstract class Tag(val name : String) : Element {
val children = ArrayList<Element>()
val attributes = HashMap<String, String>()
}
abstract class TagWithText(name : String) : Tag(name) {
fun String.plus() {
children.add(TextElement(this))
}
}
class HTML() : Tag("html") {
fun head(init : fun Head.() : Unit) { }
fun body(init : fun Body.() : Unit) { }
}
36
37. Builders in Kotlin
html {
head {
title { +"XML encoding with Kotlin" }
}
body {
h1 { +"XML encoding with Kotlin" }
p { +"this format is now type-safe" }
/* an element with attributes and text content */
a(href="http://jetbrains.com/kotlin") { +"Kotlin" }
}
}
37
38. Generics: Invariance
class List<T> {
fun add(t : T)
fun get(index : Int) : T
}
val ints = List<Int>()
val anys : List<Any> = ints
anys.add("1") // Cause of the problem
val i : Int = ints.get(0) // !!!
38
39. Generics: Declaration-site variance
class List<T> { List<Int> >:< List<Any>
fun add(t : T) val ints = List<Int>()
fun get() : T val anys : List<Any> = ints
}
class Producer<out T> { val ints = Producer<Int>()
fun get() : T val anys : Producer<Any> = ints
}
class Consumer<in T> { val anys = Consumer<Any>()
fun add(t : T) val ints : Consumer<Int> = anys
}
39
40. Generics: Use-site variance
val ints = List<Int>()
val anysOut : List<out Any> = ints
anysOut.add("1") // Not available
val i : Int = ints.get() // No problem
val anys = List<Any>()
val intsIn : List<in Int> = anys
intsIn.add(0)
val obj = intsIn.get() // : Any?
40
41. Reified generics
• Type information in retained at runtime
➡ foo is List<T>
➡ Array<T>(3)
➡ T.create()
• Java types are still erased
➡ foo is java.util.List<*>
41
42. Class objects (I)
• Classes have no static members
• Each class may have a class object
associated to it:
class Example() {
class object {
fun create() = Example()
}
}
val e = Example.create()
42
43. Class objects (II)
• Class objects can have supertypes:
class Example() {
class object : Factory<Example> {
override fun create() = Example()
}
}
val factory : Factory<Example> = Example
val e : Example = factory.create()
43
44. Class objects (III)
• Generic constraints for class objects:
class Lazy<T>()
where class object T : Factory<T>
{
private var store : T? = null
public val value : T
get() {
if (store == null) {
store = T.create()
}
return store
}
}
44