TypeCheck (‘is’) and Cast (‘as’) in Kotlin

This post was originally posted at https://agrawalsuneet.github.io/blogs/typecheck-is-and-cast-as-in-kotlin/ and reposted on Medium on 24th Nov 2017.
interface Shape {
fun calculateArea(): Float
}
class Circle : Shape {
var radius: Float = 10.0f
override fun calculateArea(): Float {
return (22 * radius * radius) / 7
}
}
class Square : Shape {
var sideLength: Float = 10.0f
override fun calculateArea(): Float {
return sideLength * sideLength
}
}
class Rectangle : Shape {
var length: Float = 10.0f
var breadth: Float = 5.0f
override fun calculateArea(): Float {
return length * breadth
}
}
var shapeObject: Shape
if (/* Some Condition*/) {
shapeObject = Circle()
} else if (/* Some Other Condition*/) {
shapeObject = Square()
} else {
shapeObject = Rectangle()
}
shapeObject.radius = 10.0f //compile time error

‘is’ and ‘!is’ Operators

is’ operator checks the type of variable and returns boolean as true if it matches the type.

if (shapeObject is Circle) {
print(“it’s a Circle”)
} else if (shapeObject is Square) {
print(“it’s a Square”)
} else if (shapeObject is Rectangle) {
print(“it’s a Rectangle”)
}
if (shapeObject !is Circle) {
print(“it’s not a Circle”)
} else if (shapeObject !is Square) {
print(“it’s not a Square”)
} else if (shapeObject !is Rectangle) {
print(“it’s not a Rectangle”)
}

Smart Casts

In other programming languages, the variable requires an explicit casting on the variable before accessing the properties of that variable but Kotlin does a smart casting. The compiler automatically converts the variable shapeObject to a particular class reference once it’s passed through any conditional operator.

var area: Float = 0.0f
if (shapeObject is Circle) {
shapeObject.radius = 10.0f //compiles fine
area = shapeObject.calculateArea()
} else if (shapeObject is Square) {
shapeObject.sideLength = 5.0f //compiles fine
area = shapeObject.calculateArea()
} else if (shapeObject is Rectangle) {
shapeObject.length = 10.0f //compiles fine
shapeObject.breadth = 5.0f //compiles fine
area = shapeObject.calculateArea()
}
if ( shapeObject !is Circle) return
shapeObject.radius = 3.0f /*compiles fine as the non Circle class reference were already returned*/
area = shapeObject.calculateArea()
/* Automatically cast the right-hand side of && to Circle */
if (shapeObject is Circle && shapeObject.radius > 5.0f){
print(“Circle with radius more than 5.0”)
}
/* Automatically cast the right hand side of || to Sqaure */
if (shapeObject !is Square || shapeObject.sideLength < 3.0f){
print(“Either not square or is a square with side length less than 3.0f”)
}
when(shapeObject){
is Circle -> shapeObject.radius = 3.0f
is Square -> shapeObject.sideLength = 4.0f
is Rectangle -> {
shapeObject.length = 5.0f
shapeObject.breadth = 6.0f
}
else -> print(“Undefined type”)
}
var count = 0
while (count < 5 && shapeObject is Circle){
shapeObject.radius = count.toFloat() //compiles fine
area += shapeObject.calculateArea()
}
  • val local variables — always;
  • val properties — if the property is private or internal or the check is performed in the same module where the property is declared. Smart casts aren’t applicable to open properties or properties that have custom getters;
  • var local variables — if the variable is not modified between the check and the usage and is not captured in a lambda that modifies it;
  • var properties — never (because the variable can be modified at any time by other code).

Explicit Cast operator ‘as’

as’ operator works as other languages cast operators which casts the object to another object with particular reference.

var otherShapeObject = shapeObject as Circle
var nullableShapeObject : Circle? = shapeObject as Circle?
var safeCastObject : Circle? = shapeObject as? Circle

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store