richardlog

On Java, Agile, Open Source, Architecture and anything in between

Exploring Kotlin, writing a simple spell checker

In my last blog I talked about exploring Kotlin, a JVM language in development by JetBrains. In this blog I’ll walk through a larger piece of Kotlin code.

Spell checker
The program we’re talking about is a simple spell checker. It reads a dictionary of words from a file (/usr/share/dict/words) into a set. Then it reads a sentence from stdin and checks if every word is in the dictionary. Finally it informs the user whether or not the sentence is spelled correctly, i.e. every word is known in the dictionary.

The spell checker is available on my GitHub. Take a moment to study the Java version, we’ll discuss the Kotlin version next.

Entry point
The Kotlin program has a main method, or in Kotlin terms a main function. This function instantiates the KotlinSpellChecker class. Notice how the ‘new’ keyword is absent in Kotlin.

The ‘checkSpelling’ function is called with an expression. In Java we probably would have used a ternary operator in this case. Kotlin has none, instead you specify an if/else expression in a single line. The return value is written to stdout with some syntactic sugar called string templates

fun main(args : Array) {
    val defaultInput = "Kotlin is an island"
    val valid = KotlinSpellChecker().checkSpelling(if (args.size > 0) args[0] else defaultInput)
    println("Is the text valid? $valid")
}

Checking spelling
The function below receives a set of words from the ‘readDictionary’ function and stores it in a variable named ‘words’. I haven’t explicitly specified a type for this (immutable) variable since Kotlin is able to infer the type information.

For-loops in Kotlin have a slightly different syntax compared to Java. In this case we iterate over an array of strings but Kotlin for-loops can also iterate over plain strings.

fun checkSpelling(input : String) : Boolean {
   val words = readDictionary()
   for (word in input.toLowerCase().split(" ")) {
        if (!words.contains(word)) {
            println("$word is not in the dictionary");
            return false;
        }
   }
   return true;
}

Reading a file
The following code returns a java.util.HashSet which is initialized using the ‘hashSet’ function from the Kotlin standard library (stdlib). The higher-order ‘forEachLine’ function accepts a function literal which adds each word to the mentioned HashSet.

Finally see the third line of code. We don’t have to wrap the FileInputStream in a BufferedInputStream ourselves, instead we just call the ‘buffered’ function to do it for us. Here we see extension functions in action, ‘buffered’ is a generic extension function implemented in stdlib on Java’s InputStream class.

private fun readDictionary() : Set {
    val words = hashSet("kotlin") // add kotlin to dictionary
    val stream = FileInputStream(DICTIONARY_WORDS).buffered();
    try {
         val reader = InputStreamReader(stream, "UTF-8");
         reader.forEachLine( { words.add(it)} )
    } finally {
         stream.close();
    }
    return words;
}

You can fork the code off GitHub in case you want to play with it. There’s room for comments below. Update: discussion on Hacker News.

  1. richardlog posted this