Typing in Java,
Kotlin and Scala
Hanneli Tavante
Breandan Considine
Hi!
@breandan
@hannelita


Disclaimer
We will work on a single example
and rebuild it several times
It is not a language war!
We are going to discuss
some architecture concepts
Agenda
- Representing Layouts in Java
- Moving to Kotlin
- Covariance and contravariance in Scala
- Covariance and contravariance in Kotlin
- ByteCode and type erasure
- Why is this important?
Mobile

Vertical
Horizontal
Layout
How can we represent that in Java?
Layout
Vertical
Horizontal
class Layout {
    //superclass
}class Vertical 
   extends Layout {
}class Horizontal 
   extends Layout {
}
Vertical
Horizontal
Layout
Inheritance... meh
- Tight coupling
- Reusing base class for unrelated child

Can we come up with a better layout?
interface Layout {
}class Vertical 
   implements Layout {
}class Horizontal 
   implements Layout {
}
Vertical
Horizontal
Layout
Does this object have these skills?
Does this object understand this protocol ?
Name refactor
interface Orientation {
}class Vertical implements
      Orientation {
}class Horizontal implements
    Orientation {
}It is time to add some methods
rotate()
rotate() applied to a Horizontal -> Vertical
rotate() applied to a Vertical -> Horizontal
Where should we place the method rotate() ?
interface Orientation {
}class Vertical implements
      Orientation {
}class Horizontal implements
    Orientation {
}interface Orientation {
}class Vertical implements
      Orientation {
    Horizontal rotate() {
        return 
         new Horizontal();
    }
}class Horizontal implements
    Orientation {
    Vertical rotate() {
        return 
         new Vertical();
    }
}interface Orientation {
   Orientation rotate();
}class Vertical implements
      Orientation {
    Horizontal rotate() {
        return 
         new Horizontal();
    }
}class Horizontal implements
    Orientation {
    Vertical rotate() {
        return 
         new Vertical();
    }
}Can we make it better?
We also could use Generics
class Layout<T> {
}class Layout<T> {
}class Vertical {
}class Horizontal {
}
Layout
Vertical
Horizontal
How do we restrict a Layout either Layout<Vertical> or Layout<Horizontal>
interface Orientation {
}class Vertical implements
      Orientation {
}class Horizontal implements
    Orientation {
}class Layout<T extends Orientation> {
}
Can we have a generic Layout rotate() ?
interface Orientation {
  Orientation rotate();
}class Vertical implements
      Orientation {
    Horizontal rotate() {
        return new Vertical();
    }
}class Horizontal implements
    Orientation {
    Vertical rotate() {
        return new Horizontal();
    }
}class Layout<T extends Orientation> {
  public Layout(T t){
    this.t = t;
  }
  Orientation rotate(){
    t.rotate();
  }
}We want to achieve:
Layout<Horizontal> layoutHorizontal = 
           new Layout<Horizontal>(new Horizontal());layoutHorizontal.rotate();Orientation result=Layout<Vertical> layoutverticalWe want:
