NSMutableArray, among many other mutable variations on standard types. In Swift, you
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 (
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
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
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.
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 (
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.
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 = 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 !