Where technology meets something or other

Erica Knows Nothing About Kotlin: Kotlin collections

Cocoa distinguishes NSArray from NSMutableArray, among many other mutable variations on standard types. In Swift, you var or let a collection and let the compiler handle the rest of the details, whether the outcome is mutable or not. Kotlin follows the Cocoa model. It uses distinct collection types based on mutability.

For example, the listOf function returns a new read-only serializable list of elements.

val myList: List<Double> = listOf(1.0, 2.0, 3.0)

You cannot automatically promote typeless literals the way you can in Swift. In Swift the literal “1” doesn’t have an intrinsic type (although it defaults to Int in the absence of any other context). “1” can represent an integer, a double, a float, and more.

Kotlin does not support literal inference. If you use listOf(1, 2, 3) for the preceding example, Kotlin issues an error: “Type inference failed. Expected type mismatch: inferred type is List<Int> but List<Double> was expected”.

Like Swift, Kotlin’s type inference system permits you to drop the explicit List<Double> type annotation from the myList declaration. The listOf function still produces the expected type, which the compiler assigns to the constant myList. In this declaration, Kotlin’s val is the same as Swift’s let. It produces a constant rather than a (var) variable.

However, the list you produced is not a value type. Switch the list from immutable to mutable, and you’ll still (like an NSMutableArray reference) be able to add new members:

You won’t be able to re-assign myList to a new list, but as a mutable reference type, the underlying instance can be modified because it is a MutableList<T>.

Kotlin also offers dictionaries, which it calls maps. That’s really not a bad name for a type that performs one-to-one mapping, which is all that key-value lookup really does. The underlying types honor that key/value relation. They’re called Map<K, out V> and MutableMap<K, V>.

Like Swift, Kotlin returns a “not there” result for a failed map lookup, but the meaning of null is distinct from Swift’s nil. A type must be nullable (sort of but not entirely like Optional) to store a null reference.

The initial value of string2 is not Optional("hello") or something like that. It feels (at least so far, because I know nothing about Kotlin, see the title of this post) more like the Objective-C nil, that is a null-reference in memory rather than a pointer to a reference type. I’m new to this, so I’m still learning.

Speaking of null, the first string example demonstrates what happens when you assign null to a non-nullable type. You end up with a (more or less) null pointer exception, which is a bad thing.

Getting back to collections, Kotlin also supports sets, both mutable and immutable. All three types: lists (arrays), maps (dictionaries) and sets (sets), inherit from Kotlin Collection, and in turn from Kotlin Iterable. All three types have a way to count the number of elements (or entries), they can be iterated over, and Collection offers many methods that may or may not apply to each type. For example, you don’t use dropWhile on a map/dictionary.

The Collections reference page lists which functions apply to which types. It’s a bit hodgepodge compared to Swift’s cleaner, hierarchical, and protocol-based system. That said, all the things you would expect to do to an array, set, or dictionary in Swift, you can do to a list, set, or map in Kotlin. Have a browse through that Collections page to get a sense of the functionality. It’s all pretty familiar.

If anything, the various subtypes (LongArray, ByteArray, IntArray, etc) feel like overkill and the available functions feel a tiny bit bloated. But that’s me looking at this stuff with Swift-ized eyes.

If you like this series of posts, let me know. Drop a tweet, email, or comment if you’d like me to keep going.

7 Comments

Perfectly timely discussion as I’m just now taking a feature from our iOS app in Swift and bringing it over to our Android app in Kotlin – having never written any code in Kotlin or on Android. Keep the posts coming!

Silver is RemObjects’ implementation of Swift language using their own compiler. Silver has 99.99% compatibility with the original Apple’s Swift, plus some extra cross platform features. For Mac users, Silver comes with its own IDE to create native cross platform apps (for Cocoa/iOS+macOS+tvOS+watchOS, Android/Java, .Net+Windows/C# and Linux). However, we still need each platform SDK to write apps for them.

The big problem with Silver is that it’s a fundamentally incompatible implementation of Swift. Collections in Silver (including Strings) all have reference semantics, which is an insurmountable difference from Swift proper.