SAM conversion for objects?

When I have a functional interface like

fun interface Transformer<A, B> {
    fun invoke(a: A) : B
}

… I can write…

val intToString = Transformer<Int, String> { i -> i.toString()  }

I assumed the same syntax would also work for objects, so I tried…

object IntToString : Transformer<Int, String> { i -> i.toString()  }

… but this isn’t allowed.

Is there a reason why this wasn’t considered?

When it was felt that the lambda body could be confusing in the case of objects, it would be natural to use a syntax like:

 fun object IntToString : Transformer<Int, String> { i -> i.toString()  }

Please be aware this code fragment uses very similr syntax to a regular object definition, so it is ambiguous - compiler would not know what we mean.

I think it’s a lot more appropriate here to use a val instead:

val IntToString = Transformer<Int, String> { i -> i.toString()  }

because it’s quite unlikely that you want IntToString to also exist as a type

In this specific case I want it as a type, because I need it as an argument of an annotation, where I can only specify classes, not lambdas itself.

I found a workaround I can live with, by specifying the lambda as constructor argument:

open class Transformer<in A, out B>(val lambda: (A) -> B) {
    fun invoke(a: A): B = lambda(a)
}

object AgeTransformer : Transformer<ZonedDateTime, Int>({ z ->
    ChronoUnit.YEARS.between(z, ZonedDateTime.now()).toInt()
})

This works for me, as I use reflection, and can still call the invoke function as usual.

Nevertheless, I still think “SAM objects” with a fun object ... syntax would be a useful thing.

This seems like a very particular use-case… I imagine 99% of Kotlin users wouldn’t need/use this feature.

2 Likes