Let's fly to the Kotlin Island. Just an introduction to Kotlin
Typing in Java, Kotlin and Scala
-
Upload
hanneli-tavante -
Category
Technology
-
view
141 -
download
2
Transcript of Typing in Java, Kotlin and Scala
Typing in Java,Kotlin and Scala
Hanneli Tavante
Breandan Considine
Hi!@breandan @hannelita
DisclaimerWe will work on a single example
and rebuild it several times
It is not a language war!
We are going to discusssome architecture concepts
Agenda
Representing Layouts in JavaMoving to KotlinCovariance and contravariance in ScalaCovariance and contravariance in KotlinByteCode and type erasureWhy is this important?
Mobile
Vertical Horizontal
Layout
How can werepresent that in
Java?
Layout
Vertical
Horizontal
class Layout { //superclass}
class Vertical extends Layout {
}
class Horizontal extends Layout {
}
Vertical
Horizontal
Layout
Inheritance... mehTight couplingReusing base class for unrelated child
Can we come up with abetter layout?
class Vertical implements Layout {
}
interface Layout {
}
class Horizontal implements Layout {
}
Vertical
Horizontal
Layout
Does this objecthave these skills?
Does this objectunderstand this
protocol ?
Name refactor
class Vertical implements Orientation {
}
interface Orientation {
}
class Horizontal implements Orientation {
}
It is time to addsome methods
rotate()
rotate() applied to a Horizontal -> Vertical
rotate() applied to a Vertical -> Horizontal
Where should weplace the method
rotate() ?
class Vertical implements Orientation {
}
interface Orientation {
}
class Horizontal implements Orientation {
}
class Vertical implements Orientation {
Horizontal rotate() { return new Horizontal(); }
}
interface Orientation {
}
class Horizontal implements Orientation {
Vertical rotate() { return new Vertical(); }
}
class Vertical implements Orientation {
Horizontal rotate() { return new Horizontal(); }
}
interface Orientation { Orientation rotate();
}
class Horizontal implements Orientation {
Vertical rotate() { return new Vertical(); }
}
Can we make itbetter?
We also could useGenerics
class Layout<T> {
}
class Layout<T> {
}
class Vertical {
}
class Horizontal {
}
Layout
Vertical
Horizontal
How do we restrict aLayout either
Layout<Vertical> orLayout<Horizontal>
class Vertical implements Orientation {
}
interface Orientation {
}
class Horizontal implements Orientation {
}
class Layout<T extends Orientation> {
}
Can we have a generic Layout rotate() ?
class Vertical implements Orientation {
Horizontal rotate() { return new Vertical(); }}
class Horizontal implements Orientation {
Vertical rotate() { return new Horizontal(); }}
interface Orientation { Orientation rotate();}
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();
layoutHorizontal.rotate();Orientation result
=Layout<Vertical> layoutvertical
We want:(Layout<Vertical>)
=
Explicit casting
:(
Is there any wayto avoid that?
Agenda
Representing Layouts in JavaMoving to KotlinCovariance and contravariance in ScalaCovariance and contravariance in KotlinByteCode and type erasureWhy is this important?
In Kotlin:
class Vertical : Orientation { override fun rotate() = Horizontal()}
class Horizontal : Orientation { override fun rotate() = Vertical()}
interface Orientation { fun rotate(): Orientation}
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 JavaMoving to KotlinCovariance and contravariance in ScalaCovariance and contravariance in KotlinByteCode and type erasureWhy 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 Scalaval layout: Layout[Orientation] = new HorizontalLayout(new Horizontal)
Compile error: "Expression doesn't conformto the expected type"
In Scalaval layout: Layout[Orientation] = new HorizontalLayout(new Horizontal)
abstract class Layout[T <: Orientation] { def layout: T}
We need to tell the compiler thatLayout[Horizontal] is a subtype
Layout[Orientation]
In Scalaval layout: Layout[Orientation] = new HorizontalLayout(new Horizontal)
abstract class Layout[+T <: Orientation] { def layout: T}
We need to tell the compiler thatLayout[Horizontal] is a subtype
Layout[Orientation]
(Covariance)
In Scalaabstract class Layout[+T <: Orientation] { def layout: T
def rerender(layout: T)}
Method to re-render the actual screen,keeping the layout.
In Scalaabstract class Layout[+T <: Orientation] { def layout: T
def rerender(layout: T)}
Compile error: "Covariant type occurs incontravariant position"
In Scalaabstract class Layout[+T <: Orientation] { def layout: T
def rerender[T >: Orientation](layout: T)
}
Why does the injected argument needs tobe contravariant?
In Scalaabstract 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 helpyou actively thinkabout covariance
and contravariance
Agenda
Representing Layouts in JavaMoving to KotlinCovariance and contravariance in ScalaCovariance and contravariance in KotlinByteCode and type erasureWhy is this important?
Back to Kotlininterface Orientation { fun rotate(): Orientation}
object Vertical : Orientation { override fun rotate() = Horizontal}
object Horizontal : Orientation { override fun rotate() = Vertical}
Back to Kotlininterface 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 Kotlinopen class Builder<out T : Layout<*>> { open fun build(): T = build()}
Back to Kotlinopen class Builder<out T : Layout<*>> { open fun build(): T = build()}
open class Renderer<in T> { open fun render(t: T) { println(t) }}
Back to Kotlinopen 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 Kotlinopen 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 JavaMoving to KotlinCovariance and contravariance in ScalaCovariance and contravariance in KotlinByteCode and type erasureWhy is this important?
JVM Languageswill loose the T
parameter! class Layout {}
(type erasure)
StrategiesTypeTags and Shapeless libraries in ScalaExtension functions in KotlinReified generics in KotlinReflectionManually store T in a field
Agenda
Representing Layouts in JavaMoving to KotlinCovariance and contravariance in ScalaCovariance and contravariance in KotlinByteCode and type erasureWhy is this important?
To sum up
Think about different coding approachesDifferent architecturesNew conceptsUnderstand the goods and the bad parts of alanguage and when to use each of them
ReferencesPattern Match Generics in ScalaShapelessScala Type System blog postGeneralized types without a PhDKotlin awesome docsTypeTagOvercoming type erasureExamples (GitHub repo)
Thank you :)Questions?