How to get around Type mismatch Required: Foo<Type>, Found: Foo<Type?> - kotlin

Given the following Kotlin code:
class Foo<T>(val t : T?)
fun <T : Any, R : Any> Foo<T?>.transform(transformer : (T) -> R) : Foo<R?> {
return when (t) {
null -> Foo(null)
else -> Foo(transformer(t))
}
}
fun main(args : Array<String>) {
val foo = Foo(args.firstOrNull())
val bar = foo.transform<String, Int> { t -> t.length }
val baz = bar.transform<Int, IntRange> { t -> t..(t + 1) }
}
Why do I get the following error:
Type mismatch. Required: Foo<String?> Found: Foo<String>
If I remove the ? from the extension function to be Foo<T>.transform I instead get the following error:
Type mismatch. Required: Foo<Int> Found: Foo<Int?>
I can understand the second error, because you cannot assign Int? to Int, but the first doesn't make any sense, as you can assign String to String?
EDIT:
I have modified the class Foo<T> to be class Foo<out T> and this works for me as the value t will only ever be read after the initial assignment. With this option I do not need to define the type parameters at the call site of transform.
Another option I have found that I think is a bit messy (and not sure why it makes a difference) is adding a third type parameter to the extension function as follows:
fun <T : Any, U : T?, R : Any> Foo<U>.transform(transformer : (T) -> R) : Foo<R?>
The call site of this on the other hand I find a bit odd. Looking at the above code the call of foo.transform MUST NOT include the type parameters, but the call of bar.transform<Int, Int?, IntRange> MUST include the type parameters in order to work.
This option allows setting the value t at some later point if it were a var instead of val. But it also removes the smart casting on t in the transform function. Although that can be gotten around with a !! if you are not worried about race conditions or (with some additional effort) ?: or ?. if you are worried about race conditions.

