When you write `class W(impl: Foo) : Foo by impl`, is the `impl` value stored and accessible inside the class? How do you access the delegate if you need it?
answer
- Bare param ≠ property → can't reference later
- Add `val` to access the delegate
- `by` expression evaluated once at construction
- Reassigning a `var` delegate does NOT redirect forwarders
- Delegate expr can be any expression, not just a param
basics
~10 sThe compiler stores the delegate in a hidden field, but a plain constructor parameter is not a property, so you can't reference it later. To use it inside the class, declare it as val.
solid answer
~40 sThe expression after `by` is evaluated once and stored in a synthetic field the compiler uses for forwarding. But that field is not directly visible to your code. If you write `class W(impl: Foo) : Foo by impl`, `impl` is a constructor parameter scoped to the constructor — it is NOT a property, so you cannot reference `impl` in methods. To both delegate to it and access it (e.g., in an override that wants to call the delegate), declare it as a property: `class W(private val impl: Foo) : Foo by impl`. Then `impl` is a real field you can call. Note: the `by`-forwarders use the captured value at construction; reassigning a `var` delegate does NOT redirect already-generated forwarders, because they bind to the initial value.
go deeper
Knows you must add val to reference the delegate later.
Distinguishes parameter vs property scope and knows forwarders capture the value at construction.
Explains the var-reassignment non-redirection and that the by expression is any once-evaluated expression.
Considers API ergonomics of exposing vs hiding the delegate and immutability guarantees this gives wrappers.
## Constructor parameter vs property In Kotlin, a constructor parameter written without `val`/`var` is **only** in scope during initialization — it is not a class member: ```kotlin class W(impl: Foo) : Foo by impl { fun touch() = impl.bar() // ERROR: 'impl' is not accessible here } ``` The delegate forwarding still works (the compiler captured the value into a synthetic field), but **you** cannot name `impl` outside the constructor. ## Making the delegate accessible Add `val` (or `private val`) so it becomes a real property: ```kotlin class W(private val impl: Foo) : Foo by impl { override fun bar() { log("before") impl.bar() // now legal } } ``` This is the common idiom when you override a member and still want to call through to the delegate (the Decorator pattern). ## Two fields, subtle point When you write `private val impl` AND `by impl`, conceptually there is the property `impl` plus the delegation. In current Kotlin the compiler is smart enough that the `by impl` forwarders read from your `impl` property field — they don't create a second independent copy that diverges. However, the value used for forwarding is the one bound when the object is constructed. ## `var` delegates and reassignment ```kotlin class W(var impl: Foo) : Foo by impl ``` The generated forwarders bind to the **value at construction time**. Reassigning `impl` later updates the property but does **not** change where the forwarders point. So delegation is effectively fixed at construction — do not expect mutable redirection. ## The `by` expression can be any expression It need not be a constructor parameter: ```kotlin class W : Foo by DefaultFoo() // fresh instance class X(list: List<Int>) : List<Int> by list.toList() // a transformed copy ``` The expression is evaluated once during construction. ## Summary - Bare parameter → forwarding works, but name is unavailable later. - `val`/`private val` parameter → forwarding works AND you can reference it. - Forwarders capture the value at construction; mutating a `var` does not redirect them.
- Why declare the delegate `private val` in a Decorator?So an overridden member can still call through to the delegate's original behavior while keeping the delegate hidden from the public API.
- If you make the delegate a `var` and reassign it, do calls suddenly go to the new object?No. The generated forwarders bind to the value captured at construction; reassignment does not redirect them.
saying these in an interview costs you the question
- Thinking a bare constructor parameter is accessible in methods
- Believing reassigning a `var` delegate redirects the forwarders
- Assuming the `by` expression is re-evaluated on each call
- Not knowing `by` accepts any expression, not just a parameter
- Claiming you must duplicate the field manually to access the delegate