How to a class with generics with an inline refied function - kotlin

If I have a class like the following:
class SimpleClass {
var test: Int = 1
}
I can do something like this:
inline fun <reified T : SimpleClass> myFunction1(): T {
//Do something with T
}
But if I have a class with generics:
class ComplexClass<T> {
var test: T? = null
}
How can I do the same?
The following doesn't work:
inline fun <reified T : ComplexClass<C>> myFunction2(): T {
//Do something with T
//Do something with C
}
How can I do it?
Here is a more complex example, if needed.

Let's take a look at your example
class Mediator {
//It does't work! My question is about this function.
inline fun <reified T : Container<C>> mediate(string: String): T {
if (C::class == Child1::class)
//Do something
if (C::class == Child2::class)
//Do something else
}
}
class UseExample : Mediator() {
fun example1(): Container<Child1> {
return mediate("test1") // your mediate function does not take
// any parameters to determine the generic type
}
fun example2(): Container<Child2> {
return mediate("test2")
}
}
To perform something with the type C which is used to create Container<C> and perform something with the result type which you represent as T : Container<C> you only need to know the C. Since reified can only be used to keep the type if it is known during the compile time at the call site, rewrite your function signature like this.
inline fun <reified C> mediate(string: String): Container<C> {
// now you know the C and you know the T which is Container<C>
if (C::class == Child1::class) ...
// Since T depends on C, you can only check the C type to perform logic
}
Use it like following
fun example1(): Container<Child1> {
return mediate<Child1>("test") // Note that know your C
// type is known at the function call therefore compiler
// can substitute it with exact type
}
Here is my minimal example from Kotlin Playground
class Container<T>(t: T) {
val smth : T = t
}
class Mediator {
inline fun <reified C> mediate(string: String): Container<C> {
if (C::class == Int::class) {
println("Int")
return Container<Int>(1) as Container<C>
}
throw IllegalStateException("Yopta")
}
}
fun main() {
val m = Mediator()
m.mediate<Int>("ABC") // Output is "Int"
}

Related

Kotlin constrain generic method's type parameter to be a supertype of class's type parameter

I'm trying to get a class similar to this (contrived) example to compile:
class Foo<T> {
val value: T
val condition: Boolean
fun <R> transform(func: () -> R): R {
return if (condition) {
func()
} else {
// Type mismatch: required: R, found: T
value
}
}
}
The transform method can return either value or the result of func(), so T should be assignable to R. Is there a way to express this in Kotlin?
I tried using where T : R, but the compiler doesn't understand that T should refer to the class's T. An extension function could work, but I want to avoid that because it complicates Java interoperability.
You can try this , it works. You need to pass two type params while initializing.
class Foo<T:R,R> constructor(val value: T,val condition: Boolean) {
fun transform(func: () -> R): R {
return if (condition) {
func()
} else {
value
}
}
}
Example:
var s = Foo<String,CharSequence>("12",false).transform {
"as"
}
You pass "12" as string . Transform return "as" value as CharSequence .
Update:
As far as I know, only using extension function might be solve your requirement.
Here is the extension function solution.
class Foo<T> constructor(val value: T,val condition: Boolean){}
fun <T:R,R> Foo<T>.transform(func: () -> R):R{
return if (condition) {
func()
} else {
value
}
}
Example of using extension function solution.
fun main() {
var s1 = Foo(setOf("Hello"),false).transform<Set<String>,Iterable<String>> {
setOf("World")
}
var s2 = Foo(listOf("Hello"),false).transform<List<String>,Iterable<String>> {
listOf("World")
}
}
You just use the type parameter from the class directly. Your method doesn't need to introduce another type parameter:
class Foo<T> {
val value: T
val condition: Boolean
fun transform(func: () -> T): T {
return if (condition) {
func()
} else {
value
}
}
}

Mockito: How to mock lambda callback? what is the type? (Kotlin)