You can change your Foo<T> class to be not invariant (see https://kotlinlang.org/docs/reference/generics.html):
class Foo<out T>(val t : T?)
fun <T : Any, R : Any> Foo<T?>.transform(transformer : (T) -> R) : Foo<R?> {
return when (t) {
null -> Foo(null)
else -> Foo(transformer(t))
}
}
fun main(args : Array<String>) {
val foo = Foo(args.firstOrNull())
val bar = foo.transform<String, Int> { t -> t.length }
val baz = bar.transform<Int, IntRange> { t -> t..(t + 1) }
}
The out T specifies precisely the behavior you want.

Since you specify the property t in the constructor as T? you don't need to specify Foo<T?> as receiver and Foo<R?> as return type. Instead use Foo<T> and Foo<R> and it will work.
class Foo<T>(val t : T?)
fun <T: Any, R: Any> Foo<T>.transform(transformer : (T) -> R) : Foo<R> {
return when (t) {
null -> Foo(null)
else -> Foo(transformer(t))
}
}
fun main(args : Array<String>) {
val foo = Foo(args.firstOrNull())
val bar = foo.transform { t -> t.length }
val baz = bar.transform { t -> t..(t + 1) }
}
Note: You don't need to specify the generic types for transform because they can be inferred (at least in this example).

Related

why lambda function parameter's type is Nothing on generic type with asterisk in kotlin?

when i call some api, i wished use multiple callback with generic parameter.
so i defined CallBackData class
class CallBackData<T>(val func: (T?) -> Boolean, val params: T?)
it not data class. because it super class of other callbacks.
and i define Array<CallBackData<*>> variable for multiple callback.
val callbackDts : Array<CallBackData<*>> = arrayOf(
CallBackData(::sampleCallback1, SomeClass(1)),
CallBackData(::sampleCallback2, "hello"),
CallBackData(::sampleCallback3, -1),
)
but when i call func, it say error
Type mismatch.
Required: Nothing?
Found: Any?
i don't get it. why? isn't same it.params type T is same of it.func(param(T))? right? why is Nothing Type? why is not same?
this is full code
fun start(){
val callbackDts : Array<CallBackData<*>> = arrayOf(
CallBackData(::sampleCallback1, SomeClass(1)),
CallBackData(::sampleCallback2, "hello"),
CallBackData(::sampleCallback3, -1),
)
callApi(callbackDts)
}
fun callApi(callbacks : Array<CallBackData<*>>){
callbacks.forEach{
it.func(it.params)
}
}
fun sampleCallback1(params: SomeClass?) : Boolean {
println("sampleCallback1 ${params.toString()}")
return true
}
fun sampleCallback2(params: String?) : Boolean {
println("sampleCallback2 $params")
return true
}
fun sampleCallback3(params: Int?) : Boolean {
println("sampleCallback3 $params")
return true
}
data class SomeClass(val i:Int)
class CallBackData<T>(val func : (T?) -> Boolean, val params: T?)
i tried convert to like this (using out keyword), but it's failed same.(Lambda's parameter type is Nothing?)
fun start(){
val callbackDts : Array<CallBackData<out Any?>> = arrayOf(
CallBackData(::sampleCallback1, SomeClass(1)),
CallBackData(::sampleCallback2, "hello"),
CallBackData(::sampleCallback3, -1),
)
callApi(callbackDts)
}
fun callApi(callbacks : Array<CallBackData<out Any?>>){
callbacks.forEach{
it.func(it.params)
}
}
fun sampleCallback1(params: SomeClass?) : Boolean {
println("sampleCallback1 ${params.toString()}")
return true
}
fun sampleCallback2(params: String?) : Boolean {
println("sampleCallback2 $params")
return true
}
fun sampleCallback3(params: Int?) : Boolean {
println("sampleCallback3 $params")
return true
}
data class SomeClass(val i:Int)
class CallBackData<T>(val func : (T?) -> Boolean, val params: T?)
i look forward to your reply. thanks!
Unfortunately, the type information of T is gone once you projected a CallbackData<T> to CallbackData<*>. It is no longer known that it.func takes the same type as it.params.
But you do know that they are the same type in the CallBackData class itself, don't you? So you can just add a call method
class CallBackData<T>(val func : (T?) -> Boolean, var params: T?) {
fun call() = func(params)
}
and
callbacks.forEach{
it.call()
}
Or you can overload the invoke operator:
operator fun invoke() = func(params)
You would then be able to do it() directly.
Even if you don't have control over CallBackData, you can still add an extension function:
operator fun <T> CallBackData<T>.invoke() = func(params)
Adding to other answers: if this is the only reason why you defined the CallBackData, then you don't really need this class. Kotlin has support for closures, so we don't need to intercept functions and parameters separately:
fun start(){
val callbackDts = arrayOf<() -> Unit>(
{ sampleCallback1(SomeClass(1)) },
{ sampleCallback2("hello") },
{ sampleCallback3(-1) },
)
callApi(callbackDts)
}
fun callApi(callbacks : Array<() -> Unit>){
callbacks.forEach{
it()
}
}
You can define a function
fun <T> CallBackData<T>.call() = func(params)
and then callApi can be changed to:
fun callApi(callbacks : Array<CallBackData<*>>){
callbacks.forEach{ it.call() }
}
Then Kotlin does not have a problem to infer that the types of func and params match for each CallBackData.

Kotlin - Infer type for one of two generic parameters

I am trying to create a function that has two generic types: one reified, and another derived from the context of its usage (since it is an extension function):
inline fun <reified E, A> Either<Throwable, A>.bypassLeft(transformation: Throwable.() -> A): Either<Throwable, A> =
when (this) {
is Either.Left -> when (value) {
is E -> value.transformation().right()
else -> this
}
else -> this
}
The idea would be to call the function just mentioning the reified type, something like:
a.bypassLeft<NoResultException> { "" }
In which "a" is an object of type Either<Throwable,String>
But the compiler is not letting me go away with it, and requires me to specify both generic types, instead of deriving the second one form the object calling the function.
It seemed quite a reasonable thing to be possible, but maybe I am wrong...
Is this possible to achieve? If so, what am I doing wrong?
It's not currently possible with a function to ascribe a single type argument and leave the other inferred. You can achieve what you want if you type the lambda arguments by changing your implementation to not use a receiver type.
I threw in there an additional impl that shows how type args can also be partially applied with a class or other surrounding scope.
import arrow.core.Either
import arrow.core.right
inline fun <reified E : Throwable, A> Either<Throwable, A>.bypassLeft(
transformation: (E) -> A //changed to regular arg not receiver
): Either<Throwable, A> =
when (this) {
is Either.Left -> when (val v = value) { //name locally for smart cast
is E -> transformation(v).right()
else -> this
}
else -> this
}
class Catch<A>(val f: () -> A) { //alternative impl with partial type app
inline fun <reified E : Throwable> recover(
recover: (E) -> A
): Either<Throwable, A> =
Either.catch(f).fold(
{
if (it is E) Either.Right(recover(it))
else Either.Left(it)
},
{
Either.Right(it)
}
)
}
suspend fun main() {
val x: Either<Throwable, Int> = Either.Left(StackOverflowError())
val recovered = x.bypassLeft {
s: StackOverflowError -> //here infers E
0 // here infers A
}
println(recovered) // Either.Right(0)
val notRecovered: Either<Throwable, Int> =
Catch {
throw NumberFormatException()
1
}.recover<StackOverflowError> { 0 }
println(notRecovered) // Either.Left(java.lang.NumberFormatException)
}
This is possible as of Kotlin v1.7.0 with the underscore operator.
The underscore operator _ can be used for type arguments. Use it to automatically infer a type of the argument when other types are explicitly specified:
interface Foo<T>
fun <T, F : Foo<T>> bar() {}
fun baz() {
bar<_, Foo<String>>() // T = String is inferred
}
In your example, it would be possible like this:
a.bypassLeft<NoResultException, _> { "" }

