Solution: Function types and literals

class AnonymousFunctionalTypeSpecified { val add: (Int, Int) -> Int = fun(num1, num2) = num1 + num2 val printNum: (Int) -> Unit = fun(num) { print(num) } val triple: (Int) -> Int = fun(num) = num * 3 val produceName: (String) -> Name = fun(name) = Name(name) val longestOf: (String, String, String) -> String = fun(str1, str2, str3) = maxOf(str1, str2, str3, compareBy { it.length }) } class AnonymousFunctionalTypeInferred { val add = fun(num1: Int, num2: Int) = num1 + num2 val printNum = fun(num: Int) { print(num) } val triple = fun(num: Int) = num * 3 val produceName = fun(name: String) = Name(name) val longestOf = fun(str1: String, str2: String, str3: String) = maxOf(str1, str2, str3, compareBy { it.length }) } class LambdaFunctionalTypeSpecified { val add: (Int, Int) -> Int = { num1, num2 -> num1 + num2 } val printNum: (Int) -> Unit = { num -> print(num) } val triple: (Int) -> Int = { num -> num * 3 } val produceName: (String) -> Name = { name -> Name(name) } val longestOf: (String, String, String) -> String = { str1, str2, str3 -> maxOf(str1, str2, str3, compareBy { it.length }) } } class LambdaFunctionalTypeInferred { val add = { num1: Int, num2: Int -> num1 + num2 } val printNum = { num: Int -> print(num) } val triple = { num: Int -> num * 3 } val produceName = { name: String -> Name(name) } val longestOf = { str1: String, str2: String, str3: String -> maxOf(str1, str2, str3, compareBy { it.length }) } } class LambdaUsingImplicitParameter { val add: (Int, Int) -> Int = { num1, num2 -> num1 + num2 } val printNum: (Int) -> Unit = { print(it) } val triple: (Int) -> Int = { it * 3 } val produceName: (String) -> Name = { Name(it) } val longestOf: (String, String, String) -> String = { str1, str2, str3 -> maxOf(str1, str2, str3, compareBy { it.length }) } }

Example solution in playground

