Kotlin as a better Java and better C yet as demonstrated with a Sudoku verifier

Konrad Banys
Feb 18 · 10 min read
Image for post
Image for post
Photo by Marc Reichelt on Unsplash

At Digital Frontiers we all have our favourite languages. The other day we were arguing about advantages and shortcomings of some specific ones and decided to have a closer look at them, using a Sudoku verifier as common example. If you are also interested in other programming languages, here is a collection of links to the other blog posts in our series:

Because, as I will try to prove here, it is inarguably a better Java (the programming language, not the island) and better C yet and other programming languages that came on the way still. Just recently I had something to do with groovy and was surprised that Kotlin shares some features with this language, too. The prominent C# feature of extension methods also found its way into the language. You could say that the developers of Kotlin gathered a multitude of useful and advanced features without making a java developer sacrifice something or getting really uncomfortable venturing into the New and Unknown.

I remember when I first had any contact with Kotlin. It was during a presentation at a local programming conference. The lecturer has shown in what an uncompromising way Kotlin removes the boilerplate code and enforces a healthy coding style. It amazed me that someone has gone to such an extent to let a programmer just concentrate on transferring his genius idea to the (obviously black) editor window of the only right IDE.

So why Kotlin again? Because this is the language that has the potential to finally replace Java as the mainstream programming language, greatly facilitating adhesion to healthy coding principles and gently leading the object-oriented world to new concepts. And as my colleagues have already done a great deal to spread the word about the greatness of Kotlin, maybe I could, as well, contribute a little bit to the noble cause.

Kotlin is a cross-platform, statically typed, and multiparadigm (functional, imperative, object-oriented, and even procedural) programming language with extensive type interference. It fully interoperates with Java but can also be compiled to JavaScript or native code. It has been created by the developers of JetBrains, the company behind one of the most popular programming IDEs (IntelliJ IDEA). One of the programmers’ favorite features of Kotlin is its null pointer safety — the language effectively does away with null pointer exceptions and detects all uninitialized variables during compilation time.

In fact, it was not quite my intention. In this blog post, I target the people who have no idea about Kotlin whatsoever (or a very vague one) and show them that they do not really have to “learn” a new language and go through the pain of learning new paradigms but still can profit from certain constructions and mechanisms they would understand and appreciate pretty immediately. Therefore I challenged myself to take my Sudoku verifier code written in C and attempt to convert it to Kotlin without changing its algorithm. As I write these words I don’t know myself how this experiment will finish. I’ll let myself be surprised.

As already warned, we deal here with the very same problem as we did in my C language post. We’ve got a very simple problem at hand — we want to know whether a Sudoku that we load from a file (you wouldn’t want to type it in, would you?) is valid or not. We use basically the same algorithm as in the case of C, but now we have all the modern weaponry that should allow us to kill the enemy fast & efficiently.

