Recently, my wife picked up a Kindle Fire, and I figured it would be fun to write an app for it. In fact, you may recall that I’ve been trying to make a library app for her for a long time. Well, what a better way to give it another chance than by taking Kotlin for a spin.
Table of Contents
Mobile App Development
My relationship with mobile app development has been rather brief. In fact, my one and only experience with it was my last semester of undergrad in 2016 when I built an Android app to interact with a smart lock.
At the time, I was only familiar with Java, C, Verilog, and x86. For the record, that was the expected repetoire for someone pursuing a Computer Engineering degree. Regardless, I hadn’t had much experience with anything beyond those languages, so I went the Android route to leverage my Java experience.
For those who are curious, we used an Arduino to drive a solenoid lock. The Arduino had a Bluetooth attachment which we used to communicate with the lock through an Android mobile app. To be honest, the project was pretty basic, but I had a lot of fun designing something from the ground up with in a multidisciplinary team.
Fast forward to today, and you’ll find that not much has change—at least not until recently. As a polyglot, I decided to not only take another stab at mobile app development but to also try my hand at Kotlin.
Revisiting PopLibrary
Back in early 2016, I decided to make a library application, PopLibrary, for my girlfriend-at-the-time, Morgan. She wanted something she could use to basically catalog her collection of books, so she could loan them to her students just like a library.
The Path to Failure
To make things interesting, I decided to expand the tool, so I could potentially make some money off it. In particular, I wanted to provide all the same functionality that Morgan wanted with the addition of features like book recommendations. Those recommendations would then tie into my Amazon Associates account which would earn me the big bucks—or at least so I thought.
Turns out, over the span of two years, I was unable to bring that application to life. I guess I just didn’t have the skills to be able to write a full stack application, and that reality never really set in. After all, I tried implementing PopLibrary three separate times:
- Windows app in C#
- JavaFX app
- Laravel web app
After three attempts, I gave up. Then, Morgan bought a Kindle Fire, and I got all excited again. For whatever reason, I felt like things might be different.
Shifting Requirements
After failing three times, I decided this time around that I’d implement all the functionality that Morgan wants first. Then, I’ll try to see if I can make a little money on the side. With that said, PopLibrary should be able to do the following things:
- Display a list of books that the user owns
- Allow user to add and edit their own books (title, image, etc.)
- Persist book data locally (long term goal: cloud storage)
- Offer search and filter features to change which books display
- Allow user to loan books to other users
- Use the camera to scan bar codes
At this point, I already have the first few features implemented, and I’ve only been working on the app for about two days. It pays to have experience!
Kotlin Impressions
All that said, I’m sure you’re not here to learn about my project. You’re probably here for any number of reasons like:
- Finding out whether or not it’s worth checking out Kotlin
- Seeing what a first-timer thinks of the language
- Sharing in some of the growing pains
Whatever the reason is, here’s my take on Kotlin so far.
Save Yourself from Null
Almost every language I’ve had the pleasure of playing with (C, C#, Java, Python, JavaScript, PHP, etc.) has had this notion of null
. To me, null
just made sense. After all, it’s the perfect value to give to a reference type when it’s value doesn’t exist. For example, if you provide a form to a user, and they choose not to fill out some of the optional elements, the values of those elements under the hood should be null
—not some arbitrary value.
Well, at least, that was my understanding of null
. I didn’t realize that it could be such an issue. In fact, there’s been a ton of literature regarding null
as one of the biggest mistakes in computer science. Oddly enough, I hadn’t heard about this animosity toward null
until I was writing my Hello World in Swift article in 2017.
Introducing Nullable
Due to the problems that null can introduce, a lot of modern languages have tried to remove them. At the very least, languages like Kotlin and Swift have wrapped null
in objects which introduces some safety checking. In other words, no more NullPointerExceptions (NPEs) unless you’re asking for them.
In Kotlin in particular, you can set any variable to nullable
using a question mark:
var count: Int? = null
Here, we’ve created a variable called count
of type Int?
meaning count could be a number or null
. When using count
, you might want to call a method on it like the decrement method:
count.dec()
Ideally, this method would decrement count
, but count
isn’t actually a number—it’s null
. In most languages, we’d get an NPE, but Kotlin will actually fail to compile. To accomodate for this, we have to change the syntax slightly:
count?.dec()
Here, we’ve performed a safe call on count
. If count
is null
, the entire chain will return null
, but we won’t get an NPE.
Nullable in Practice
Now, this is an awesome feature for null
haters, but I’ve found that it can occasionally make life more difficult. For example, I created a Book
class that looks something like the following:
data class Book( val isbn13: String? = null, val title: String? = null, val author: String? = null, val editor: String? = null, val language: String? = null, val coverImageURL: String? = null, val pageCount: Int? = null, val dateOfPublication: Date? = null ) { }
I’ve set every field to nullable
because I don’t want to populate these fields with arbitrary data. In other words, I don’t want to setup the String fields as empty strings or some other arbitrary data because I’d have to remember what that default value was for checking later. Instead, I leave all unfilled fields as null and deal with the null issues as they come.
That said, I have run into a couple issues. For example, if I want to check if a string is contained in the title, I might write something like this:
title?.contains("Gatsby", true)
Of course, the problem here is that this expression could return true, false, or null. In a language like JavaScript, conditions might be able to deal with that kind of ambiguity but not in Kotlin. As a result, we basically have to force the null value to false using the Elvis
operator:
title?.contains("Gatsby", true) ?: false
In other words, if title is null
then the expression returns false.
Now, imagine having some sort of condition that check a few of these terms. Very quickly, we end up with a messy expression which requires the Elvis
operator to handle any sort of null possibilities. I ended up wrapping the expression above in a function and chained the different possibilities together using the OR operator:
checkContains(title, str) || checkContains(author, str) || checkContains(editor, str) || checkContains(language, str)
Obviously, this isn’t ideal, but there are no NPEs! I imagine more seasoned Kotlin developers would have a better way of dealing with this problem, but I’m just trying to get an app running.
Compare Objects with Operator Overloading
While Kotlin’s most interesting feature to me is null safety, I have to say that operator overloading is a close second. Normally, I would be totally against operator overloading as it introduces unnecessary complexity to a language, but I think Kotlin does a pretty nice job with the feature.
Unfortunately, for you to get an appreciation for the feature, you need to know a little bit about how Java works. In particular, you need to be familiar with the equals()
method of objects and the compareTo()
method of the comparable interface.
Object Equivalence
In Java, all objects have an equals()
method, so they can be tested against another object for equality. Of course, the alternative to equals()
is the ==
operator, but it serves a different purpose. Instead of testing whether or not two objects are equivalent, the ==
operator tests whether or not two objects have the same identity. In other words, if two objects have the same identity, they’re actually one object with multiple aliases.
In Kotlin, the ==
is used universally for equality. Meanwhile, identity checking is handled with the ===
operator. As a result, ==
and equals()
are synonymous. Once we’ve implemented the equals()
method, we can use the ==
operator in its place:
val x = Date(1000) val y = Date(1000) x.equals(y) // Evaluates equality based on equals() implementation x == y // Does the same exact thing
As it turns, IntelliJ actually promotes using the operator over the method, and I’m a huge fan. But wait, it gets better!
Object Comparison
In Java, when we want to compare two objects—say, for sorting purposes—we usually make sure to implement the Comparable
interface. As a part of that interface, we have to override the compareTo()
method which takes a pair of objects and returns a number that represents their relationship. When the two objects are equivalent, the method should return 0. Meanwhile, the method should return a positive number when the calling object is the “bigger” object and a negative number otherwise.
Determining which object is “bigger” depends on the type of object we’re using. For example, the string “apple” is smaller than the string “carrot” because alphabetical ordering dictates that “apple” comes first. In other words, compareTo
should behave as follows:
"apple".compareTo("carrot") // Returns some negative number "carrot".compareTo("apple") // Returns some positive number
At any rate, compareTo
is sort of confusing, and Kotlin does a nice job of alleviating some of that confusion by introducing a few operators. Using the same example as above, we can compare “apple” and “carrot” using the relational operators:
"apple" > "carrot" // false "apple" < "carrot" // true
Personally, I used this for sorting books by their Lexile level. In my project, Lexile
is a class which implements Comparable
. To compare them, I use their numeric value:
override fun compareTo(other: Lexile): Int { return this.toInteger() - other.toInteger() }
Then, I can compare two Lexile
objects as follows:
val lex1 = Lexile(270, Lexile.LexileType.NA) val lex2 = Lexile(400, Lexile.LexileType.NA) assertTrue(lex1 < lex2)
Now, I think that’s pretty cool.
Say Goodbye to Verbosity
One of the biggest complaints people have about Java is the language’s verbosity. In particular, variable definitions require an overwhelming amount of detail:
ArrayList<Integer> myList = new ArrayList<Integer>()
In order to create this list, we had to specify a lot of information:
- Type, twice
- Generic type, twice
- Name
- Keyword (new)
- Operator (=)
- Constructor
Naturally, this line of code can grow exponentially in length depending on factors like the length of the type’s name, the number of nested generic types, and the size of the constructor.
To deal with this, Kotlin introduces a much more concise syntax:
val list = arrayListOf<Int>()
Obviously, there’s a lot going on here, but it’s important to take note of the lack of redundant information. We don’t specify the type, but we have the option. Also, populating the ArrayList
is significantly easier:
val list = arrayListOf<Int>(5, 6, 8, -4)
Now while the reduced verbosity is nice, I would also like to point out that Kotlin has introduced two new keywords as well: val
and var
. We use val
when we want to mark a variable as immutable or read-only (think final
from Java) and var
to mark a variable as mutable.
Mastering the Art of Flow Control
If there’s anything I’ve learned from playing around with programming languages, there are a ton of flow control mechanisms. For instance, there are if statements and loops just for starters. Then, there are fun mechanisms like goto and switch statements which offer even more options for flow control.
All that said, Kotlin introduced yet another flow control mechanism to me: when
. It’s essentially a switch
statement, but I find the syntax to be a lot cleaner:
override fun toString(): String { return when (this.type) { LexileType.NA -> level.toString() + "L" else -> type.name + level.toString() + "L" } }
In this method, we’ve overridden the toString()
method to return a string under two possible conditions:
- The type is NA
- The type is anything else
In particular, we return the result of a when
statement which accepts this object’s type (same Lexile
class from earlier). If the type is NA, we return some string. Otherwise, we return some other string.
In my opinion, the when
statement is clever because it removes a lot of redundant code that you might find in a switch
statement: break, return, etc. Naturally, I’ve been using them quite a bit because IntelliJ actually prefers them over chains of if statements. Also, I just think they’re cool.
The Verdict
As of right now, I like Kotlin a lot. The null safety feature has been tough to work around, but everything else is great. Kotlin is everything I love about Java plus everything I love about higher level languages like Python. With most of the boilerplate out of the way, I feel like I can really build something quickly while also relying on all the amazing static analysis utilities that come standard with compiled languages.
All that said, we’ll see how I’m feeling soon. I’m probably just in the honeymoon phase, but I’m really enjoying this language. It sort of reminds me of how I felt when I first started using C#—both are big improvements over Java.
Since this is my first time really reviewing a language in depth like this, I don’t really have any articles to recommend. Regardless, here are a couple articles I’d love to get in front of more eyes:
Also, if you enjoyed this article, give it a share! By the time it publishes, I will probably have a totally different opinion on the subject, so let’s also have a dialogue. For those of you that want to foster some community, make your way over to the members page and sign up! For the less committed, there’s also a newsletter. As always, thanks for stopping by!
Recent Posts
Recently, I was thinking about the old Pavlov's dog story and how we hardly treat our students any different. While reflecting on this idea, I decided to write the whole thing up for others to read....
In the world of programming languages, expressions are an interesting concept that folks tend to implicitly understand but might not be able to define. As a result, I figured I'd take a crack at...