Multi-delegation/proxy class support

Kotlin has some nice features, and one of them I find really useful and use regularly, is delegation. However, while it works well for one to one relationships (one interface delegated to one implementation), there are instances when one needs to use a proxy approach, where a main class implements an interface, and has not just one, but multiple instances of implementations of the same interface to delegate the calls to.

Currently I solve this issue manually, which can result in a lot of manual boilerplate writing. I’d like to avoid this, as this approach is something that can be safely generated by even annotation processors, however a language native solution (even if it’s just compile-time desugaring and codegen), would be incredibly useful.

A sample of the pattern I’m using:

interface MyStuff {
   fun myCall(param: Any?)
}

class StuffImplOne: MyStuff {
    override fun myCall(param: Any?) { /* do stuff 1 here */ }
}

class StuffImplTwo: MyStuff {
    override fun myCall(param: Any?) { /* do stuff 2 here */ }
}

class StuffImplThree: MyStuff {
    override fun myCall(param: Any?) { /* do stuff 3 here */ }
}

class StuffProxy: MyStuff {

    private val children: List<MyStuff> // Initialised, of course

    override fun myCall(param: Any?) {
         children.forEach { it.myCall(param) }
    }
}

This would come extremely handy in situations when a single call needs to be spread to multiple users - say, logging spread out to multiple outputs, or analytics to multiple endpoints.

There is a KEEP about improving delegation:

It does not yet include your problem. Maybe you want to add to the discussion there. However I don’t think your use case is common enough to warrant a language feature, even though I understand it. But maybe I didn’t think of the area in programming where this is a common pattern ( I know you mentioned logging, but this is only a handfull of frameworks and most people don’t implement this themselfs)

I’m not sure that it is easy to do this automatically. Any automatic spreading would need to be compatible in that multiplexing is valid. This is not only having a Unit return type on all methods (otherwise how do you determine the return value), but also none of the implementations are allowed to have side effects that implicitly expect single invocation.

You’re describing the Gang-of-Four Composite Pattern here…

It’s not really something that I’d think should be implemented at the language level for delegation, but might prove useful as a compiler plugin for an annotation (as it’s a very common pattern). Something like

@Composite(MyStuff::class)
class Container: MyStuff {
    ...
}

and the compiler plugin could generate children and myCall to make it effectively:

class Container: MyStuff {
    var children: List<MyStuff>(); // optional arg to annotation to make this private
    override fun myCall(...params...) {
        children.forEach { it.myCall(...params...); } 
    }
    ...
}

Probably useful to do for a few other Design Patterns as well

And there’s the question of how exceptions should be handled: pass through? log and continue? collect and re-throw as composite exception? etc. So, coming up with a general-purpose implementation - which doesn’t lead people into common mistakes - would be hard.

I’m not sure the idea of a compiler plugin is so good. While I love annotation processing/compiler plugins in general, I don’t like to have too much “magic” going on, without good reasons. It just makes sharing code/working with other people much harder.
I could support the idea of such a plugin if it supports many different coding patterns. That way it might get enough usage so it won’t just confuse new people when they see the code.
Also there are the problems @pdvrieze and @HughG pointed out. Your plugin would need to sovle all those issues, porbably by providing different solutions, which would lead to a complex system for something that in most cases is done in a few lines.