import org.junit.Test import kotlin.reflect.KClass import kotlin.reflect.typeOf import kotlin.test.assertEquals import kotlin.test.assertNotNull class FunctionsClassic { fun add(num1: Int, num2: Int): Int = num1 + num2 fun printNum(num: Int) { print(num) } fun triple(num: Int): Int = num * 3 fun produceName(name: String): Name = Name(name) fun longestOf( str1: String, str2: String, str3: String, ): String = maxOf(str1, str2, str3, compareBy { it.length }) } data class Name(val name: String) class AnonymousFunctionalTypeSpecified { val add: (Int, Int) -> Int = fun(num1, num2) = num1 + num2 val printNum: (Int) -> Unit = fun(num) { print(num) } val triple: (Int) -> Int = fun(num) = num * 3 val produceName: (String) -> Name = fun(name) = Name(name) val longestOf: (String, String, String) -> String = fun(str1, str2, str3) = maxOf(str1, str2, str3, compareBy { it.length }) } class AnonymousFunctionalTypeInferred { val add = fun(num1: Int, num2: Int) = num1 + num2 val printNum = fun(num: Int) { print(num) } val triple = fun(num: Int) = num * 3 val produceName = fun(name: String) = Name(name) val longestOf = fun(str1: String, str2: String, str3: String) = maxOf(str1, str2, str3, compareBy { it.length }) } class LambdaFunctionalTypeSpecified { val add: (Int, Int) -> Int = { num1, num2 -> num1 + num2 } val printNum: (Int) -> Unit = { num -> print(num) } val triple: (Int) -> Int = { num -> num * 3 } val produceName: (String) -> Name = { name -> Name(name) } val longestOf: (String, String, String) -> String = { str1, str2, str3 -> maxOf(str1, str2, str3, compareBy { it.length }) } } class LambdaFunctionalTypeInferred { val add = { num1: Int, num2: Int -> num1 + num2 } val printNum = { num: Int -> print(num) } val triple = { num: Int -> num * 3 } val produceName = { name: String -> Name(name) } val longestOf = { str1: String, str2: String, str3: String -> maxOf(str1, str2, str3, compareBy { it.length }) } } class LambdaUsingImplicitParameter { val add: (Int, Int) -> Int = { num1, num2 -> num1 + num2 } val printNum: (Int) -> Unit = { print(it) } val triple: (Int) -> Int = { it * 3 } val produceName: (String) -> Name = { Name(it) } val longestOf: (String, String, String) -> String = { str1, str2, str3 -> maxOf(str1, str2, str3, compareBy { it.length }) } } class FunctionalTest { @Test fun `AnonymousFunctionalTypeSpecified has correct property signatures`() { checkPropertySignatures(AnonymousFunctionalTypeSpecified::class) } @Test fun `AnonymousFunctionalTypeSpecified has correct property behavior`() { checkPropertyBehavior(AnonymousFunctionalTypeSpecified()) } @Test fun `AnonymousFunctionalTypeInferred has correct property signatures`() { checkPropertySignatures(AnonymousFunctionalTypeInferred::class) } @Test fun `AnonymousFunctionalTypeInferred has correct property behavior`() { checkPropertyBehavior(AnonymousFunctionalTypeInferred()) } @Test fun `LambdaFunctionalTypeSpecified has correct property signatures`() { checkPropertySignatures(LambdaFunctionalTypeSpecified::class) } @Test fun `LambdaFunctionalTypeSpecified has correct property behavior`() { checkPropertyBehavior(LambdaFunctionalTypeSpecified()) } @Test fun `LambdaFunctionalTypeInferred has correct property signatures`() { checkPropertySignatures(LambdaFunctionalTypeInferred::class) } @Test fun `LambdaFunctionalTypeInferred has correct property behavior`() { checkPropertyBehavior(LambdaFunctionalTypeInferred()) } @Test fun `LambdaUsingImplicitParameter has correct property signatures`() { checkPropertySignatures(LambdaUsingImplicitParameter::class) } @Test fun `LambdaUsingImplicitParameter has correct property behavior`() { checkPropertyBehavior(LambdaUsingImplicitParameter()) } private fun checkPropertySignatures( classToCheck: KClass<*>, expectLongestOf: Boolean = true, ) { val c = classToCheck.members val properties = mutableMapOf( "add" to typeOf<(Int, Int) -> Int>(), "printNum" to typeOf<(Int) -> Unit>(), "triple" to typeOf<(Int) -> Int>(), "produceName" to typeOf<(String) -> Name>(), ) if (expectLongestOf) { properties += "longestOf" to typeOf<(String, String, String) -> String>() } for ((propertyName, propertyType) in properties) { val propertyReference = c.find { it.name == propertyName } assertNotNull(propertyReference) { "Property $propertyName is missing" } assertEquals(propertyType, propertyReference.returnType, "Property $propertyName has wrong type") } } @Suppress("UNCHECKED_CAST") private fun <T: Any> checkPropertyBehavior( instance: T, expectLongestOf: Boolean = true, ) { val members = instance::class.members val add = members.find { it.name == "add" }!! assertEquals(3, (add.call(instance) as (Int, Int) -> Int)(1, 2)) assertEquals(12, (add.call(instance) as (Int, Int) -> Int)(4, 8)) val printNum = members.find { it.name == "printNum" }!! (printNum.call(instance) as (Int) -> Unit)(42) val triple = members.find { it.name == "triple" }!! assertEquals(9, (triple.call(instance) as (Int) -> Int)(3)) assertEquals(15, (triple.call(instance) as (Int) -> Int)(5)) val produceName = members.find { it.name == "produceName" }!! assertEquals(Name("John"), (produceName.call(instance) as (String) -> Name)("John")) assertEquals(Name("Jane"), (produceName.call(instance) as (String) -> Name)("Jane")) if (expectLongestOf) { val longestOf = members.find { it.name == "longestOf" }!! assertEquals("abc", (longestOf.call(instance) as (String, String, String) -> String)("a", "ab", "abc")) assertEquals("xyz", (longestOf.call(instance) as (String, String, String) -> String)("x", "xy", "xyz")) } } }