4. Kotlin Types [kotlin-workshop]

4. Kotlin Types [kotlin-workshop]

Part of https://github.com/jetBrains/kotlin-workshop.

Covers:
- Basic types (primitives)
- Nullable types & Java
- Collections types & Java
- Variance

Recording of this talk (excluding variance):
https://www.youtube.com/watch?list=PLQ176FUIyIUY6UK1cgVsbdPYA3X5WLam5&v=Uizh2WlJtnk

C6997ce411091d4a51ea3caa2109c0b0?s=128

Svetlana Isakova

November 01, 2017
Tweet

Transcript

  1. Kotlin Types: Exposed

  2. Agenda …types…

  3. Agenda • Basic types • Nullable types • Collection types

    &
  4. fun foo(): Int = 1 fun bar(): Int? = 1

    Types under the hood
  5. Under the hood?

  6. Kotlin Bytecode

  7. Kotlin Bytecode

  8. Kotlin Bytecode

  9. public static final int foo() { return 1; } @Nullable

    public static final Integer bar() { return Integer.valueOf(1); } Decompiled Java code
  10. fun foo(): Int = 1 public static final int foo()

    { return 1; } Correspondence between Kotlin and Java types Kotlin code: Decompiled Java code:
  11. public static final Integer bar() { return 1; } Correspondence

    between Kotlin and Java types Kotlin code: Decompiled Java code: fun bar(): Int? = 1
  12. Kotlin Java Int int Int? java.lang.Integer Correspondence between Kotlin and

    Java types
  13. Basic types

  14. Primitive & wrapper types Kotlin Java Int int Double double

    Boolean boolean Kotlin Java Int? java.lang.Integer Double? java.lang.Double Boolean? java.lang.Boolean
  15. Generic arguments Kotlin Java List<Int> List<Integer>

  16. Arrays Kotlin Java Array<Int> Integer[]

  17. Arrays of primitive types Kotlin Java Array<Int> Integer[] IntArray int[]

  18. String Kotlin Java kotlin.String java.lang.String

  19. "one.two.".replace(".".toRegex(), "*") kotlin.String hides some confusing methods "one.two.".replaceAll(".", "*") ********

    "one.two.".replace(".", "*") one*two*
  20. Any Kotlin Java Any java.lang.Object

  21. User Any Any

  22. Any Int Any User

  23. Boxing under the hood log(2017) fun log(any: Any) { println("Value:

    $any") } the value is autoboxed
  24. No boxing now log(2017) fun log(any: Any) { println("Value: $any")

    } fun log(i: Int) { println("Value: $i") }
  25. Unit vs Nothing vs void ?

  26. Unit instead of void No meaningful value is returned fun

    f(): Unit { /*...*/ } Two equivalent syntactic forms: fun f() { /*...*/ }
  27. Unit Kotlin Java Unit void

  28. Nothing is different to Unit/void fun fail(message: String): Nothing {


    throw IllegalStateException(message)
 } It means “this function never returns”
  29. “a type that allows only one value and thus can

    hold no information” Unit Nothing “a type that has no values” “the function completes successfully” “the function never completes”
  30. Any & Nothing types Int Any Unit Nothing

  31. Expressions of Nothing type inline fun TODO(reason: String): Nothing =

    throw NotImplementedError("An operation is not implemented: $reason") val answer: Int = if (timeHasPassed()) { 42 } else { TODO("Needs to be done") }
  32. fun greetPerson(person: Person) { val name: String = person.name ?:

    throw IllegalArgumentException("Name is unspecified") println("Hello, $name!") } Expressions of Nothing type
  33. fun greetPerson(person: Person) { val name = person.name ?: fail("Name

    is unspecified") println("Hello, $name!") } Expressions of Nothing type
  34. fun greetPerson(person: Person) { val name = person.name ?: return

    println("Hello, $name!") } Expressions of Nothing type
  35. val answer = if (timeHasPassed()) { 42 } else {

    fail("Not ready") } fun fail(message: String) {
 throw IllegalStateException(message)
 } Let’s say, fail function returns Unit Int Unit Any : Unit
  36. val answer: Any = if (timeHasPassed()) { 42 } else

    { fail("Not ready") } fun fail(message: String) {
 throw IllegalStateException(message)
 } Int Any Unit Let’s say, fail function returns Unit
  37. val answer = if (timeHasPassed()) { 42 } else {

    fail("Not ready") } fun fail(message: String): Nothing {
 throw IllegalStateException(message)
 } Now, fail returns Nothing
  38. val answer = if (timeHasPassed()) { 42 } else {

    fail("Not ready") } fun fail(message: String): Nothing {
 throw IllegalStateException(message)
 } Int Nothing Now, fail returns Nothing
  39. val answer: Int = if (timeHasPassed()) { 42 } else

    { fail("Not ready") } fun fail(message: String): Nothing {
 throw IllegalStateException(message)
 } Nothing Int Now, fail returns Nothing
  40. Nothing Kotlin Java Nothing void because we don’t have Nothing

    at JVM
  41. Any & Nothing types Int Any User Nothing

  42. Type hierarchy Any Nothing User Any? Nothing? Int? User? Int

  43. Type hierarchy Any Nothing User Any? Nothing? Int? User? Int

    ?
  44. Type of null var user = null user = User("svtk")

    val users = mutableListOf(null) users.add(User("svtk")) Error: Type mismatch: inferred type is User but Nothing? was expected Error: Type mismatch: inferred type is User but Nothing? was expected
  45. Type of null var user: Nothing? = null user =

    User("svtk") val users: List<Nothing?> = mutableListOf(null) users.add(User("svtk"))
  46. Specify types explicitly var user: User? = null user =

    User("svtk") val users: List<User?> = mutableListOf(null) users.add(User("svtk")) ✓ ✓
  47. Nullable types Java &

  48. Nullable Types Under the Hood @Nullable, @NotNull annotations

  49. @Nullable @NotNull Type Type? Type Type Nullability annotations

  50. Nullability & Java Type behaves like regular Java type ?

  51. Platform type Type Type! type of “unknown” nullability notation, not

    syntax type that came from Java
  52. A bit of history…

  53. The safest approach would be… Type Type? We tried, but

    it didn’t work well
  54. Type? then the code looks like Type And it doesn’t

    really work with generics !! !! !! !! !! !! !! !! !! !! !! !! If
  55. Platform type Type Type! type of “unknown” nullability type that

    came from Java
  56. Pick two • Null-safety • Convenience • Java Interop

  57. Pick two • Null-safety • Convenience • Java Interop Thanks

    to Dr. Ross Tate of Platform types
  58. Platform type in error message public class Session {
 public

    String getDescription()
 } val session = Session()
 val description: Boolean = session.description Compiler error: Type mismatch: inferred type is String! but Boolean was expected
  59. Using Java from Kotlin val session = Session()
 val description

    = session.description
 println(description.length) NullPointerException! public class Session {
 public String getDescription() {
 return null;
 }
 }
  60. How to still prevent NPEs? • Annotate your Java types

    • Specify types explicitly
  61. How to still prevent NPEs? • Annotate your Java types

    • Specify types explicitly
  62. Type @NotNull @Nullable Type Annotate your Java types

  63. Different annotations are supported @Nullable @NotNull JetBrains @Nullable @NonNull Android

    @Nullable @CheckForNull JSR-305 @Nullable @CheckForNull FindBugs @NonNull Lombok ...
  64. Using Java from Kotlin public class Session { @Nullable String

    getDescription() { return null; } } val session = Session() val description = session.description println(description.length) compiler error
  65. Type @NotNull @Nullable Type Annotate your Java types - You

    can specify @NotNull as default, and annotate only @Nullable types - All of them???
  66. Non-null by default (JSR-305) @ParametersAreNonnullByDefault @MyNonnullByDefault

  67. @MyNonnullApi @javax.annotation.Nonnull @TypeQualifierDefault(ElementType.PARAMETER, ...) annotation class MyNonnullByDefault @MyNonnullByDefault package mypackage;

    package-info.java
  68. @MyNonnullByDefault public class Session { public void setDescription(String description) {

    this.description = description; } } @NonNull by default val session = Session() session.setDescription(null) Warning: Expected type doesn’t accept nulls in Java, but the value may be null in Kotlin
  69. Make it an error compileKotlin { kotlinOptions { freeCompilerArgs +=

    "-Xjsr305=strict" } } build.gradle
  70. @MyNonnullByDefault public class Session { public void setDescription(String description) {

    this.description = description; } } @NonNull by default val session = Session() session.setDescription(null) Error: Null can not be a value of a non-null type String
  71. How to still prevent NPEs? • Annotate your Java types

    • Specify types explicitly
  72. Specify types explicitly val session = Session() val description: String?

    = session.description println(description?.length) public class Session {
 public String getDescription() {
 return null;
 }
 } ✓
  73. IllegalStateException: session.description must not be null val session = Session()

    val description: String = session.description public class Session {
 public String getDescription() {
 return null;
 }
 } Specify types explicitly
  74. Intrinsic checks val session = Session() val description: String =

    session.description println(description)
  75. val session = Session() val description: String = session.description println(description)

    Intrinsic checks is generated by the compiler throws an exception if session.description is null Intrinsics.checkExpressionValueIsNotNull( description, "session.description");
  76. public fun foo(s: String) { } Intrinsic checks Intrinsics.checkParameterIsNotNull(s, "s");

  77. How to still prevent NPEs? • Annotate your Java types

    • Specify types explicitly
  78. Nullable platform types: summary Good compromise between safety and convenience

  79. Collections

  80. List & MutableList kotlin.List kotlin.MutableList • Two interfaces declared in

    kotlin package • MutableList extends List
  81. Read-only immutable (1, 2, 3) • Read-only interface just lacks

    mutating methods • The actual list can be changed by another reference list mutableList
  82. val mutableList = mutableListOf(1, 2, 3) val list: List<Int> =

    mutableList println(list) // [1, 2, 3] (1, 2, 3) list mutableList (1, 2, 3, 4) mutableList.add(4) println(list) // [1, 2, 3, 4] Read-only immutable
  83. Under the hood fun getNames(): List<String>
 fun getNames(): MutableList<String> 


    java.util.List<String> getNames(); Both functions are compiled to:
  84. Kotlin uses java.util.ArrayList under the hood kotlin.MutableList java.util.ArrayList kotlin.List

  85. Platform type for Java collection collection type of “unknown” mutability

    List<String> (Mutable)List<String!> notation, not syntax type that came from Java
  86. Read-only interfaces improve API object Shop { private val customers

    = mutableListOf<Customer>() fun getCustomers(): List<Customer> = customers } val customers = Shop.getCustomers() customers.add() you can’t shoot yourself in the foot any longer
  87. Platform types: summary Good compromise between safety and convenience

  88. Variance

  89. Java wildcards public interface Stream<T> {
 <R> Stream<R> map( Function<?

    super T, ? extends R> mapper);
 }
  90. interface Function1<in P, out R> {
 operator fun invoke(p: P):

    R
 } (Animal) -> Int (Cat) -> Any Animal Cat Int Any in/out on the declaration-site
  91. Just (T) -> R on the call-site inline fun <T,

    R> Iterable<T>.map(
 transform: (T) -> R): List<R> Function1<T, R>
  92. List & MutableList MutableList<String> MutableList<Any> String Any ✗ List<String> List<Any>

  93. Copyright © 2017 https://github.com/JetBrains/kotlin-workshop