Kotlin - TypeReference<T> Cannot obtain Class<*> For Type Arguments

I've created a Kotlin equivalent of TypeReference<T> like so:
abstract class TypeReference<T> : Comparable<T> {
val type: Type get() = getGenericType()
val arguments: List<Type> get() = getTypeArguments()
final override fun compareTo(other: T): Int {
return 0
}
private fun getGenericType(): Type {
val superClass = javaClass.genericSuperclass
check(superClass !is Class<*>) {
"TypeReference constructed without actual type information."
}
return (superClass as ParameterizedType).actualTypeArguments[0]
}
private fun getTypeArguments(): List<Type> {
val type = getGenericType()
return if (type is ParameterizedType) {
type.actualTypeArguments.toList()
} else emptyList()
}
}
In order to obtain Class<*> of the generic type and its arguments, I've also created the following extension function (and this is where I believe the problem lies, since this is where the stack trace fails).
fun Type.toClass(): Class<*> = when (this) {
is ParameterizedType -> rawType.toClass()
is Class<*> -> this
else -> Class.forName(typeName)
}
I'm unit testing this like so:
#Test
fun `TypeReference should correctly identify the List of BigDecimal type`() {
// Arrange
val expected = List::class.java
val expectedParameter1 = BigDecimal::class.java
val typeReference = object : TypeReference<List<BigDecimal>>() {}
// Act
val actual = typeReference.type.toClass()
val actualParameter1 = typeReference.arguments[0].toClass()
// Assert
assertEquals(expected, actual)
assertEquals(expectedParameter1, actualParameter1)
}
The problem I think, lies in the extension function else -> Class.forName(typeName) as it throws:
java.lang.ClassNotFoundException: ? extends java.math.BigDecimal
Is there a better way to obtain the Class<*> of a Type, even when they're generic type parameters?
You need to add is WildcardType -> ... branch to your when-expression to handle types like ? extends java.math.BigDecimal (Kotlin equivalent is out java.math.BigDecimal), ?(Kotlin equivalent is *), ? super Integer(Kotlin equivalent is in java.math.Integer):
fun Type.toClass(): Class<*> = when (this) {
is ParameterizedType -> rawType.toClass()
is Class<*> -> this
is WildcardType -> upperBounds.singleOrNull()?.toClass() ?: Any::class.java
else -> Class.forName(typeName)
}
Note that in this implementation single upper bound types will be resolved as its upper bound, but all other wildcard types (including multiple upper bounds types) will be resolved as Class<Object>
https://github.com/pluses/ktypes
val typeReference = object : TypeReference<List<BigDecimal>>() {}
val superType = typeReference::class.createType().findSuperType(TypeReference::class)!!
println(superType.arguments.first())// List<java.math.BigDecimal>
println(superType.arguments.first().type?.arguments?.first())// java.math.BigDecimal

Kotlin Current Function Name by Anonymous Object No Longer Works in Kotlin 1.3.x

