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:

val myList: MutableList<Double> = mutableListOf(1.0, 2.0, 3.0)
myList.add(4.0)
println(myList) // [1.0, 2.0, 3.0, 4.0]

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>.

val myDictionary = mutableMapOf(
    "cow" to "moo",
    "dog" to "woof",
    "pig" to "oink"
)

println(myDictionary["dog"]) // woof
println(myDictionary["kitten"]) // null

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.

var string = "Hello"
println(string)
// string = null 
// error: null can not be a value of a non-null type String

var string2: String? = "Hello"
println(string2) // hello
string2 = null
println(string2) // null

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!

  • To write Android apps, we —Swift programmers— don’t need to learn Kotlin. We could simply write our Android apps using Swift too. Take a look at RemObjects’ Silver and Fire IDE here: http://www.elementscompiler.com/elements/silver/

    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.

    And yes, Silver and Fire IDE are free. So, why bother with Kotlin? 🙂

    • For me it’s a matter of trust and avoiding reliance on 3rd party solutions

      • So, you never use 3rd party solutions at all? You should use Java, instead of Kotlin then. Because Kotlin is also 3rd party (JetBrains) solution. ????

    • 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.


      let numbers = [2, 13, 11, 4, 7]
      var otherNumbers = numbers

      otherNumbers[2] = 5

      print(numbers) // prints [2, 13, 11, 4, 7] in Swift, but [2, 13, 5, 4, 7] in Silver.

      The switch from ARC to .NET/JVM’s GC is trivial by comparison.

  • Very good post; I am learning Kotlin too, and this was very helpful. Please keep them coming!

  • Very interesting post, I like the Swift / Kotlin comparaison on a specific topic, please continue !