Object Expression in Kotlin

Sometimes we need to create an object of some class with slight modification, without explicitly declaring a new subclass for it. Java handles this case with anonymous inner classes. Kotlin uses object expression to achieve the same functionality.

This post was originally posted at https://agrawalsuneet.github.io/blogs/object-expression-in-kotlin/ and reposted on Medium on 6th Oct 2018.

We can even create an object expression for an interface or abstract class by just implementing their abstract methods. This functionality is called an anonymous interface implementation or anonymous abstract class implementation.

Let’s understand with examples

We have a class AClass having someFunction in it. We want to pass AClass object to achieve some other functionality but at the same time, we want to override the default functionality of someFunction. Ideally, this can be done by creating another class extending AClass and overriding the someFunction method and then pass the object of extending class. But we can achieve the same using an anonymous inner class in Java.

public class AClass {    public void someFunction(){
System.out.println("SomeClass : some Function");
}
}
public class UsageClass {

public void useSomeClass(AClass someClassObj){
someClassObj.someFunction();
}
}

Now to use the method in UsageClass,

UsageClass usageClass = new UsageClass();usageClass.useSomeClass(new AClass(){
@Override
public void someFunction() {
super.someFunction();
System.out.println("UsageClass : overridden some Function");
}
});

We created an object of AClass and passed it to useSomeClass method also we overridden the functionality of somefunction without extending the class.

The same can be achieved in Kotlin using object expression.

open class AClass {
open fun someFunction() {
println("SomeClass : some Function")
}
}
class UsageClass {

fun useSomeClass(someClassObj: AClass) {
someClassObj.someFunction()
}
}

Now to use the method in UsageClass,

val usageClass = UsageClass()usageClass.useSomeClass(object : AClass() {
override fun someFunction() {
super.someFunction()
println("UsageClass : overridden some Function")
}
})

Same can be possible in the case of anonymous interface implementation or anonymous abstract class implementation also.

Let’s have a look.

public abstract class AAbstractClass {
abstract void doSomething();

public void iAmDoingSomething() {
System.out.println("AAbstractClass : I am doing something");
}
}

public interface IInterface {
void canIDoSomething();
}
public class UsageClass {

public void useAbstractClass(AAbstractClass abstractClassObj) {

abstractClassObj.doSomething();
abstractClassObj.iAmDoingSomething();
}

public void useInterface(IInterface iInterfaceObject) {
iInterfaceObject.canIDoSomething();
}
}

Now to use the functions in the UsageClass,

UsageClass usageClass = new UsageClass();usageClass.useAbstractClass(new AAbstractClass() {
@Override
void doSomething() {
System.out.println("UsageClass : I am doing something");
}
});

usageClass.useInterface(new IInterface() {
@Override
public void canIDoSomething() {
System.out.println("UsageClass : can I Do Something");
}
});

The equivalent Kotlin code for the same using object expression will be,

abstract class AAbstractClass {
internal abstract fun doSomething()

fun iAmDoingSomething() {
println("AAbstractClass : I am doing something")
}
}

interface IInterface {
fun canIDoSomething()
}
class UsageClass {

fun useAbstractClass(abstractClassObj: AAbstractClass) {

abstractClassObj.doSomething()
abstractClassObj.iAmDoingSomething()
}

fun useInterface(iInterfaceObject: IInterface) {
iInterfaceObject.canIDoSomething()
}

fun useSomeClass(someClassObj: AClass) {
someClassObj.someFunction()
}
}

To use the UsageClass,

val usageClass = UsageClass()usageClass.useAbstractClass(object : AAbstractClass() {
override fun doSomething() {
println("UsageClass : I am doing something")
}
})

usageClass.useInterface(object : IInterface {
override fun canIDoSomething() {
println("UsageClass : can I Do Something")
}
})

If a supertype has a constructor, appropriate constructor parameters must be passed to it. Many supertypes may be specified as a comma-separated list after the colon :

open class BClass(val x: Int){
open val y = 20
}
interface IInterface {
fun canIDoSomething()
}
val bClassObj : BClass = object : BClass(10), IInterface {

override val y: Int = 30

override fun canIDoSomething() {
println("bClassObj : can I do something")
}

}

We can even create just an object with no nontrivial supertypes. This is called an anonymous object.

val justAnObject = object {
var x = 10
var y = 20
fun sum(): Int = x + y
}

But the anonymous objects can only be used as types only in local and private declarations. If you use an anonymous object as a return type of a public function or the type of a public property, the actual type of that function or property will be the declared supertype of the anonymous object, or Any if you didn’t declare any supertype. In that case, the members added in the anonymous object will not be accessible.

class CClass {
// Private function, so the return type is
// the anonymous object type
private fun privateFunction() = object {
val x: String = "x"
}

// Public function, so the return type is Any
fun publicFunction() = object {
val x: String = "x"
}

fun main() {
val x1 = privateFunction().x // Works fine
val x2 = publicFunction().x // ERROR:
//Unresolved reference 'x'
}
}

One last thing, unlike Java we can access non-final variables also inside an object expression.

int value = 0;usageClass.useInterface(new IInterface() {
@Override
public void canIDoSomething() {
value++; // Error

// variable 'value' is access from withing inner class, needs to be declared final.
}
});

In Kotlin, this works fine

var value = 0

usageClass.useInterface(object : IInterface {
override fun canIDoSomething() {
value++ // works fine
}
})

That’s all for now. You can read my other interesting posts here or you can enjoy my games or apps listed here. Feel free to use my open-source Android components in your app listed here. Or drop an email, if you didn’t find what you are looking for and need some help.

Reference: Kotlin docs