In Kotlin JVM 1.2.x, I use to be able to do the following:
inline fun <R> Logger.logStuff(
crossinline f: () -> R
): R {
val methodName = object {}.javaClass.enclosingMethod.name
try {
this.debug("$methodName : Begin")
f()
this.debug("$methodName : End")
} catch (ex: Exception) {
this.error("$methodName : Threw exception : $ex")
throw ex
}
}
class Foo {
fun doStuff() = log.logStuff {
1 + 3
}
}
This would give me logs like:
Foo : doStuff : Begin
Foo : doStuff : End
But, after upgrading to Kotlin 1.3.50 (from 1.2.x), I got logs like the following:
Foo : logStuff : Begin
Foo : logStuff : End
I am aware of currentThread().stackTrace[1].methodName to get the enclosing method name, but I was hoping to avoid that.
Is there another way to get the current function name?
You may convert your logStuff() fun to extension and make your R type reified, like this:
inline fun <reified R : Any> R.logStuff() {
val methodName = object {}.javaClass.enclosingMethod.name
}
Update 08/12/22:
What is the difference and what this solution gives us?
We may improve it just a little bit more to visualise it better:
inline fun <reified R : Any> R?.log(msg: String?) = this?.run {
val objectId: String = this::class.simpleName ?: this::class.hashCode().toString()
val methodName = object {}.javaClass.enclosingMethod?.name
Log.d("TAG", "$objectId.$methodName() {\n $msg\n}")
}
Now we may use it just like:
class ExampleClass {
fun exampleFun() {
log("test")
}
}
And it will give us an output like:
ExampleClass.exampleFun() {
test
}
Because log function is inlined, the code will be executed inside an "exampleFun()".
As you may see, there would be a "Current Function Name" in the output. Please also note, that in some cases class may not have a simpleName, that's why there is a fallback to hashCode.
Update 30/01/22:
If above doesn't work for you, please try this:
inline fun <reified R : Any> R?.log(msg: String?) = this?.run {
val objectId: String = this::class.simpleName ?: this::class.hashCode().toString()
val methodName = StackWalker.getInstance().walk { frames ->
frames.findFirst().map { it.methodName }.orElse(null)
}
println("$objectId.$methodName() {\n $msg\n}")
}

Kotlin DSL - union structure

