Moving Explor3r – Part II

In this second part of Moving Explor3r, we will make some changes using extension functions to improve readability.

Here is the code we wrote on Part I :

package com.kotlinrobots.usingwhen

import lejos.hardware.motor.EV3LargeRegulatedMotor
import lejos.hardware.port.MotorPort
import lejos.utility.Stopwatch

fun main(args: Array<String>) {

    val motorA = EV3LargeRegulatedMotor(MotorPort.A)
    val motorD = EV3LargeRegulatedMotor(MotorPort.D)
    val watch = Stopwatch()

    motorA.speed = 360 // 1 RPM
    motorD.speed = 360 // 1 RPM

    watch.reset()

    while (watch.elapsed() < 10000) {
        println("Milliseconds : ${watch.elapsed()}")

        when (watch.elapsed()) {
            in 3000..5000, in 7000..9000 -> {
                motorA.backward()
                motorD.backward()
            }
            else -> {
                motorA.forward()
                motorD.forward()
            }
        }
    }

    motorA.stop()
    motorD.stop()
}

Extension Functions

An extension function is a function that can be called as a member of a class but it is defined outside of it.
Kotlin In Action, page 52

Where can we use this feature in our code? On Line 18, we are calling the method elapsed() and compare it to 1000. We can make this code more readable by adding this extension function:

fun Stopwatch.elapsedSecondsIsLessThan(seconds: Int): Boolean = this.elapsed() < seconds * 1000

As you can see, we are adding a function to Stopwatch class, and now can use it in our code like this:

while (watch.elapsedSecondsIsLessThan(10)) {
      println("Milliseconds : ${watch.elapsed()}")

      when (watch.elapsed()) {
          in 3000..5000, in 7000..9000 -> {
              motorA.backward()
              motorD.backward()
          }
          else -> {
              motorA.forward()
              motorD.forward()
          }
      }
  }

If you run this code, you will see that it still works but now our code is more readable. With this Kotlin feature, we can create methods with better names to improve our code.

Let’s create one more extension function for the Stopwatch, like this:

fun Stopwatch.elapsedSeconds(): Int = this.elapsed() / 1000

Now we have to change the code inside when to use seconds instead of milliseconds:

package com.kotlinrobots.extensionfunctions

import lejos.hardware.motor.EV3LargeRegulatedMotor
import lejos.hardware.port.MotorPort
import lejos.utility.Stopwatch

fun Stopwatch.elapsedSecondsIsLessThan(seconds: Int): Boolean = this.elapsed() < seconds * 1000
fun Stopwatch.elapsedSeconds(): Int = this.elapsed() / 1000

fun main(args: Array<String>) {

    val motorA = EV3LargeRegulatedMotor(MotorPort.A)
    val motorD = EV3LargeRegulatedMotor(MotorPort.D)
    val watch = Stopwatch()

    motorA.speed = 360 // 1 RPM
    motorD.speed = 360 // 1 RPM

    watch.reset()

    while (watch.elapsedSecondsIsLessThan(10)) {
        println("Seconds : ${watch.elapsedSeconds()}")

        when (watch.elapsedSeconds()) {
            in 3..5, in 7..9 -> {
                motorA.backward()
                motorD.backward()
            }
            else -> {
                motorA.forward()
                motorD.forward()
            }
        }
    }

    motorA.stop()
    motorD.stop()
}

Note that in Stopwatch.elapsedSecondsIsLessThan(seconds: Int) we are still converting seconds to milliseconds. We can change this code to this final version:

package com.kotlinrobots.extensionfunctions

import lejos.hardware.motor.EV3LargeRegulatedMotor
import lejos.hardware.port.MotorPort
import lejos.utility.Stopwatch

fun Stopwatch.elapsedSecondsIsLessThan(seconds: Int): Boolean = this.elapsedSeconds() < seconds
fun Stopwatch.elapsedSeconds(): Int = this.elapsed() / 1000

fun main(args: Array<String>) {

    val motorA = EV3LargeRegulatedMotor(MotorPort.A)
    val motorD = EV3LargeRegulatedMotor(MotorPort.D)
    val watch = Stopwatch()

    motorA.speed = 360 // 1 RPM
    motorD.speed = 360 // 1 RPM

    watch.reset()

    while (watch.elapsedSecondsIsLessThan(10)) {
        println("Seconds : ${watch.elapsedSeconds()}")

        when (watch.elapsedSeconds()) {
            in 3..5, in 7..9 -> {
                motorA.backward()
                motorD.backward()
            }
            else -> {
                motorA.forward()
                motorD.forward()
            }
        }
    }

    motorA.stop()
    motorD.stop()
}

Source code

Miguel

Leave a Reply

Your email address will not be published. Required fields are marked *