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

Level up in Kotlin

pahill
September 19, 2019

Level up in Kotlin

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