Kotlin SAM interfaces

Hi.

I ran into a problem recently while upgrading dependent libraries where a new function was added that overloaded one I was using. The compiler started throwing a compile time error.

Given this function

fun <T> executeWithNull(action: (ofy: SomeObject) -> T): T? {
    val callable = Callable {
        return@Callable SomeObjectService.run {
            val value = SomeObjectService.value()
            action(value)
        }
    }

    return this.timer.time(callable)
}

Where the SomeObjectService has a function run, as below, all works. I’m assuming Kotlin is building an object with a single method in order to map the lambda to the method parameter below.

	public static <R> R run(final Work<R> work) {
		try (Closeable closeable = begin()) {
			return work.run();
		}
	}

Now I add another run method to the SomeObjectService and Kotlin throws a compile time error.

So adding

public static void run(final Runnable work) {
	factory().run(work);
}

inferred type is Unit! but T? was expected

I was hoping to understand if this is a Kotlin compiler “bug” or if I’m just expecting to much (Mapping to the correct method based the return type of the lambda supplied) or if I’m just not understanding the issue at all.

PS wrapping the lambda passed to the function in a new object (Work) works.

I think this: “I’m just expecting to much (Mapping to the correct method based the return type of the lambda supplied)”. it doesn’t sound trivial to do.

I’m not exactly sure why it chose the second run method. Maybe it considered the first to be more generic.

1 Like

Indeed, when there is overload ambiguity:

Any non-parameterized callable is a more specific candidate than any parameterized callable

(more details in this thread)

1 Like

Thanks for responses.

The workaround (implement the interface), was simple enough once I understood the issue.

My bigger concern though is that a 3rd partly library change broke my code even though the library didn’t change anything about the API I was using. Seems I traded off maintainability and consistency for ease of use/less typing. :frowning:

I think that shouldn’t concern you. Adding a new method is also an API change. It would be pretty scary if it would change the behavior without any notice. But if it fails to compile, then I think this is fine.