Smart Casts

Peter Sommerhoff
A free video tutorial from Peter Sommerhoff
Developer & Software Engineer - With 45,000+ Happy Students
4.5 instructor rating • 6 courses • 62,662 students

Learn more from the full course

Kotlin for Android & Java Developers: Clean Code on Android

Become a professional Kotlin developer and write cleaner code in your Android apps than in Java, avoid boilerplate code

09:14:18 of on-demand video • Updated November 2020

  • Write clean code with Kotlin
  • Avoid ceremony and boilerplate code around Android APIs
  • Use functional programming to write concise, expressive code
  • Create Android apps with Kotlin
  • Write readable SQLite transactions using extension functions in Kotlin
  • Use the Kotlin Android Extensions to avoid findViewById()
  • Create multiple activities, layouts and menus
English -: In this lecture you're gonna learn about smart casts, which are a very nice feature in Kotlin, to make it easier to work with inheritance structures and again to avoid boilerplate code. So lets go ahead and create a new file for this again, and I'm gonna just call this smart casts, and then let's go ahead and create a main function here, and then I'm gonna go ahead again and create an object called vehicle, and I'll explicitly use the drivable interface as the type and then instantiate this to bicycle. So at this point during the execution, the vehicle object or variable here is always just going to be of type drivable to the compiler, even though it is actually instantiated with the more concrete or more specific class bicycle. So this again goes back to this good practice I mentioned before to only use the most abstract interface you can, but in this lecture we're actually gonna use this to talk about how to differentiate between different types if you have to in Kotlin. So this is what's 'instanceof' in Java, and it's just called 'is' in Kotlin. So now at this point here we can only call, because that's the only method you find on the drivable interface, but let's actually go ahead and say 'if (vehicle is Bicycle)', so just like in Java when you check for instance of, it's just that the keyword here is simply 'is', then inside here, you will actually now be able to make use of smart casts in Kotlin, but in order to actually see this difference, we're gonna have to make some changes, or, lets actually just add some extension functions to the bicycle and the boat classes, just so we have some kind of differentiation between the two. So for the bicycle let's say we have an additional method called 'replace wheel', I'm just gonna do a print line on that again, and for the boat class we have startEngine(), which returns a Boolean, so return type Boolean, and it's just going to go ahead and print out 'Starting engine...' and then it's gonna return true. So this way now we actually have a way to differentiate between whether we're dealing with a bicycle or a boat. So now when I go ahead here and say vehicle dot to call a method, then you can see that now we also have the replaceWheel() method here, even though we defined the object vehicle here to just be of type drivable. So in Java when you have a condition like 'if (vehicle instanceof Bicycle)', then the next line is normally always something like, 'val b is', and then you just cast the variable to a bicycle here, but that's not how you do it in Kotlin, so in Kotlin you can see that it's gonna automatically cast the vehicle object here to a bicycle in this case, and you can also see in IntelliJ, I'm not sure if you can see in the video, but in your editor you will be able to see that the vehicle object here is also highlighted in green, with a green background, and if you hover over it it's also gonna tell you it was smart cast to a Bicycle. So the green background always means that a smart cast has happened, because inside this condition here the compiler can actually infer that vehicle is of type bicycle, so its safe to call the method replaceWheel(), which only exists for bicycles. And similarly, you can go ahead and say 'else if (vehicle is Boat)', then of course you can similarly just go ahead and call vehicle.startEngine(). So in this case it's gonna smart cast the vehicle object to a boat. So this is a very neat feature, but we can actually go a bit further with the examples, which is also gonna be a bit of a logic exercise, so lets take a look at this. So what I can also do is I can say, if vehicle is boat and vehicle.startEngine() then I'm gonna do something, that's not really important for us, the important thing here is that in the second part of our condition, the vehicle object was again cast to a boat. Now at this point, in order to understand why this is actually possible, it's important to know that, just like in Java, Kotlin will only evaluate the second part of this condition if the first part here is true. And this is actually something that programmers make use of quite a lot, so whenever you have an 'and' operator in your condition, then Java and also Kotlin are gonna go ahead, look at the first expression or the first part here, 'vehicle is Boat' and if that part's already false, it's just not gonna go ahead and even evaluate the second part, because if this first part here is false, then the whole condition can't be true any more. So only if vehicle is of type boat, only then it's gonna go into the second part here, so now the Kotlin compiler can again infer that vehicle is indeed of type boat, so again it's gonna be able to smart cast this to a boat, so that we can call startEngine(). And similarly you could also go ahead and say if vehicle is not instance of, or is not boat, and then use the or operator for this junction, then you can also actually call startEngine(), and the compiler can again smart cast this to a boat. Now I'm gonna challenge you to think about why this is possible again with the same kind of reasoning that we did for the end operator here, in case you're already familiar with this, you probably know why this works, but just think about in what cases the second part of the condition here actually has to be executed, and in which cases it doesn't. So now the last example I wanna do is, if vehicle is not a bicycle, let's say, then we're just gonna return. So so far no smart casting here, but now after this block you can go ahead and just call replaceWheel() on this, and again the compiler is just gonna smart cast this to a bicycle, because at this point at the execution, the vehicle object can only be of type bicycle, because if it wasn't of type bicycle, it would already have returned at this point. So I think it's just very interesting to see how clever the Kotlin compiler actually is, and in what kind of cases it can infer the type of an object, and will then just help you with smart casting the variable, so that you don't have to write that kind of boilerplate code. So again, this increases readability, it also makes your code more concise, more understandable, so it's really a very nice feature, and, well, there's really no drawback to it. Alright, so what you should take away from this lecture is that 'instanceof' is called 'is' in Kotlin, and whenever you have to do this, make sure to remember that Kotlin can use smart casts, so whenever you have something like this, there's no need to cast the object yourself, just make use of smart cast and call the method you wanna call, and also I think the other takeaway is just that, the compiler's quite clever and can infer, in many cases, where it's possible, that an object has a specific type. So that's all for this lecture, thanks a lot for watching again, if you have any questions, let me know in the Q&A, and otherwise, I'm gonna see you in the next lecture.