Friday, September 8, 2017

Kotlin cheat sheet

Yet another kotlin cheat sheet.
Enjoy!

Variable declaration
Java:

public class JavaFile {
    String mutableVariable = "Mutable";
    final String finalVariable = "NotMutable";
    private final String privateVariable = "privateNotMutable";
    private String initialNull = null;
}

Kotlin:

class KotlinFile {
    var mutableVariable = "Mutable"
    val finalVariable = "NotMutable"
    private val privateVariable = "privateNotMutable"
    var initialNull: String? = null
}
...and Kotlin also has a couple of new ways. One of them is lateinit var:

class KotlinFile {
    var mutableVariable = "Mutable"
    val finalVariable = "NotMutable"
    private val privateVariable = "privateNotMutable"
    var initialNull: String? = null

    lateinit var somewhatNull: String
    init {
        somewhatNull = "Initialized at a later time"
    }
}


Methods / Functions (in practice they are the same things)
Java:

public class JavaFile {
    private void myVoidMethod(){
        // do something
        // no returns
    }
    
    public String myStringMethod() {
        return "";
    }
    
    public Double calculateArea(final double width, final double length) {
        return width * length;
    }
}

Kotlin:

class KotlinFile {
    private fun myVoidMethod() {
        // do something
        // no returns
    }

    fun myStringMethod(): String {
        return ""
    }

    fun calculateArea(width: Double, length: Double): Double {
        return width * length
    }
}


Static field
Java:

public class JavaFile {
    final static String MY_CONSTANT = "some_value";
    final static String SOME_OTHER_CONSTANT = "some_value_2";

    // called as:
    // JavaFile.MY_CONSTANT
    // JavaFile.SOME_OTHER_CONSTANT
}

Kotlin (note that Kotlin doesn't really have the concept of static, but you can achieve the same result from this):

class KotlinFile {
    companion object {
        val MY_CONSTANT = "some_value"
        val SOME_OTHER_CONSTANT = "some_value_2"
    }

    // called as:
    // KotlinFile.MY_CONSTANT
    // KotlinFile.SOME_OTHER_CONSTANT
}


Constructors
Java

public class JavaFile {
    private String myString;
    private int myNumber;

    public JavaFile(final String myStringParam, final int myNumberParam) {
        myString = myStringParam;
        myNumber = myNumberParam;
    }
    
    public JavaFile(final String myStringParam) {
        myString = myStringParam;
        myNumber = -1;
    }
}

Kotlin:

class KotlinFile(val myString: String, val myNumber: Int) {

    // in Kotlin, this is called a "secondary constructor"
    // the 'this()' is then calling the "primary constructor"
    constructor(myString: String) : this(myString, -1)
}

Kotlin, option 2:

class KotlinFile(val myString: String, val myNumber: Int = -1) {
    // this then overloads the constructor and generates 2 versions
    // one takes a String and an Int
    // the second one is just a String. The Int value is then set to the defined -1
}



Inheritance and Extension

Let's move on to more complex stuff. Let's say we have some java classes we want extend and implement. Here they are:

BaseAnimal.java

public class BaseAnimal {
    private final int mNumberLegs;
    
    public BaseAnimal(final int numberLegs) {
        mNumberLegs = numberLegs;
    }
    
    public int getNumberLegs() {
        return mNumberLegs;
    }
}

JavaInterfaceOne.java

public interface JavaInterfaceOne {
    void makeDrink(final String someFlavor);
}

JavaInterfaceTwo.java

public interface JavaInterfaceTwo {
    void makeSandwich(final String someIngredient);
}

We want to extend the base class, and implement the interface classes. Here's how we do it.

Java:

public class JavaFile extends BaseAnimal implements JavaInterfaceOne, JavaInterfaceTwo {

    public JavaFile() {
        super(4);
    }

    @Override
    public void makeDrink(String someFlavor) {
        // do something
    }

    @Override
    public void makeSandwich(String someIngredient) {
        // do something
    }
}
In case there's any doubt, we extend the BaseAnimal class. Because of this we need to have a constructor and invoke the super constructor with some integer for the number of legs.
The other 2 methods are because we're implementing 2 other classes, and each class requires to override each of their methods.

Now, here's how we do it using Kotlin:

class KotlinFile: BaseAnimal(4), JavaInterfaceOne, JavaInterfaceTwo {
    override fun makeDrink(someFlavor: String?) {
        // do something
    }

    override fun makeSandwich(someIngredient: String?) {
        // do something
    }
}
A few notable differences:
  • There's no implements or extends keyword anymore
  • We declare that we're going to implement or extend a class by adding a colon ( : ) after our class name. If our class has a constructor, then its class ClassName() : SomeInterface
  • We use parenthesis (technically a constructor) for classes we extend
  • We don't use parenthesis for classes we implement
  • If we need to call a super for the base class, we pass that in the constructor of the class we're extending (notice the (4) next to BaseAnimal)
  • Android Studio autocompletes the variables inside the Interface methods as conditionals (with the question mark ? ). I'm currently not sure why, of it is better to have it.

At this point, this will work. This will work as a Java class, and as a Kotlin class.
Why would I even mention this??

There's an interesting difference with Kotlin regarding extending a class...
Let's say we create our Base class in Kotlin instead:

class BaseAnimalKotlin(val numberLegs: Int)

And now let's modify our Kotlin class to extend this new Kotlin version of the Base class:

class KotlinFile: BaseAnimalKotlin(4), JavaInterfaceOne, JavaInterfaceTwo {
    override fun makeDrink(someFlavor: String) {
        // do something
    }

    override fun makeSandwich(someIngredient: String) {
        // do something
    }
}
This will, unfortunately, not even compile. The error is: "This type is final, so it cannot be inherited from"
What is this???

In Kotlin, if you want a class to be extended you must "allow" so by making the base class open.
This means that the fix is on our Base class, to be this:

open class BaseAnimalKotlin(val numberLegs: Int)
Notice how the first word in this line is the keyword open. This means our Base class is "open" for extension.
I personally do not like this, but that's just my opinion...

No comments:

Post a Comment