I have two class TestTarget, MockTarget and test code below. If the TestTarget has two functions with same name and same count of parameter, the any() is ambiguous. I need to assign the type to any(ClassType). But what is the type of () -> Unit? I have tried Function0 and it doesn't work. Can anyone help?
Class TestTarget:
Class TestTarget(private val mockTarget: MockTarget) {
fun testFunction() {
// some logic to be tested.
// call mockTarget.doSomething.
}
}
Class MockTarget
Class MockTarget {
fun doSomething(callback: () -> Unit) {
// some logic here.
}
fun doSomething(listener: OtherType) {
// Test code works without this function.
}
}
Test Code:
// setup mocks.
#Test
fun `verify testFunction`() {
`when`(mockTarget.doSomething(any())).thenAnswer { invocation ->
// callback here.
}
}
Replace org.mockito.Mockito with org.mockito.kotlin.*
and you can code like this
val anyLambda = any<() -> Unit>()
val anyListener = any<OtherType>()

Runtime polymorphism in Kotlin

Is there any elegant way to apply polymorphism in this case? The parser provides the following classes at runtime:
class io.swagger.v3.oas.models.media.Schema //is parent of the rest :
class io.swagger.v3.oas.models.media.ComposedSchema
class io.swagger.v3.oas.models.media.ArraySchema
class io.swagger.v3.oas.models.media.StringSchema
class io.swagger.v3.oas.models.media.ObjectSchema
I'd like to have function for each class with the same name and simple, short method which will cast and call necessary function at runtime. Which is actually happening, but I hope there is more brief solution, without necessity of making this kind of duplicates:
fun main() {
val parser = OpenAPIV3Parser()
val asList = listOf(pathYaml3, pathYml2)
val map = asList.map(parser::read)
.flatMap { it.components.schemas.values }
.forEach(::parseRawSchema)
}
fun parseRawSchema(schema: Schema<Any>) {
if (schema is ComposedSchema) {
parseSchema(schema)
}
if (schema is StringSchema) {
parseSchema(schema)
}
...
}
fun parseSchema(schema: ComposedSchema) {
println("Compose-schema")
}
fun parseSchema(schema: StringSchema) {
println("Sting-schema")
}
...
Try use extension.
For example:
fun ComposedSchema.parseSchema() {
println("Compose-schema")
}
fun StringSchema.parseSchema() {
println("Sting-schema")
}
And than:
fun parseRawSchema(schema: Schema<Any>) {
schema.parseSchema()
}

How to combine variable argument definitions and function with receiver in Kotlin

In Kotlin I am able to define a function that accepts a variable number of arguments (see: testVariableArguments below) and I can define a function with a specified receiver (see: testFunctionWithReceiver below). I am wondering if there is a way to combine both of these concepts?
fun main(args: Array<String>) {
testVariableArguments { a: Int -> println(a) }
testVariableArguments { a: Int, b: Int -> println("$a, $b") }
testVariableArguments { a: Int, b: Int, c: Int -> println("$a, $b, $c") }
testVariableArguments { a: Int, b: Int, c: Int, d: Int -> println("$a, $b, $c, $d") }
testFunctionWithReceiver {
doSomething()
doAnotherThing()
}
}
fun <R, T : Function<R>> testVariableArguments(function: T) {
val method = function::class
.java
.declaredMethods
// May need to do something else here to get the
// correct method in case the return type is
// expected to be Object, but for my case it
// would never be Object
.first { m -> m.name == "invoke" && m.returnType != Object::class.java }
val args = method
.parameterTypes
// Mapping to Int here for demonstration, in real
// situations would use the parameter types to
// create the correct value
.withIndex()
.map { i -> i.index }
// Not really needed, but would be if I were
// using multiple types and not just Int
.map { i -> i as Any }
.toTypedArray()
method.invoke(function, *args)
}
fun <R> testFunctionWithReceiver(function: MyInterface.() -> R) {
val myObject = object : MyInterface {
override fun doSomething() {
println("doing something")
}
override fun doAnotherThing() {
println("doing another thing")
}
}
function(myObject)
}
interface MyInterface {
fun doSomething()
fun doAnotherThing()
}
EDIT:
I have found a way to combine these two features, but it is a bit messy at the call site, so if there is a better approach I would be interested.
What I did was add the following operator function to MyInterface
operator fun <R, T : Function<R>> T.unaryPlus() {
testVariableArgumentDefinition(this)
}
Then when I call testFunctionWithReceiver I do the following:
testFunctionWithReceiver {
+{ a: Int, b: Int ->
println("$a, $b")
doSomething()
doAnotherThing()
}
}
You can add parameter requirements to the closure called with receiver by adding:
MyInterface.(P) -> R
Replacing your creation of test parameters with a fixed one, this is what it might look like:
fun <R, P> testVariableArgumentsWithReceiver(param: P, function: MyInterface.(P) -> R) {
function.invoke(myObject, param)
}
fun main(args: Array<String>) {
testVariableArgumentsWithReceiver(17) { a: Int ->
println("$a")
doSomething()
doAnotherThing()
}
}
Of course, you're not as flexible here as you need to pass a single value of type P (which could be an array). You can extend it to MyInterface.(P,Q) but not arbitrary signatures per se.
What you truly want is a signature like this:
fun <R, T: Function<R>> someName(function: MyInterface.T)
or
fun <R, T: FunctionWithReceiver<MyInterface, R>> someName(function: T)
To my knowledge, neither can currently be expressed:
Only function-type literals seem to be allowed as part of extension types; MyInterface.T is not valid code.
There doesn't seem to be a first-class type for functions with receiver; we can't declare FunctionWithReceiver.
This may be worthwhile to bring up on discuss.kotlinlang.org

