The Programmers Guide To Kotlin - Smart Casts
Written by Mike James   
Monday, 13 May 2019
Article Index
The Programmers Guide To Kotlin - Smart Casts
Function Types

Kotlin tries to make casting easy and safe. In this extract from the book on Kotlin by Mike James we look at how to handle smart casts and type aliases.

Programmer's Guide To Kotlin

Now Available as a Print Book

cover

You can buy it from: Amazon

Contents

Some Chapters Already Available On The Web

  1. What makes Kotlin Special (Book Only)
  2. The Basics: Variables, Primitive Types and Functions
  3. Control
  4. Strings and Arrays
  5. The Class & The Object
  6. Inheritance
  7. The Type Hierarchy 
            Extract  Type and its problems
            Extract  Smart Casts
  8. Generics
            Extract Basic Generics
            Extract Covariance & Contravariance
  9. Collections, Iterators, Sequences & Ranges
            Extract Iterators & Sequences
  10. Advanced functions 
  11. Anonymous, Lamdas & Inline Functions
            Extract    Annoymous and Lambda Functions
            ExtractInline Functions  **NEW!**
  12. Data classes, enums and destructuring
            Extract  Data Classes
            Extract 
         Delegated Properties 
  13. Exceptions, Annotations & Reflection
            Extract Annotation & Reflection 
  14. Working with Java
            Extract Using Swing  

Smart Casts

To make a safe cast you need to know the type of the object you are working with. This turns out to be very easy. You can use is or !is to test an object's type. 

For example, assuming that the variable myObject is of type Any, but references an object of type ClassA:

if(myObject is ClassA) {
  (myObject as ClassA).myFunctionA()
}

Notice that is tests the type of the object referenced and not the type of the variable referencing it. 

You can use this to make both up and down casting safe but isn't there something a bit redundant in using an if to test that an object is ClassA and then explicitly casting it to that type.

Smart casts are a Kotlin idiom that save you the time and trouble of an explicit cast. You don't need to do anything extra as the compiler tracks your use of is and !is within conditionals and automatically applies a cast. 

Thus the previous example, see the earlier extract, can be written more simply:

var myObject:Any=myObjectA
if(myObject is MyClassA) {
       myObject.myFunctionA()
}

It can even apply an automatic cast within a conditional expression:

myObject is MyclassA && myObject.myFunctionA()==0

You can use smart casts within if statements, when and while. The compiler also checks to make sure that the variable that is the subject of the is cannot change before it is used. 

You don't have to make use of smart casts.

You can always include an as or as? where a smart cast would apply.

Should you use smart casts?

Smart casts do reduce the amount of typing but it could be argued that they result in code that is less clear. I would advise always making casts explicit.  

cover

Overriding & Casting – Virtual methods 

Inheritance in Kotlin is always "virtual" in the sense used in C++ and C#. That is, the method called depends on the type of the object and not the type of the variable at compile time.

For example, if we have two classes:

open class MyClassA{
    open fun myFunctionA(){println("A")}
} class MyClassB:MyClassA() {     override fun myFunctionA(){println("B")}     fun myFunctionB(){println("B")} }

The derived MyClassB overrides the inherited myFunctionA.

Now consider:

val myObjectB=MyClassB()
var myObject:MyClassA
myObject=myObjectB

In this case we have a variable of type MyClassA referencing an object of type MyClassB i.e. a down cast. 

What do you think happens when we call the overridden function?

myObject.myFunctionA()

If you are a C++ or C# programmer then you will expect that it is the original MyClassA version of the overridden function which is used. That is you see an "A" printed.

If you are a Java or a Kotlin programmer you can't really understand why the answer should be anything other than the new overridden version of the function as defined in MyClassB i.e. you expect to see a "B" printed and are mystified as to why "A" would ever be considered a correct result.

The reason for this strange behavior is that in C++ and C# methods are bound to variables at compile time, and as myObject is of type MyClassA it calls MyClassA's functions not MyClassB's functions. To produce the behavior we get in Kotlin in C++ and C# you have to declare the method "virtual" which is another meaning of this popular term. This causes the compiler to bind the variable to the methods of the object it is referencing at runtime. Not as efficient but much more logical.  

In Kotlin the methods used depend on the object that the variable references at runtime not its compile time type.

Another, potentially confusing, way to say this is that all Kotlin methods are "virtual" in the sense of C++ and C#.

<ASIN:1871962536>

<ASIN:1871962544>



Last Updated ( Monday, 17 June 2019 )