I am designing a DSL and run into a requirement where I have a variable which could be assigned to different ways. Greatly simplified, I would like to set value property either by an integer or by an expression in String. (The real need is even more complex.)
I would like to write in my DSL:
value = 42
or
value = "6*7"
Behind the scene, the value will be stored in a DynamicValue<Int> structure which contains either an integer or the expression.
class DynamicValue<T>(dv : T?, expr : String) {
val directValue : T? = dv
val script : String? = expr
...
}
I tried several ways (delegate, class, etc), but none of them provided these syntax.
Is there a way to declare this union like structure?
What do you think about the following syntax:
value(42)
value("6*7")
//or
value+=42
value+="6*7"
You can do this with operator functions:
class DynamicValue<T>() {
var dv: T? = null
var expr: String? = null
operator fun invoke(dv : T) {
this.dv = dv
this.expr = null
}
operator fun invoke(expr: String) {
this.dv = null
this.expr = expr
}
operator fun plusAssign(dv : T) {
this.dv = dv
this.expr = null
}
operator fun plusAssign(expr: String) {
this.dv = null
this.expr = expr
}
}
You can't redefine the assign operator in Kotlin, therefor the pure syntax value=42 is not possible.
But I wouldn't go with operator functions, it's to magical. I would do this:
val value = DynamicValue<Int>()
value.simple=42
value.expr="6*7"
class DynamicValue2<T>() {
private var _dv: T? = null
private var _expr: String? = null
var simple: T?
get() = _dv
set(value) {
_dv = value
_expr = null
}
var expr: String?
get() = _expr
set(value) {
_expr = value
_dv = null
}
}
Rene's answer gave me the lead and finally I turned up with this solution.
In this solution I took all my requirements in (the ones I dropped out in my original question) so this became much more complicated than my original question would have required.
My whole requirement was to be able to add static values or scripts (snippets) running on a well guarded context. These script would be stored, and executed later. I wanted to enable the whole power of the IDE when writing the script, but would like to guard my scripts from code injections and help the user to use only the context values the script requires.
The trick I used to achieve this is to enable adding script in kotlin, but before I run the whole DSL script and create the business objects, I convert the script into a string. (This string will be executed later in a guarded, wrapped context by JSR233 engine.) This conversation forced me to tokenize the whole script before execution and search/replace some of the tokens. (The whole tokenizer and converter is rather long and boring, so I won't insert here.)
First approach
What my goal was to be able to write any of this:
myobject {
value = static { 42 } // A static solution
value = static { 6 * 7 } // Even this is possible
value = dynamic{ calc(x, y) } // A pure cotlin solution with IDE support
value = dynamic("""calc(x * x)""") // This is the form I convert the above script to
}
where calc, x and y are defined in the context class:
class SpecialScriptContext : ScriptContextBase() {
val hello = "Hello"
val x = 29
val y = 13
fun calc(x: Int, y: Int) = x + y
fun greet(name: String) = println("$hello $name!")
}
So let's see the solution! First I need a DynamicValue class to hold one of the values:
class DynamicValue<T, C : ScriptContextBase, D: ScriptContextDescriptor<C>>
private constructor(val directValue: T?, val script: String?) {
constructor(value: T?) : this(value, null)
constructor(script: String) : this(null, script)
}
This structure will ensure that exactly one of the options (static, script) will be set. (Don't bother with the C and D type parameters, they are for context-based script support.)
Then I made top level DSL functions to support syntax:
#PlsDsl
fun <T, C : ScriptContextBase, D : ScriptContextDescriptor<C>> static(block: () -> T): DynamicValue<T, C, D>
= DynamicValue<T, C, D>(value = block.invoke())
#PlsDsl
fun <T, C : ScriptContextBase, D : ScriptContextDescriptor<C>> dynamic(s: String): DynamicValue<T, C, D>
= DynamicValue<T, C, D>(script = s)
#PlsDsl
fun <T, C : ScriptContextBase, D : ScriptContextDescriptor<C>> dynamic(block: C.() -> T): DynamicValue<T, C, D> {
throw IllegalStateException("Can't use this format")
}
An explanation to the third form. As I wrote before, I don't want to execute the block of the function. When the script is executed, this form is converted to the string form, so normally this function would never appear in the script when executed. The exception is a sanity warning, which would never be thrown.
Finally added the field to my business object builder:
#PlsDsl
class MyObjectBuilder {
var value: DynamicValue<Int, SpecialScriptContext, SpecialScriptContextDescriptor>? = null
}
Second approach
The previous solution worked but had some flaws: the expression was not associated with the variable it set, neither with the entity the value was set in. With my second approach I solved this problem and removed the need of equal sign and most of the unnecessary curly brackets.
What helped: extension functions, infix functions and sealed classes.
First, I split the two value types into separated classes defined a common ancestor:
sealed class Value<T, C : ScriptContextBase> {
abstract val scriptExecutor: ScriptExecutor
abstract val descriptor: ScriptContextDescriptor<C>
abstract val code: String
abstract fun get(context: C): T?
}
class StaticValue<T, C : ScriptContextBase>(override val code: String,
override val scriptExecutor: ScriptExecutor,
override val descriptor: ScriptContextDescriptor<C>,
val value: T? = null
) : Value<T, C>() {
override fun get(context: C) = value
constructor(oldValue: Value<T, C>, value: T?) : this(oldValue.code, oldValue.scriptExecutor, oldValue.descriptor, value)
}
class DynamicValue<T, C : ScriptContextBase>(override val code: String,
script: String,
override val scriptExecutor: ScriptExecutor,
override val descriptor: ScriptContextDescriptor<C>)
: Value<T, C>() {
constructor(oldValue: Value<T, C>, script: String) : this(oldValue.code, script, oldValue.scriptExecutor, oldValue.descriptor)
private val scriptCache = scriptExecutor.register(descriptor)
val source = script?.replace("\\\"\\\"\\\"", "\"\"\"")
private val compiledScript = scriptCache.register(generateUniqueId(code), source)
override fun get(context: C): T? = compiledScript.execute<T?>(context)
}
Note, that I made the primary constructor internal and created a kind of copy and alter constructor. Then I defined the new functions as extension of the common ancestor and marked them infix:
infix fun <T, C : ScriptContextBase> Value<T, C>.static(value: T?): Value<T, C> = StaticValue(this, value)
infix fun <T, C : ScriptContextBase> Value<T, C>.expr(script: String): Value<T, C> = DynamicValue(this, script)
infix fun <T, C : ScriptContextBase> Value<T, C>.dynamic(block: C.() -> T): Value<T, C> {
throw IllegalStateException("Can't use this format")
}
Using the secondary copy-and-alter constructor allows to inherit the context sensitive values. Finally I initialize the value inside the DSL builder:
#PlsDsl
class MyDslBuilder {
var value: Value<Int, SpecialScriptContext> = StaticValue("pl.value", scriptExecutor, SpecialScriptContextDescriptor)
var value2: Value<Int, SpecialScriptContext> = StaticValue("pl.value2", scriptExecutor, SpecialScriptContextDescriptor)
}
Everything is in place and now I can use it in my script:
myobject {
value static 42
value2 expr "6 * 7"
value2 dynamic { calc(x, y) }
}