As I am principally a Java programmer (although I guard a soft place for C# in my heart) and as Kotlin inherits a lot of its I/O classes from Java (why reinvent the wheel?), programming user input wasn’t rocket science. In order to load all the numbers of sudoku I just used the loadNumberList method, pardon, function from the File class (analogically to the C solution, the whole source code of the Kotlin verifier can be found on Github):

private fun readFileContentsIntoList(filePath: String) = File(filePath).loadNumberList(filePath)

“Oh, I did not know the function” — you might say. A quick google search will reveal that there’s no such function. What’s going on then? While this very method is not terribly useful and innovative, it is an example of a very useful construct — an extension function.

fun File.loadNumberList(filePath: String) = readText().trim().split(Regex("\\D+"))

It’s a mechanism that lets you “fix” the “shortsightedness” of the original developers and extend just any class, even the standard ones. Just imagine you could add your own function to String, Integer, or List which makes you feel like a co-author of these classes. Just wow. But jokes aside, you would soon find how handy extension functions are, freeing you from the necessity of writing small but cumbersome utility classes or wrappers.

By the way, with this example, you can already notice how concise Kotlin is, without sacrificing static typing (thus “type inference”). No return type? (But it gets inferred from the return statement) But there’s no return statement?! (return keyword assumed for one-liner function contents). No curly brackets? (Can be omitted for one-liners) And the worst, no semicolon?! (Yes, semicolons are not necessary in Kotlin and that’s one of the features one gets used to pretty immediately).

The simple existence of lists made the process of retrieving numbers from a file and converting them to a two-dimensional sudoku array so much easier (no need for a nodelist class I was forced to use in my C code to accommodate unknown size — either 4x4 or 9x9 — of sudoku in the file) and the concise syntax of array initialization in Kotlin made the code look more elegant, too:

private fun convertElementListToSudokuArray(elements: List<String>): Array<Array<Int>> 
{
val sudokuSize = sqrt(elements.size)
return Array(sudokuSize) { i ->
Array(sudokuSize) { j ->
[...]
elements[i * sudokuSize + j].toInt()
[...]
}
}
}

Just as it was in the case of the C implementation, after retrieving a Sudoku matrix and verifying that its contents are numbers and size is one of the standard sudoku sizes, we proceed to the next step and verify whether the sudoku is valid, that is:

  • there are only numbers between 1 and Sudoku size (size of the dimension of the sudoku matrix, either 4 or 9)
  • the numbers do not repeat in any row, column or any subsection of the matrix sized sqrt(n) x sqrt(n) where n is the sudoku size.

Kotlin excellent support for lambda expressions for arrays and lists have helped to greatly simplify validation per row:

private fun isRowValid(rowNumber: Int): Boolean {

return sudoku[rowNumber].groupingBy {
it
}
.eachCount().filter {
it
.value > 1 || it.key !in 1..sudoku.size
}.isEmpty()
}

column, or subsection:

private fun isSubsectionValid(row: Int, column: Int): Boolean {

return sudoku.slice(row until row + sudoku.subSectionSize).map {
it
.slice(column until column + sudoku.subSectionSize)
}.flatMap { it.toList() }
.groupingBy { it }.eachCount().filter {
it
.value > 1 || it.key !in 1..sudoku.size
}.isEmpty()
}

If you compare the validation code in C and in Kotlin there are several things to notice and to be thankful for. Gone are all the stars and ampersands of the C and C++ pointer world, tedious debugging through memory faults because you treated a value as a pointer and vice versa. Gone are the auxiliary arrays and variables created to facilitate collecting of validating results and gone so much of initialization code — actually all of it!

Notice the very convenient construct of ranges:

row until row + sudoku.subSectionSize

and:

valueToCount.key !in 1..sudoku.size

… that can be used instinctively and understood even by people without coding background. The language designers even thought about a very useful until keyword which is a clean way of showing that the range should finish at the element BEFORE the specified end. The in keyword used with ranges is so much cleaner than “variable is less than…and variable is greater than…” construction.

Grouping of lambda function results made an additional list to detect duplicates redundant and the Kotlin syntax makes everything look clean and easy and triggers you to want to use it extensively to write your statements as effective as possible — just like LINQ in C#:)

And yet another example of how Kotlin makes your life easy — the useful slice method contributes to simplifying the verification routine for a subsection.

Where in the case of C you see a loop after loop with cryptic thread invocations and then again next loops to gather and verify the results of validation, in the Kotlin code there’s basically only one short loop that starts verification of all rows, columns, and subsection and one loop to obtain the final result of validation:

fun isValid(): Boolean {
//starting validation methods
with(sudoku) {
val deferredList = indices.map {
listOf(async { isRowValid(it) },
async { isColumnValid(it) },
async {
isSubsectionValid(
it / subSectionSize * subSectionSize,
it % subSectionSize * subSectionSize
)
})
}.flatMap { it.toList() }
//waiting for the validation to complete, assembling and returning //the final result
return runBlocking {
deferredList.map {
it
.await()
}.none { !it }
}
}
}

You may also notice another Kotlin useful construction: with which is a scope function. In this case, yet again Kotlin delivers on the promise of being concise letting you skip repeating the object name within its context limited by the curly brackets. And if you paid attention, you have noticed the subSectionSize which is an extension property — yes, the extension functions mechanism works also for properties. Placing the calculation of the value in property seems to be inefficient, but in this case, the performance tradeoff is negligible and the change keeps the validation code cleaner.

When I started writing the blog post I had no experience with coroutines (a type of light-weight threads implemented Kotlin) whatsoever so I hesitated whether I should include them. But as you’ve noticed asynchronous programming in Kotlin can be dramatically easy and self-explanatory, taking all the complexity away from the user:

Run a task asynchronously:

val deferredResult = async { isRowValid(it) }

Verify the task is finished and collect the results:

Code:

val result = deferredResult.await()

The only trace of the fact that something thread-like has been started is the async scope and the await function making sure we’ve collected the results of the coroutine execution. You could say asynchronous execution just cannot get any simpler.

Big advantage of coroutines is that they have a much much smaller footprint comparing to threads. You might consult this short introduction if you are interested in this subject.

You might know the abbreviation from telecommunications but this here is a completely different story. Kotlin was designed to greatly facilitate writing domain-specific languages so even though our tiny wee Sudoku verifier doesn’t really need one, I couldn’t peacefully sleep at night without at least mentioning the concept. DSLs are practical when you have a lot of code to configure an object (a sandwich with all extras and sauces, an HTML document, build process, etc) and when you want to hide this code away from the user and give her a clean abstract interface.

In my case, the configuration is painfully, dreadfully simple. In the end, the only parameter is the file name of the file containing serialized Sudoku. This allows me to create this minute DSL:

sudoku {
file {
<
filePath>
}
}

And then the only thing you have to do is to call the isValid() method on the return value of this construct. Everybody can understand it and the implementation details are completely hidden — only the “domain” is visible.

As one of my colleagues has written an excellent post on Kotlin DSL, I recommend you to consult it if you would like to have a broader picture of the subject and its applications.

if you inspected the code, you’ve might have stumbled upon this function:

fun sqrt(intValue: Int) = sqrt(intValue.toDouble()).toInt()

I’ve written it because the standard Kotlin sqrt function did not accept integer parameters. But to what class does this function belong? Well, to none, not even to Utils, Tools, or anything of the kind where you used to put your methods which you did not know where to put. It’s a so called top level function that you might know from languages like C or JavaScript. Kotlin developers did not shy away from including the procedural paradigm where it is useful, at the same time gently pushing you, also with the excellent help of the only right coding IDE, towards the functional paradigm. This is where the strength and probably the future success of Kotlin lies.

Probably the best idea would be to write a series of blog posts where the code is first written in C, then migrated to C++, then C++ with the Standard Library, then Java, and finally Kotlin, showing how the incremental improvements make the code more understandable and concise. Of course, I have shown only a small section of improvements that Kotlin provides, mainly due to the limitations of the small project and the attention span of an average reader.

Nevertheless, I believe that this blog post has shown you how radically Kotlin makes your developer life easier compared with C and in relation to Java, lets you be even more efficient, concentrate on the gist and explore new concepts still within your comfort zone. The carefully designed language constructs make you write code with pleasure and efficiency and make you constantly search whether you can code your idea even more concisely and elegantly. Because with Kotlin you most probably can.

If you want to learn more about Kotlin, you will find the blog post “7 things any Java developer should know when starting with Kotlin” by my colleague Frank Scheffler very informative. This article in German by the same author treats the Kotlin DSL in greater detail. A blogpost by another colleague, Benedikt Jerat, an interesting discussion on why Kotlin enjoys much bigger success than Scala will also be published soon, so stay tuned.

Digital Frontiers — Das Blog

Dies ist das Blog der Digital Frontiers GmbH & Co.

Thanks to Joachim Baumann and Benedikt Jerat

Konrad Banys

Written by

Digital Frontiers — Das Blog

Dies ist das Blog der Digital Frontiers GmbH & Co. KG (http://www.digitalfrontiers.de). Hier veröffentlichen wir zu Themen, die uns interessieren und bewegen.

Konrad Banys

Written by

Digital Frontiers — Das Blog

Dies ist das Blog der Digital Frontiers GmbH & Co. KG (http://www.digitalfrontiers.de). Hier veröffentlichen wir zu Themen, die uns interessieren und bewegen.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store