Kotlin 1.3 in Action

Tobse Fritz

  • Reich
  • Gut aussehend
  • Java Entwickler
  • Kotlin Fanboy
  • ITscope GmbH

 

 

         github.com/TobseF

         unsplash.com/@tobsef

Hibernate


@Entity
@OptimisticLocking(type = VERSION)
@Table(name = "HIB_PERSON")
@Proxy(lazy = false)
@Access(javax.persistence.AccessType.FIELD)
@BatchSize(size = 10)
@Cache(usage = READ_WRITE)
public class Person extends AuditablePersistent implements PersonIdentifier {

	@OneToOne(optional = true)
	@NotFound(action = NotFoundAction.EXCEPTION)
	@PrimaryKeyJoinColumn
	private Employee employee;

	@ManyToOne(optional = true)
	@JoinColumn(name = "org_id")
	@NotFound(action = NotFoundAction.EXCEPTION)
	@Fetch(FetchMode.JOIN)
	private Organisation organisation;


	@Column(nullable = false, columnDefinition = "boolean default false")
	private boolean registrationPending;

...

Java Server Face

<html>
<head><title>Hallo Leute</title></head>
<body>
  <%
    double num = Math.random();
    if (num > 0.95) {
  %>
      <h2>Freut euch auf einen verdammt guten Vortrag!</h2><p>(<%= num %>)</p>
  <%
    } else {
  %>
      <h2>Freut euch auf ein gutes Gespräch mit eurem Sitznachbarn</h2><p>(<%= num %>)</p>
  <%
    }
  %>
  <a href="<%= request.getRequestURI() %>"><h3>Nochmal drüber nachdenken?</h3></a>
</body>
</html>

React

import { Component } from '@someframework/core';  

@Component ({ 
   selector: 'my-app', 
   template: '<h1>Hallo {{name}}</h1>'; 
}) 

export class AppComponent { name = 'Leute'; } 

Vaadin

@Title("My UI")
public class HelloWorld extends UI {
    @Override
    protected void init(Request request) {

        VerticalLayout content = new VerticalLayout();
        setContent(content);

        content.addComponent(new Label("Hello Leute!"));

        content.addComponent(new Button("Drück mich!",
            click -> Notification.show("Heute hab ich eine Sache gelernt!")));
    }
}

Ktor

fun Application.module() {
    routing { get("/") {
        call.respondHtml {

        head {
            link(rel = "stylesheet", href = "/styles.css", type = "text/css")
        }
        body {
            styleCss {
                rule("p.demo") {
                    color = Color.green
                }
            }
            p {
                +"Hello"
                span {
                    style {
                        textDecoration(TextDecorationLine.underline)
                    }
                    +" Folks!"
                }
            }
        }
        }
        }
    }
}

"Entwickler, die Software entwerfen,
sind gezwungen diese mit Lösungen zu implementieren, welche die Sprache, Libs, Frameworks und Tools abbilden."

Tobse F

Baustoff und Fundament sind essentiell

Kenne die richtigen Tools

... und wie man sie einsetzt

Kotlin Features

  • Prägnant
  • Sicher
  • Interoperabel
  • Optimales Tooling

Kotlin Features

Prägnant

public class Person {

    private final String firstName;
    private final String lastName;
    private final LocalDate birthDay;

    public Person(String firstName, String lastName, 
                  LocalDate birthDay) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.birthDay = birthDay;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public LocalDate getBirthDay() {
        return birthDay;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return Objects.equals(firstName, person.firstName) &&
                Objects.equals(lastName, person.lastName) &&
                Objects.equals(birthDay, person.birthDay);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstName, lastName, birthDay);
    }

    @Override
    public String toString() {
        return "Person{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", birthDay=" + birthDay +
                '}';
    }
}
data class PersonK(
    val firstName: String,
    val lastName: String,
    val birthDay: LocalDate
)

Java

Kotlin

Kotlin Features

Sicher

var output: String
output = null

Kotlin

val name: String? = null
println(name.length)
fun calculateTotal(obj: Any) {
    if (obj is Invoice){
        obj.calculateTotal()
    }
}
fun isCloneBaby(father: Person, son: Person): Boolean {
    return father == son
}
// compile Error
// compile Error
// Autocast
// equals()

Kotlin Features

Interoperabel

  • iOS (arm32, arm64, simulator x86_64)
  • MacOS (x86_64)
  • Android (arm32, arm64)
  • Windows (mingw x86_64, x86)
  • Linux (x86_64, arm32, MIPS, MIPS little endian, Raspberry Pi)
  • WebAssembly (wasm32)

Kotlin Features

Interoperabel

fun callJava(){
  val backend = LegacyBackend()
  backend.sendMail("Be prepared... we deploy")
}

Kotlin

private void callKotlin(){
  var backend = new NewBackend();
  backend.sendSlack("We introduced NetID oAuth!");
}

Java

Kotlin Features

Optimales Tooling

