$30 off During Our Annual Pro Sale. View Details »

Presentation - The Ins and Outs of Generics in Kotlin by Erik Colban

SD Kotlin
September 05, 2018

Presentation - The Ins and Outs of Generics in Kotlin by Erik Colban

Presentation slides for SD Kotlin's September 2018 meeting.

SD Kotlin

September 05, 2018
Tweet

More Decks by SD Kotlin

Other Decks in Programming

Transcript

  1. Kotlin Generics
    Presentation at San Diego Kotlin Meetup,
    September 5, 2018, by Erik Colban

    View Slide

  2. Outline
    ● Using Kotlin’s built-in generic classes and functions
    ● Variance
    ○ Covariance, contravariance, invariance
    ● Declaring generic functions, properties, and classes
    ● Variance
    ○ Type projections
    ○ Use-site vs declaration-site variance specification
    ● Type erasure
    ○ What it is
    ○ How to get around it
    ○ *- projections

    View Slide

  3. Using Kotlin’s built-in generic classes and function
    ● Possible
    ○ val list: List = listOf(12, 3, 1007)
    ○ val list = listOf(12, 3, 1007)
    ○ val list: List = listOf(12, 3, 1007)
    ○ val list = listOf(12, 3, 1007)
    ○ val list: List = listOf(12, 3, 1007)
    ● Not possible
    ○ val array: Array = arrayOf(12, 3, 1007)
    ● Note: In Java:
    ○ Number[] array = new Integer[]{12, 3, 1007};
    ○ Big mistake!
    ■ array[0] = 12.3; ⇒ java.lang.ArrayStoreException

    View Slide

  4. Variance
    Covariance: If C is a generic type with type parameter T and U is a subtype of
    T, then C is a subtype of C
    ● U subtype of T ⇒ C subtype of C
    ● Example: List is a subtype of List because Int is a subtype of
    Number.
    ● Applies to types that are “producers”, or a “source” of T
    ● T only appears only in “out” position, i.e., the return type of a function
    ○ Example: getters
    ● T is never in “in” position, i.e. the type of a function argument.

    View Slide

  5. Variance
    Contra-variance: If C is a generic type with type parameter T and U is a
    subtype of T, then C is a subtype of C
    ● U subtype of T ⇒ C subtype of C
    ● Example: Function1 is a subtype of Function1
    because Int is a subtype of Number.
    ● Applies to types that are “consumers” of T
    ● T only appears only in “in” position, i.e., the type of a function argument
    ● T is never in “out” position, i.e. the return type of a function.

    View Slide

  6. Variance
    Invariance: If C is a subtype of C, then T = U
    ● Example: Array is invariant in T
    ● T appears in both “in position” and “out position”
    ● Type is both a producer and consumer of T
    To remember: Lambdas are contra-variant in their argument types and covariant
    in their return type

    View Slide

  7. Variance Rationale
    Liskov’s substitution principle:
    “You can substitute a subtype for a super-type.”
    ● “Annie get your gun”-principle
    ○ Subtype to super-type: “Anything you can do, I can to better. I can do anything better than you!”
    ● Example: If anything a List produces is OK, then anything a List
    produces is OK too.
    ● Example: Any input to a Function1 can be input to a Function1 too.
    ● Example: An Array is better than an Array in the same sense that a List
    is better than a List, but an Array can hold anything an Array can
    hold. So neither is better than the other.

    View Slide

  8. Scenario
    Bob arrives late to his hotel. Hungry, but not eager to go out to a restaurant, he asks the
    hotel clerk if there is a vending machine (VM) in the hotel where he can buy a chocolate bar.
    He also says he only has a few dollar bills to pay with, so the vending machine must accept
    dollar bills as payment.
    The hotel clerk gives Bob directions to the vending machine, and Bob heads to the VM. After
    seeing the VM, Bob is furious! He stomps back to the reception and complains: “I specifically
    asked for a VM that accepts dollar bills as payment, but that machine accepts coins,
    banknotes, credit cards, and what have you! Moreover, it has no selection for chocolate bar!
    KitKat, Snickers, chips and peanuts, yes, but chocolate bar? Nooo!”
    “Is there a problem?”, asks the bewildered hotel clerk.

    View Slide

  9. Payment Model
    PaymentMethod
    Cash Card
    DollarBills

    View Slide

  10. Merchandise Model
    Merchandise
    ChocolateBar SnackFood
    TrailMix
    Chips
    Snickers
    KitKat Hershey

    View Slide

  11. RobotCommand Model
    RobotCommand
    PrimitiveCommand ComplexCommand
    Turn
    Move Pen
    ?
    ...

    View Slide

  12. Code Examples
    ● See https://github.com/ecolban/KotlinGenerics
    ● This project uses a library: (see
    .idea/libraries/robot.xml). Copy this jar from
    https://github.com/jointheleague/Robot/blob/master/jar/robot.jar

    View Slide

  13. Type Projections
    /**
    * All occurrences of T in Array that are in "out position" are replaced by Any?
    */
    fun getFromInProjection(a: Array) {
    val b = a[0]
    }
    /**
    * All occurrences of T in Array that are in "in position" are replaced by Nothing
    */
    fun insertIntoOutProjection(a: Array, b: T) {
    a[0] = b ⇒ Error!! (Would only work if b were of type Nothing :-)
    }
    ● “T in in position” = “T is an argument type”
    ● “T in out position” = “T is a return type”

    View Slide

  14. Use-site vs Declaration-site Variance
    ● Declaration-site variance
    ○ Specifies a subtype relationship between generic types
    ○ Example: class GenericRobot declares that GenericRobot is a
    subtype of GenericRobot (because RobotCommand is a supertype of
    PrimitiveCommand).
    ○ “Once for all” declaration
    ● Use-site variance
    ○ Specifies which types can be assigned to a variable or function argument, without there being a
    subtype relationship between them
    ○ Example: fun execute(robot: GenericRobot, command: T) {...}
    declares that when T is bound to PrimitiveCommand, robot can be of type
    GenericRobot
    ○ Uses type projections (in this example, replaces all occurrences of T in out position in GenericRobot
    with Any?)

    View Slide

  15. Type Erasure
    ● Type checking and inference happens at compile time
    ○ Example: Compiler verifies and “knows” that an instance of List only contains
    instances of String and does not contain null.
    ○ Compiler assigns types to type parameters
    ● During runtime, the information about which types have been assigned to type
    parameters is lost.
    ● See code examples

    View Slide