Sergey Galkin
Sergey Galkin

Reputation: 179

Kotlin function reified parameter with parametrized return type

I use an in-house Java framework containing the following classes (simplified for demonstration):

    public interface SomeAction<T, R> {
        R run(T t);
    }

    public class ConcreteAction implements SomeAction<Integer, String> {

        @Override
        public String run(Integer arg) {
            return "abc";
        }
    }

    public class ActionFactory {

        public <A extends SomeAction<T, R>, T, R> SomeAction<T, R> create(Class<A> clz) throws IllegalAccessException, InstantiationException {
            return clz.newInstance();
        }
    }

Calling the factory method from Kotlin in a java-way works ok:

ActionFactory().create(ConcreteAction::class.java).run(1)

Then I created the following extension method to make it more concise:

    inline fun <reified A : SomeAction<T, R>, T, R> ActionFactory.create(): SomeAction<T, R> {
        return create(A::class.java)
    }

But a call to ActionFactory().create<ConcreteAction>().run(1) fails with the error 3 type arguments for inline fun ...

Are there any ways to make it work without touching the java code?

Upvotes: 0

Views: 273

Answers (2)

Alexey Romanov
Alexey Romanov

Reputation: 170713

Note: this may not work with actual code depending on what exactly you simplified out. But given this setup, it may be reasonable to assume that the return value of create will actually be an instance of A, in which case

inline fun <reified A : SomeAction<*, *>> ActionFactory.create(): A {
    return create(A::class.java) as A
}

ActionFactory().create<ConcreteAction>().run(1)

will work. The assumption should be documented and tests added if you go that way!

Upvotes: 0

Mikhail Burshteyn
Mikhail Burshteyn

Reputation: 5002

Kotlin does not allow calling a generic function while specifying only a part of the type parameters. If you want to call create with explicit type parameters, you have to specify all three of them:

ActionFactory().create<ConcreteAction, Int, String>().run(1)

Upvotes: 2

Related Questions