Kotlin Features

  • Prägnant
  • Sicher
  • Interoperabel
  • Optimales Tooling

 

  • Frei & OpenSource

Kotlin Highlights

  • Null Safety
  • Data Classes
  • Lambdas - ohne Interface Hölle
  • Equal Checks mit ==
  • Delegations
  • Type Safe Builders
  • Sealed Clasess
  • Reified Types

💎

Kotlin 1.3

  • Inline Classes
  • Unsigned Integers
  • Coroutines
  • Contracts
  • Serialization
  • Gradle DSL
  • Scripting & Runnable Scratch Files
  • Multiplatform

UPDATE

Inline Class

Value types schon heute

Inline Classes

inline class CM(val number: Double = 1.0){
        fun toInch() = number * 2.54
        fun toFeet() = number * 0.0328084

    override fun toString(): String {
        return "$number cm"
    }
}

fun main() {
    println(CM(1.0))
    println(CM(1.0).toFeet())
    println(CM(1.0).toInch())
    cutTheRope(length = CM(20.0))
}

var ropeLength = CM(100.0)

fun cutTheRope(length:CM ){
    ropeLength = CM(ropeLength.number  + length.number)
    println("Remaining rope: $length")
}

Inline Classes

fun weeNeedBoxedValue(value: CM?){
    value?.apply (::println)
}

Boxing

Inline Classes

public static final void cutTheRope(double length) {
    ropeLength = CM.constructor-impl(ropeLength + length);
    String var2 = "Remaining rope: " + CM.toString-impl(length);
    System.out.println(var2);
}
public static final void weeNeedBoxedValue(@Nullable CM value) {
    if (value != null) {
        System.out.println(value);
    }
}

Compiliert

TypeAlias

Coole Namen für

schlechte Typen

TypeAlias

typealias cm = Double

fun main() {
    cutTheRope( 20.0)
}

var ropeLength : cm = 100.0

fun cutTheRope(length: cm){
    ropeLength -= length
    println("New rope length: $ropeLength cm")
}
typealias ExceptionMap = Map<Int, ()->DatatypeConfigurationException>

fun configure(mappings: ExceptionMap){
    mappings[0]?.invoke()
}

TypeAlias

vs

Inline Class

Unsigned Int

fun main() {
    val theAnswer = 42u
    pronounce(theAnswer)
    pronounce(42.toUInt())
    pronounce(42) // ⚡ Compile error
}

fun pronounce(answer: UInt){
    print("The answer is $answer")
}

Ein gutes Vorzeichen

  • Callback Hell
  • Was kostet ein Thread?

Coroutines

Coroutines

Coroutinen sind leichtgewichtige Threads.
Sie können angehalten werden,
ohne den Thread zu blockieren.

Suspending

Launch startet eine Coroutine und

gibt einen Job zurück.

Async ist wie Launch, nur mit Rückgabewert.

Await wartet auf den Rückgabewert.

Async / Await

Launch

Coroutines

Coroutines

  • Leserlich wie imperativer Code
  • Keine Callback Hell
  • Leichtgewichtiger als Threads
    • ​Geringerer Speicherverbrauch
    • Schneller Wechsel
  • Syntax ist unabhängig von Implementierung
  • Verfügbar in JVM, JS und Native Kotlin

Coroutines 📙

  • Channels
  • Actors
  • Sequence Builder
  • Coroutine Dispatcher
  • Coroutine Scope

Contracts

Der Vertrag mit dem Compiler

Contracts

open class Animal(var isAlive: Boolean)

class Unicorn : Animal(true){
    fun doMagicPoop() = print("🌈✨")
}

fun Animal.isMagical() : Boolean{
    contract {
        returns(true) implies (this@isMagical is Unicorn)
    }
    return this is Unicorn && isAlive
}

fun main() {
    val babyUnicorn : Animal = Unicorn()
    if (babyUnicorn.isMagical()) {
        babyUnicorn.doMagicPoop()
    }
}

Kotlin Gradle DSL

plugins {
    kotlin("jvm") version "1.3.30"
    java
}

group = "de.tfr.presentation"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    implementation(kotlin("stdlib-js"))
    testCompile("junit", "junit", "4.12")
}

configure<JavaPluginConvention> {
    sourceCompatibility = JavaVersion.VERSION_1_8
}

Kotlin Scratch Files

fun ourCoolBuildScript(){
    val timeStamp = LocalDateTime.now()
    downloadI18nMessages()
    formatMessageProperties()
    mergeChangeLogEntries(timeStamp)
    sendSlackMessage("We gonna deploy that stuff 🤘")
}

One-Click Scripts

*.kts

Kotlin Scratch Files

  • Build scripts (Gradle/Kobalt)
  • Test scripts (Spek)
  • Command-line Utilities
  • Routing Skripte (ktor)
  • Type-safe configuration files (TeamCity)
  • In-process scripting and REPL for IDE
  • Consoles like IPython/Jupyter Notebook
  • Game scripting engines

THE END

Quellen