Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

Kotlin interface delegation is a language-level feature that allows a class to implement an interface by forwarding all of its public member invocations to a designated backing object. Utilizing the by keyword, the Kotlin compiler automatically generates the necessary boilerplate to route method calls and property accesses from the implementing class to the delegate instance.

Syntax and Mechanics

To implement interface delegation, the delegating class must declare the interface it implements, followed by the by keyword and the instance that will handle the implementation.
interface Engine {
    val cylinders: Int
    fun start()
}

class V8Engine : Engine {
    override val cylinders: Int = 8
    override fun start() = println("V8 starting")
}

// Car implements Engine by delegating to the provided 'engine' instance.
// Note the absence of 'val' or 'var', which prevents the generation of an additional property backing field.
class Car(engine: Engine) : Engine by engine
In this structure, Car is recognized by the type system as an Engine. When start() or cylinders is invoked on an instance of Car, the call is directly routed to the engine object passed via the primary constructor.

Overriding Delegated Members and the this Context

A delegating class retains the ability to provide its own implementation for specific interface members. When a member is explicitly overridden in the delegating class, the compiler uses the local implementation instead of forwarding the call to the delegate.
interface Engine {
    fun start()
    fun rev()
}

class V8Engine : Engine {
    override fun start() {
        println("V8 starting")
        rev() // Internal call to rev()
    }
    
    override fun rev() = println("V8 revving")
}

class CustomCar(engine: Engine) : Engine by engine {
    // Overrides the delegate's method
    override fun rev() = println("CustomCar revving")
}
Critical Behavioral Detail: The delegate object maintains its own this context. If the delegate object internally calls another method of the interface, it will invoke its own implementation, not the overridden version provided by the delegating class. In the example above, calling CustomCar(V8Engine()).start() will print "V8 revving", not "CustomCar revving". This is a fundamental difference between delegation and inheritance. Additionally, when overriding a delegated member, the delegating class cannot access the delegate’s implementation using the super keyword. The delegate is strictly a backing field, not a superclass.

Multiple Delegation

Kotlin supports delegating multiple interfaces within a single class declaration. Each interface must be delegated to a distinct instance that implements that specific interface.
interface Transmission {
    fun shift()
}

class AutoTransmission : Transmission {
    override fun shift() = println("Shifting")
}

class AdvancedVehicle(
    engine: Engine,
    transmission: Transmission
) : Engine by engine, Transmission by transmission

Compiler Behavior (Under the Hood)

Interface delegation is a compile-time mechanism. The Kotlin compiler translates the by keyword into standard JVM bytecode equivalent to the manual implementation of the Delegation pattern. For the Car class defined earlier (declared with engine: Engine rather than val engine: Engine), the compiler generates a single private, synthetic backing field for the delegate and creates proxy methods for every interface member:
// Conceptual Java equivalent of the generated bytecode
public final class Car implements Engine {
    // Synthetic backing field generated by the compiler
    private final Engine $$delegate_0;

    public Car(Engine engine) {
        this.$$delegate_0 = engine;
    }

    @Override
    public int getCylinders() {
        return this.$$delegate_0.getCylinders();
    }

    @Override
    public void start() {
        this.$$delegate_0.start();
    }
}

Instantiation Requirements

The object acting as the delegate must be initialized and available at the time of the delegating class’s instantiation. It is most commonly passed through the primary constructor, but it can also be a directly instantiated object or a companion object, provided it conforms to the target interface.
// Delegating to a directly instantiated object rather than a constructor parameter
class DefaultCar : Engine by V8Engine()
Master Kotlin with Deep Grasping Methodology!Learn More