GitHub Repo

Two small changes for your amusement. UPDATE: No, three! Thanks Christian!


moveItemTo

In Items, we had:

    fun moveItemTo(name: String, target: Items): Boolean {
        val maybeItem: Item? = remove(name)
        return when (maybeItem) {
            null -> false
            else -> {
                target.add(maybeItem)
                return true
            }
        }
    }

We can instead write:

    fun moveItemTo(name: String, target: Items): Boolean {
        val item = remove(name) ?: return false
        target.add(item)
        return true
    }

That seems nicer to me.

Details:
The “elvis” operator, ?: executes whatever is to its right, only if the expression it follows is null. Here, if remove returns an item, it is stored in our local item. If it returns null, we immediately exit, returning false. Otherwise, we carry on, completing the move and returning true.

I think that while this is likely a bit cryptic to Kotlin newbies, it can and should become a valuable tool in our kit when we get used to it: it lets us get rid of nulls quickly and safely. The code above “knows” that item is really an Item, not an Item? as returned from remove.


moveItemTo even more so

Here’s a one-liner, h/t Christian Hujer:

    fun moveItemTo(name: String, target: Items): Boolean
        = remove(name)?.also {target.add(it)} != null
Details:
The ?. calls the function to its right only if the remove returns non-null.

The also function passes the result of the remove, an Item, to its block, as it.

That same object, the remove result, the Item, is always returned from the block.

Finally, the result of the remove is checked for non-null, returning the correct Boolean.

A very nice concise expression, thanks to Christian Hujer. Might take some getting used to, but when one gets used to these they’ll probably become second nature.


take

A day or so ago, we had this code:

    val take = { imperative: Imperative, world: World ->
        when {
            contents.moveItemTo(imperative.noun, world.inventory) -> {
                world.response.say("${imperative.noun} taken.")
            }
            else -> {
                world.response.say("I see no ${imperative.noun} here!")
            }
        }
    }

Today, we have this:

    fun take(imp: Imperative, world: World) {
        with (world) { imp.noun.let {
        response.say(
            when (contents.moveItemTo(it, inventory)) {
                true -> "$it taken."
                false -> "I see no $it here!" }) }}
    }

This one I’m not so certain about but I think I prefer it for compactness. I can imagine that it might be harder to grok in fullness, but I’m not certain.

Details:
The with allows us to skip typing world ahead of anything that would require it. The let lets us substitute it for imp.noun.

It’s possible that the use of both with and let is asking us to put a method somewhere else. I’m not sure, I just got here myself.


Anyway just a couple of nice(?) Kotlin possibilities.

Your thoughts, should you have them, are welcome. See you soon!