1

I want to have for example:

class Foo {
   fun doSomething(arg1: String, arg2: String, arg3: Boolean)
}

class FooDelegate {
   //different fun name
   fun execute by Foo::doSomething
}

Either with reflection or other way.

What I currently have is:

class FooDelegated<R>(
    private val func: KFunction<R>
) {
    fun execute(vararg params: Any) = func.call(*params)
}

So that I can call

FooDelegated(Foo::doSomething).execute("1", "2", true)

However I require to send parameters which are not really know. I would like my compiler to know which parameters can be sent. Else, I can write the following and it won't fail until run time:

   FooDelegated(Foo::doSomething).execute("1", "2", "new argument", false)

NOTE that I want it to have different names, not by using interfaces.

htafoya
  • 18,261
  • 11
  • 80
  • 104
  • How would `fun execute by Foo::doSomething` ever work? You don't even have an instance of `Foo`! Do you expect `execute` to take an extra parameter of `Foo`? – Sweeper Oct 12 '21 at 19:45
  • Also, what is wrong with `fun execute(arg1: String, arg2: String, arg3: Boolean) = someFoo.doSomething(arg1, arg2, arg3)`? – Sweeper Oct 12 '21 at 19:53
  • I can't think of any possible way to do this at compile time with annotations. Reflection is useless since that is done at runtime. I think you would need a customized Kotlin compiler to achieve this. – Tenfour04 Oct 12 '21 at 19:56

1 Answers1

3

Instead of creating execute() function, you can create execute property and keep a function reference there. Then you can use it almost like it is a function:

class FooDelegate {
    val execute = Foo::doSomething
}

fun main() {
    FooDelegate().execute(Foo(), "hello", "world", true)
}

Or:

class FooDelegate {
    private val foo = Foo()
    val execute = foo::doSomething
}

fun main() {
    FooDelegate().execute("hello", "world", true)
}

You can also create a wrapper around KFunction to hide its properties like annotations, isFinal, etc., but keep its operator fun invoke functionality. This would give you more flexibility on what you can do with these functions. It would also make possible to replace execute property with a true execute() function. However, you would need to create a separate wrapper per number of properties. It could look like this:

fun main() {
    delegate(Foo()::doSomething).execute("hello", "world", true)
    delegate(Foo::doSomething).execute(Foo(), "hello", "world", true)
}

fun <P0, P1, P2, R> delegate(func: (P0, P1, P2) -> R) = FunctionDelegate3(func)
fun <P0, P1, P2, P3, R> delegate(func: (P0, P1, P2, P3) -> R) = FunctionDelegate4(func)

class FunctionDelegate3<P0, P1, P2, R>(
    private val func: (P0, P1, P2) -> R
) {
    fun execute(p0: P0, p1: P1, p2: P2): R = func(p0, p1, p2)
}

class FunctionDelegate4<P0, P1, P2, P3, R>(
    private val func: (P0, P1, P2, P3) -> R
) {
    fun execute(p0: P0, p1: P1, p2: P2, p3: P3): R = func(p0, p1, p2, p3)
}

Still, it sounds like a very strange thing to do. Like you trying to create programming language inside another programming language.

broot
  • 21,588
  • 3
  • 30
  • 35
  • Mm I understand however it doesn't work as I need. What I am really looking forward is to send Foo:doSomething as a parameter, so that the Delegate can use execute to call any other function defined as a parameter. I tryed using a KFunction in the val but it doesn't seem to be able to infer the parameters. – htafoya Oct 12 '21 at 22:11
  • For example: `Delegate(foo::doSomething).execute("1", "2", false)` . I'm exploring some possibilities for an architecture, to create intermediate components without having to create an "empty" class just to have the intermediate component – htafoya Oct 12 '21 at 22:13
  • I updated my answer. – broot Oct 12 '21 at 22:49
  • Thanks, I also thought about that and creating FunctionN variants, then I thought that even so the argument names won't be identified as the original names, but only as p0, p1, p2, etc ; and will probably be more confusing to devs :P. Thank you anyway! – htafoya Oct 12 '21 at 23:31