I saw my friend do this in his codebase, but I'm struggling to figure out how to do it with my class.
Suppose I have the following code:
class JobTest {
fun interface JobCompiler {
fun compile(s: String, l: Long): Job
}
data class Job(val name: String, val id: Long)
}
fun main() {
val compiler = JobTest.JobCompiler { s: String, l: Long -> JobTest.Job(s, l) }
val job = compiler.compile("Tom", 100)
println("Name: ${job.name}, Id: ${job.id}") // Prints Name: Tom, Id: 100
}
This compiles and works fine, but I'm reading an example from another class where they are able to just pass ::Job
, and the other two variables are inferred. meaning, They're able to just write:
val compiler: JobTest.JobCompiler = ::Job
However, when I try the above I get the following compiler error:
Type mismatch. Required: JobTest.JobCompiler Found: KFunction2<String, Long, JobTest.Job>
How would I fix this code so that I only need to use ::
??
That implicit conversion of the functional reference to a function interface implementation is supported for function arguments but not variable/property assignments.
But you can do:
val compiler = JobTest.JobCompiler(::Job)
so you’re using it as a function argument (of the implicitly created function for constructing functional interfaces) and then assigning it.
Every functional interface has an implicit "constructor" (not really a constructor) function where the argument is a functional reference matching the signature of its single abstract function.
So in your case, there is an implicit function that would look like the following if you explicitly defined it:
inline fun JobCompiler(block: (String, Long)->Job): JobCompiler = object: JobCompiler {
fun compile(s: String, l: Long): Job = block(s, l)
}
I don't think the Kotlin documentation mentions this. They talk about SAM conversions, which also use this implicit constructor, but not about how you can also pass functional references instead of lambdas.