What is Kotlin's way to have similar effect as flags enum variable in C#

In C#, I can do this.
[Flags]
enum BeerProperty
{
Bold = 1,
Refreshing = 2
}
static void Taste(BeerProperty beer)
{
if (beer == (BeerProperty.Bold | BeerProperty.Refreshing))
{
Debug.WriteLine("I can't qutie put my finger on...");
}
}
static void Main(string[] args)
{
var tickBeer = BeerProperty.Bold | BeerProperty.Refreshing;
Taste(tickBeer);
}
In Kotlin, it seems that I cannot "OR" two flags. What is the Kotlin's way to do this? Using a list of enum variables?
enum class BeerProperty(value:Int)
{
Bold(1),
Refreshing(2)
}
fun taste(beer:BeerProperty)
{
if(beer == (BeerProperty.Bold | BeerProperty.Refreshing))
{
print("I can't qutie put my finger on...");
}
}
fun main(args: Array<String>)
{
val tickBeer = BeerProperty.Bold | BeerProperty.Refreshing;
taste(tickBeer);
}
Added: Thank you for the answer (which I cannot mark as answer yet, due to time limitation). I modified the code like below and achieved what I wanted.
fun taste(beer: EnumSet<BeerProperty>)
{
if(beer.contains(BeerProperty.Bold) && beer.contains(BeerProperty.Refreshing))
{
print("I can't qutie put my finger on...");
}
}
fun main(args: Array<String>)
{
val tickBeer = EnumSet.of(BeerProperty.Bold, BeerProperty.Refreshing);
taste(tickBeer);
}
Using extension functions
import java.util.*
enum class BeerProperty
{
BOLD,
REFRESHING,
STRONG;
infix fun and(other: BeerProperty) = BeerProperties.of(this, other)
}
typealias BeerProperties = EnumSet<BeerProperty>
infix fun BeerProperties.allOf(other: BeerProperties) = this.containsAll(other)
infix fun BeerProperties.and(other: BeerProperty) = BeerProperties.of(other, *this.toTypedArray())
fun taste(beer: BeerProperties) {
if(beer allOf (BeerProperty.BOLD and BeerProperty.REFRESHING and BeerProperty.STRONG)) {
print("I can't qutie put my finger on...")
}
}
fun main(args: Array<String>) {
val tickBeer = BeerProperty.BOLD and BeerProperty.REFRESHING and BeerProperty.STRONG
taste(tickBeer)
}
I use extension functions to allow properties to be added with and, and allof to check all flags are set.
Indeed, in Kotlin every enum constant is an instance of the class corresponding to the enum, and you can't use 'OR' to combine multiple class instances. If you need to track multiple enum values, the most efficient way to do that is to use the EnumSet class.
You can achieve the same result of c# enum flags in this way
enum class TestType(val value: Int)
{
x(1),
y(2),
z(4)
}
fun Int.hasFlag(flag: Int): Boolean
{
return ((this and flag) == flag)
}
Usage:
val myType = TestType.x.value or TestType.y.value //myType = 3
println(myType.hasFlag(TestType.x.value)) //true
println(myType.hasFlag(TestType.y.value)) //true
println(myType.hasFlag(TestType.z.value)) //false
println(myType.hasFlag(TestType.x.value or TestType.y.value)) //true
println(myType.hasFlag(TestType.x.value or TestType.z.value)) //false