(Layout<Vertical>)layoutHorizontal.rotate();=Explicit casting
:(
Is there any way to avoid that?
Agenda
- Representing Layouts in Java
- Moving to Kotlin
- Covariance and contravariance in Scala
- Covariance and contravariance in Kotlin
- ByteCode and type erasure
- Why is this important?
In Kotlin:
interface Orientation {
    fun rotate(): Orientation
}class Vertical : Orientation {
  override 
      fun rotate() = Horizontal()
}class Horizontal : Orientation {
    override 
      fun rotate() = Vertical()
}class Layout<out T : Orientation>(val t: T) {
}In Kotlin:
class Layout<out T : Orientation>(val t: T) {
}
In Kotlin:
class Layout<out T : Orientation>(val t: T) {
}
@JvmName("rotateVertical")
fun Layout<Horizontal>.rotate(): Vertical = this.t.rotate()
@JvmName("rotateHorizontal")
fun Layout<Vertical>.rotate(): Horizontal = this.t.rotate()Extension functions
In Kotlin:
val horizontal = Layout(Horizontal())
val vertical = Layout(Vertical())
// Type safe rotation!
var v: Layout<Vertical> = horizontal.rotate()
var h: Layout<Horizontal> = vertical.rotate()
h = horizontal.rotate().rotate()
v = vertical.rotate().rotate()
In Kotlin:
val horizontal = Layout(Horizontal())
val vertical = Layout(Vertical())
// Type safe rotation!
var v: Layout<Vertical> = horizontal.rotate()
var h: Layout<Horizontal> = vertical.rotate()
h = horizontal.rotate().rotate()
v = vertical.rotate().rotate()
/* Does not compile!
v = horizontal.rotate().rotate()
h = vertical.rotate().rotate()
*/Agenda
- Representing Layouts in Java
- Moving to Kotlin
- Covariance and contravariance in Scala
- Covariance and contravariance in Kotlin
- ByteCode and type erasure
- Why is this important?
Redesign In Scala:
trait Orientation {}
Redesign In Scala:
trait Orientation {}
class Vertical extends Orientation {}
class Horizontal extends Orientation {}
Redesign In Scala:
trait Orientation {}
class Vertical extends Orientation {}
class Horizontal extends Orientation {}
abstract class Layout[+T <: Orientation] {
  def layout: T
}
Redesign In Scala:
trait Orientation {}
class Vertical extends Orientation {}
class Horizontal extends Orientation {}
abstract class Layout[T <: Orientation] {
  def layout: T
}
class VerticalLayout(v: Vertical) 
              extends Layout[Vertical] {
  override def layout = v
}
class HorizontalLayout(h: Horizontal) 
               extends Layout[Horizontal] {
  override def layout = h
}
Orientation
Vertical
Horizontal
Orientation
Vertical
Horizontal
Layout
Horizontal
Layout
Vertical
Orientation
LayoutVertical
LayoutHorizontal
In Scala
val layout: Layout[Orientation] = new 
                             HorizontalLayout(new Horizontal)Compile error: "Expression doesn't conform to the expected type"

In Scala
val layout: Layout[Orientation] = new 
                             HorizontalLayout(new Horizontal)abstract class Layout[T <: Orientation] {
  def layout: T
}We need to tell the compiler that
Layout[Horizontal] is a subtype Layout[Orientation]
In Scala
val layout: Layout[Orientation] = new 
                             HorizontalLayout(new Horizontal)abstract class Layout[+T <: Orientation] {
  def layout: T
}We need to tell the compiler that
Layout[Horizontal] is a subtype Layout[Orientation]
(Covariance)
In Scala
abstract class Layout[+T <: Orientation] {
  def layout: T
  def rerender(layout: T)
}Method to re-render the actual screen, keeping the layout.
In Scala
abstract class Layout[+T <: Orientation] {
  def layout: T
  def rerender(layout: T)
}Compile error: "Covariant type occurs in contravariant position"


In Scala
abstract class Layout[+T <: Orientation] {
  def layout: T
  def rerender[T >: Orientation](layout: T)
}Why does the injected argument needs to be contravariant?
In Scala
abstract class Layout[+T <: Orientation] {
  def layout: T
  def rerender(layout: T)
}var layoutWrapper: Layout[Orientation] = 
            new HorizontalLayout(new Horizontal)
  layoutWrapper.rerender(new Vertical)^That is not right.
That is why input arguments are contravariant.
Scala and Kotlin help you actively think about covariance and contravariance
Agenda
- Representing Layouts in Java
- Moving to Kotlin
- Covariance and contravariance in Scala
- Covariance and contravariance in Kotlin
- ByteCode and type erasure
- Why is this important?
Back to Kotlin
interface Orientation {
    fun rotate(): Orientation
}
object Vertical : Orientation {
    override fun rotate() = Horizontal
}
object Horizontal : Orientation {
    override fun rotate() = Vertical
}
Back to Kotlin
interface Orientation {
    fun rotate(): Orientation
}
object Vertical : Orientation {
    override fun rotate() = Horizontal
}
object Horizontal : Orientation {
    override fun rotate() = Vertical
}
class Layout<out T : Orientation>(val t: T) {
}Back to Kotlin
open class Builder<out T : Layout<*>> {
    open fun build(): T = build()
}
Back to Kotlin
open class Builder<out T : Layout<*>> {
    open fun build(): T = build()
}
open class Renderer<in T> {
    open fun render(t: T) {
        println(t)
    }
}Back to Kotlin
open class Builder<out T : Layout<*>> {
    open fun build(): T = build()
}
open class Renderer<in T> {
    open fun render(t: T) {
        println(t)
    }
}
fun covariance(horizontalBuilder: Builder<Layout<Horizontal>>,
               layoutBuilder: Builder<Layout<Orientation>>) {
    // Layout<Horizontal> is a subtype of Layout<Orientation> ✓
    val bldr: Builder<Layout<Orientation>> = horizontalBuilder
    
    // Layout<Orientation> is a supertype of Layout<Horizontal> ✗
    val hlbr: Builder<Layout<Horizontal>> = layoutBuilder //ERROR
}Back to Kotlin
open class Builder<out T : Layout<*>> {
    open fun build(): T = build()
}
open class Renderer<in T> {
    open fun render(t: T) {
        println(t)
    }
}
fun contrav(layoutRenderer: Renderer<Layout<Orientation>>,
            horizontalRenderer: Renderer<Layout<Horizontal>>) {
    // Layout<Orientation> is a supertype of Layout<Horizontal> ✓
    val hlrd: Renderer<Layout<Horizontal>> = layoutRenderer
    
    // Layout<Horizontal> is a subtype of Layout<Orientation> ✗
    val lrdr: Renderer<Layout<Orientation>> = horizontalRenderer
}Agenda
- Representing Layouts in Java
- Moving to Kotlin
- Covariance and contravariance in Scala
- Covariance and contravariance in Kotlin
- ByteCode and type erasure
- Why is this important?
JVM Languages
will loose the T parameter!
     class Layout {}(type erasure)
Strategies
- TypeTags and Shapeless libraries in Scala
- Extension functions in Kotlin
- Reified generics in Kotlin
- Reflection
- Manually store T in a field
Agenda
- Representing Layouts in Java
- Moving to Kotlin
- Covariance and contravariance in Scala
- Covariance and contravariance in Kotlin
- ByteCode and type erasure
- Why is this important?
To sum up
- Think about different coding approaches
- Different architectures
- New concepts
- Understand the goods and the bad parts of a language and when to use each of them
References
Thank you :)
Questions?

Typing in Java, Kotlin and Scala - Devoxx US 2017
By Hanneli Tavante (hannelita)
Typing in Java, Kotlin and Scala - Devoxx US 2017
- 4,070
 
   
   
  