Exercise: Function caller
Your task is to implement methods of a class that is used to call function references with constant values specified by type. This class should have the following methods:
setConstant
- sets a constant value for a given type.call
- calls a function reference with constant values specified by type.
If a constant value for a given type is not specified, an exception should be thrown. Unless the parameter with this type is optional, then its default argument should be used.
class FunctionCaller {
inline fun <reified T> setConstant(value: T) {
setConstant(typeOf<T>(), value)
}
fun setConstant(type: KType, value: Any?) {
TODO()
}
fun <T> call(function: KFunction<T>): T {
TODO()
}
}
fun printStrIntNum(str: String, int: Int, num: Number) {
println("str: $str, int: $int, num: $num")
}
fun printWithOptionals(l: Long = 999, s: String) {
println("l: $l, s: $s")
}
fun main() {
val caller = FunctionCaller()
caller.setConstant("ABC")
caller.setConstant(123)
caller.setConstant(typeOf<Number>(), 3.14)
caller.call(::printStrIntNum)
// str: ABC, int: 123, num: 3.14
caller.call(::printWithOptionals)
// l: 999, s: ABC
}
This problem can either be solved in the below playground or you can clone kotlin-exercises project and solve it locally. In the project, you can find code template for this exercise in advanced/reflection/FunctionCaller.kt. You can find there starting code, example usage and unit tests.
Hint: To support optional parameters, you should use callBy
instead of call
.
Once you are done with the exercise, you can check your solution here.
import org.junit.After
import org.junit.Test
import kotlin.reflect.KFunction
import kotlin.reflect.KType
import kotlin.reflect.typeOf
import kotlin.test.assertEquals
class FunctionCaller {
inline fun <reified T> setConstant(value: T) {
setConstant(typeOf<T>(), value)
}
fun setConstant(type: KType, value: Any?) {
TODO()
}
fun <T> call(function: KFunction<T>): T {
TODO()
}
}
fun printStrIntNum(str: String, int: Int, num: Number) {
println("str: $str, int: $int, num: $num")
}
fun printWithOptionals(l: Long = 999, s: String) {
println("l: $l, s: $s")
}
fun main() {
val caller = FunctionCaller()
caller.setConstant("ABC")
caller.setConstant(123)
caller.setConstant(typeOf<Number>(), 3.14)
caller.call(::printStrIntNum)
// str: ABC, int: 123, num: 3.14
caller.call(::printWithOptionals)
// l: 999, s: ABC
}
class FunctionCallerTest {
var value: Any? = null
fun callStr(str: String) {
value = "callStr $str"
}
fun callInt(int: Int) {
value = "callInt $int"
}
fun callStringInt(str: String, int: Int) {
value = "callStringInt $str $int"
}
data class User(val id: Int, val name: String?, var surname: String?)
fun callUser(user: User) {
value = user
}
fun callWithDefault(c: Char, i: Int = 999, s: String = "XXX", l: Long) {
value = "callWithDefault $c $i $s $l"
}
@After
fun cleanUp() {
value = null
}
@Test
fun testWithString() {
val caller = FunctionCaller()
caller.setConstant("ABC")
caller.call(::callStr)
assertEquals("callStr ABC", value)
}
@Test
fun testWithInt() {
val caller = FunctionCaller()
caller.setConstant(123)
caller.call(::callInt)
assertEquals("callInt 123", value)
}
@Test
fun testWithStringInt() {
val caller = FunctionCaller()
caller.setConstant("DEF")
caller.setConstant(456)
caller.call(::callStringInt)
assertEquals("callStringInt DEF 456", value)
}
@Test
fun testWithUser() {
val caller = FunctionCaller()
val user = User(123, "DEF", "GHI")
caller.setConstant(user)
caller.call(::callUser)
assertEquals(user, value)
}
@Test
fun testIgnoredOptional() {
val caller = FunctionCaller()
caller.setConstant('Z')
caller.setConstant(123L)
caller.call(::callWithDefault)
assertEquals("callWithDefault Z 999 XXX 123", value)
}
}
Marcin Moskala is a highly experienced developer and Kotlin instructor as the founder of Kt. Academy, an official JetBrains partner specializing in Kotlin training, Google Developers Expert, known for his significant contributions to the Kotlin community. Moskala is the author of several widely recognized books, including "Effective Kotlin," "Kotlin Coroutines," "Functional Kotlin," "Advanced Kotlin," "Kotlin Essentials," and "Android Development with Kotlin."
Beyond his literary achievements, Moskala is the author of the largest Medium publication dedicated to Kotlin. As a respected speaker, he has been invited to share his insights at numerous programming conferences, including events such as Droidcon and the prestigious Kotlin Conf, the premier conference dedicated to the Kotlin programming language.