codete Yet Another Kotlin Tutorial for Android Developers Part 1 1 main e2ceaf40b1
Codete Blog

Yet Another Kotlin Tutorial for Android Developers – Part 1

avatar male f667854eaa

31/03/2016 |

6 min read

Witold Wiśniewski

Welcome to the very beginning of the series about Android development with kotlin. This article will be a gentle introduction, focusing on the language itself. 

To be more specific - I would like to present some mechanisms and use these as arguments for considering if Kotlin is worth a shot. 

 

Properties

In the Kotlin world, classes cannot have fields, just properties. `var` keyword tells us the property is mutable, in contrast to `val`. Let’s see an example: 

class Contact(var number: String) {


   var firstName: String? = null
   var lastName: String? = null
   private val hasPrefix : Boolean
       get() = number.startsWith("+")


}

There is not much code, but lots of things are happening behind the scenes. We will go through it step by step.

First of all, we created the public final class `Contact`. As I come from Java, my first reaction was like: 

http://memesvault.com/wp-content/uploads/Wat-Meme-Old-Lady-01.jpg

This is the primary rule we have to face: if not specified otherwise, classes are public and final by default (by the way, the same is for class methods). If you want to inherit from a class, mark it with the `open` keyword. 

We have also created a primary public constructor, which takes `number` as the parameter. Note a `var` keyword in constructor signature - this is property declaration, with default getter and setter. This is not the only way to declare property, it is possible also in the class body - look at `firstName`, `lastName`, and `hasPrefix`. 

You have probably noticed something strange, a `?` mark, but please do not focus on it now, this will be discussed later in this article (TODO interactive link). 

As mentioned before, Kotlin provides default getter and setter for each property (which are named after it, f.e. `contact.firstName=” John”`), but you are allowed to make some customization - look at `hasPrefix`. Modification of getter/setter visibility can also be changed, keep in mind that getter’s visibility must be the same as property’s visibility. 

There is one more thing - my IDE shows an alert: This property has a backing field when hovering over `firstName`. It took a while for me to understand what the backing field is as in the Java world there is no such distinction, but this is what I figured out. I like to think properties are boxes that define an object’s state. 

The backing field is the content of the box, the value itself, and when a property is accessed, this content is unwrapped (or a new value is put inside the box). You may say ‘ok, so is `hasPrefix` a property? It is not holding any value’. That’s right, it does not wrap any value, but it is a property. 

The difference is, that properties without a backing field get the state from a different source, they must open another box. 

So far so good, but let’s see when the backing field may be helpful. Assume we want to have for some reason the first name represented by lower letters. We may define custom setter:

var firstName: String? = null
   set(value) {
       firstName = value.toLowerCase()
   }

Try to run such code. I tried and got StackOverflowError. The thing is, that assignment in 3rd line is implicit setter invocation, so we have never-ending recursion. 

The solution is easy - access to the backing field is possible via the `field` keyword, visible only inside setter (and getter likewise) :

var firstName: String? = null
   set(value) {
       field = value
   }

We learned some basics, it is time for something more interesting.

 

Late initialization

Non-null properties must be initialized either inside the constructor or immediately in the declaration, but sometimes we want to init them later. Good guy Kotlin is aware that such situations exist (for instance when you use dependency injection) and comes with the `lateinit` keyword. 

You can define this property when you need it, but accessing it before initialization will result in `UninitializedPropertyAccessException`.

class Sms {
   var message : String? = null
   lateinit var contact: Contact
}

Keep in mind that only mutable properties with no custom getter/setter can be marked with `lateinit`. Further limitations: it must be a non-null, non-primitive type.

 

Delegates

Yes, the Delegation pattern is built-in. 

var firstName: String? by NameProvider(number)

All we have to do is implement `getValue’ and ‘setValue’ methods inside ‘NameProvider’ class, which are corresponding to the getter and setter of that property. Yes, it is that simple. 

Kotlin also provides built-in delegates. You can use `vetoable` to prevent changing the value of a property. Let’s assume we have method `checkPermissionToModifyContactGranted` returning `Boolean` value.

var firstName: String by Delegates.vetoable("no-name", {
   property, oldValue, newValue -> checkPersmissionToModifyContactGranted()
}) 

If this method returns false, the property will not be changed, as `vetoable` is invoked before assignment. This delegate takes two arguments - default value marked as `no-name` String and a callback function, represented in this example by lambda expression - this will be covered later on, think about it as an anonymous function for now. The main point is that we have to provide a criterium returning `Boolean` to decide whether the value should change.

The other delegate provided by the standard library is `observable`, working pretty much as above. This one enables us to watch when the property is changed.

var firstName: String by Delegates.observable("no-name", {
   property, oldValue, newValue ->
    println("First name has been modified")
}) 

The difference is that the handler method is invoked after assignment, and the handler method does not return anything.

At this point, when we learned what we can do with properties, it is appropriate time to explain what mysterious question mark does.

 

Null safety

Kotlin distinguishes between nullable and non-nullable types, so declaration like  

var contact : Contact = null

will not compile, but there is an easy solution.

var contact: Contact? = null

When the compiler sees such a declaration, it tells ok, you gave me a nullable variable, so let me worry about it. I will remind you about possible null every time you want to access it, so all further invocations require a little special treatment.

 

Safe calls

We can do something like that:

var name = contact?.lastName

Safe call operator `?.` invokes (in this example) getter for `lastName’, so `name` will be assigned with appropriate property or null, if `contact` is null. No more NPE!

http://img1.ak.crunchyroll.com/i/spire3/80fb20a4778ca8143bc26a8eb78492ee1369114012_full.gif

Safe calls can be chained:

var name = sms?.contact?.lastName

or used with Elvis operator:

var name = sms?.contact?.lastName ?: "no-name"

Everything is fine, but what is the type of `name` as no such information provided? The reason why I missed type declaration is a mechanism called type inference - the compiler can guess type from the context.

var name = sms?.contact?.lastName ?: "no-name" // the type is String
var name = sms?.contact?.lastName  //the type is String? (nullable String)

Nullable types can be used with `!!` which means trust me, I know this is not null, but please be careful with this, as it is a potential candidate for the NPE cause.

var contact: Contact? = null
var number = contact!!.number // baaaad practice

 

Summary

We managed to go through null safety as well as properties (and variations about). As you can see, there are few concepts behind, which create numerous ways to accomplish different tasks. This article was just the first part of the series, so wait for more!

Rated: 5.0 / 1 opinions
avatar male f667854eaa

Witold Wiśniewski

Senior Software Developer

Our mission is to accelerate your growth through technology

Contact us

Codete Global
Spółka z ograniczoną odpowiedzialnością

Na Zjeździe 11
30-527 Kraków

NIP (VAT-ID): PL6762460401
REGON: 122745429
KRS: 0000983688

Get in Touch
  • icon facebook
  • icon linkedin
  • icon instagram
  • icon youtube
Offices
  • Kraków

    Na Zjeździe 11
    30-527 Kraków
    Poland

  • Lublin

    Wojciechowska 7E
    20-704 Lublin
    Poland

  • Berlin

    Bouchéstraße 12
    12435 Berlin
    Germany