Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Level up in Kotlin

Avatar for pahill pahill
September 19, 2019

Level up in Kotlin

Avatar for pahill

pahill

September 19, 2019
Tweet

More Decks by pahill

Other Decks in Programming

Transcript

  1. I am Pamela Hill Android Engineer - Luno You can

    find me here: • Twitter: @pamelaahill • Blog: www.pamelaahill.com Hello! ! 2
  2. ! 3

  3. General-purpose language A general-purpose language solves any problem that can

    be solved by a computer A general-purpose language is imperative, specifying the operations to solve the problem What is a DSL? Domain-specific language A domain-specific language focusses on solving problems in a specific domain A domain-specific language is declarative, describing the required result ! 7
  4. External DSL Unrestricted in terms of how it expresses itself

    Requires string concatenation and parsing What is an internal DSL? Internal DSL Restricted by the syntax of a general purpose language No concatenation or parsing necessary ! 8
  5. Why is Kotlin great for constructing DSLs? • Optional semicolon

    - removes syntactic noise • Dropping . and ( ) by infixing functions
 str should startsWith("Space") is more readable than assertTrue(str.startsWith(“Space")) • Extension functions - makes existing code more fluent • No ( ) required for last lambda argument - removes syntactic noise • Lambdas with receivers • Invoke convention ! 10
  6. ! 12 val printDelimitedMission: Mission.(String) -> Unit = { delimiter

    -> println("$delimiter $this $delimiter") } Mission().printDelimitedMission("*")
  7. Commander Eileen M. Collins • First female pilot, commander of

    a Space Shuttle • On mission STS-63, she piloted the ship, which rendezvoused with Discovery and Mir ! 13
  8. ! 14 EileenCollins mission { board on SpaceShuttle launch at

    9.00 rendesvouz with Discovery rendesvouz with Mir land at 14.00 }
  9. ! 15 class Astronaut { infix fun mission(block: Mission.() ->

    Unit) { val mission = Mission() mission.block() } }
  10. ! 16 class Mission { var shuttle: Shuttle? = null

    var rendezvousShuttles: MutableList<Shuttle> = LinkedList() var board = this var launch = LaunchTime() var rendesvouz = this var land = LandTime() infix fun on(ship: Shuttle) { shuttle = ship } infix fun with(destination: Shuttle) { rendezvousShuttles.add(destination) } }
  11. DSLs - key takeaways • DSLs are focussed on describing

    only solutions to problems for a specific domain • DSLs are concise, readable, and maintainable • Language features like lambdas with receivers support the creation of readable DSLs ! 17
  12. Coroutines • Like lightweight threads • Run on a shared

    pool of threads, one thread can run many coroutines ! 19
  13. Suspendable computation Function that can suspend its computation at some

    point and resume later on, without blocking the thread ! 20
  14. Coroutine Scope Coroutine Launches Coroutine Builder Originates from Suspending Function

    Runs Dispatcher Specifies Controls thread Coroutine Context Contains
  15. Suspending function • Suspend and resume without blocking the thread

    • Marked with suspend keyword in function signature ! 25
  16. ! 30 suspend fun launchSpaceShuttle(){...} suspend fun flyToDestination(){...} suspend fun

    dockOnSpaceStation(){...} val job = launch { delay(1000) println("10,9,8 ... Ignition!") launchSpaceShuttle() flyToDestination() dockOnSpaceStation() println("Mission complete") } println("What were we doing again?")
  17. ! 32 suspend fun checkFlightPath(): FlightPath {...}
 suspend fun checkCrewHealth():

    CrewHealth {...}
 fun reportToMissionControl(flightPath: FlightPath, crewHealth: CrewHealth){...}

  18. ! 33 suspend fun checkFlightPath(): FlightPath {...}
 suspend fun checkCrewHealth():

    CrewHealth {...}
 fun reportToMissionControl(flightPath: FlightPath, crewHealth: CrewHealth){...} val job = launch {
 val flightPath = async {checkFlightPath()}
 val crewHealth = async {checkCrewHealth()}
 reportToMissionControl(flightPath.await(), crewHealth.await()) }

  19. ! 35 suspend fun flyHalfway(){...} suspend fun flyToDestination(){...} launch {

    flow { emit(Point(0.0, 0.0)) flyHalfway() emit(Point(50.0, 50.0)) flyToDestination() emit(Point(100.0, 100.0)) }.collect { point -> updateUI(point) } }
  20. ! 37 val channel = Channel<Point>() launch { channel.send(Point(0.0, 0.0))

    flyHalfway() channel.send(Point(50.0, 50.0)) flyToDestination() channel.send(Point(100.0, 100.0)) channel.close() } launch { for (point in channel) { updateUI(point) } }
  21. ! 38 val channel = Channel<Point>() launch { channel.send(Point(0.0, 0.0))

    flyHalfway() channel.send(Point(50.0, 50.0)) flyToDestination() channel.send(Point(100.0, 100.0)) channel.close() } launch { for (point in channel) { updateUI(point) } }
  22. viewModelScope • Start coroutines in the ViewModel • Use this

    scope to ensure that coroutines are only cancelled once ViewModel is cleared ! 39
  23. Coroutines - key takeaways • Coroutines are like lightweight threads

    • Suspendable computations are functions that suspend at some point, and resume at a later point - without blocking the thread • launch, async are examples of coroutine builders • Flows are cold, asynchronous data streams that sequentially emit values • Channels can be used to communicate between coroutines ! 40
  24. Inline Classes • Improve API by wrapping single type •

    Avoid unnecessary heap allocation ! 42
  25. ! 45 val planet: String? = "" if (planet !=

    null && !planet.isEmpty()){ planet.first() }
  26. ! 47 public inline fun CharSequence?.isNullOrEmpty(): Boolean { contract {

    returns(false) implies (this@isNullOrEmpty != null) } return this == null || this.length == 0 }
  27. What’s new - key takeaways • Inline classes improve the

    API, without the heap allocations of wrapper classes • Contracts give the compiler extra information about a code - use with caution • Immutable collections prevent the underlying data from being modified ! 51