Reactor with Kotlin type inference failed with flatMapMany(Flux::fromIterable) - kotlin

Trying to convert a Mono object that has an iterable inside to a Flux I got this error (kotlinc console):
>>> Mono.just(listOf(1,2,3,4,5)).flatMapMany(Flux::fromIterable)
error: type inference failed: Not enough information to infer parameter R in fun <R : Any!> flatMapMany(p0: Function<in (Mutable)List<Int!>!, out Publisher<out R!>!>!): Flux<R!>!
Please specify it explicitly.
(Mono.just(listOf(1,2,3,4,5)) it's just an example to make it simple)
If I change to the following it works:
>>> Mono.just(listOf(1,2,3,4,5)).flatMapMany { Flux.fromIterable(it) }
res28: reactor.core.publisher.Flux<kotlin.Int!>! = MonoFlatMapMany
So replacing flatMapMany(Flux::fromIterable) by flatMapMany { Flux.fromIterable(it) } works, but makes it larger and less functional style, in Java the Flux::fromIterable notation does work (jshell console example):
jshell> Mono.just(Arrays.asList(1,2,3,4,5)).flatMapMany(Flux::fromIterable)
$6 ==> MonoFlatMapMany
I tried to explicitly set the type as required in different ways but nothing works:
Mono.just(listOf(1,2,3,4,5)).flatMapMany<Int>(Flux::fromIterable)
Mono.just(listOf(1,2,3,4,5)).flatMapMany(Flux<Int>::fromIterable)
Mono.just(listOf(1,2,3,4,5)).flatMapMany(Flux::fromIterable<Int>)

Kotlin 1.4 is bringing a more powerful type inference algorithm which might help us with these kinds of issues. But there's nothing we can do about it currently. We just have to write the lambda out explicitly. JetBrains is aware of this usability issue, and is working on it.

Related

Kotlin Function Generics - Upper Bound Not Working

I faced some issue regarding usage of Kotlin generics in functions
fun <T : CharSequence> doSomething(): T {
return String() as T
}
class Something(intValue: Int)
Something(doSomething()) // Doesn't show any compile error
Now when it is executed it throws error
java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Number
Wanted to know why Kotlin compiler is not throwing error for incompatible typecasting
I think what you are seeing is the major compiler bug KT-47664. Though in the bug report they used a much more complex example to demonstrate the issue, the cause of the bug is the same, that being the compiler has inferred an empty intersection type (the intersection of CharSequence and Int is empty) as the type parameter.
The algorithm apparently treats an empty intersection type the same as any other type, doesn't think anything special of it, and so type inference succeeds.
This bug has been fixed by KT-51221 Deprecate inferring type variables into an empty intersection type. From what I understand from reading the reports, there will now be a warning if an empty intersection type is inferred. However, the fix is only included in Kotlin 1.7.20+, which at the time of writing, is not released yet :(

how to convert Java Map to read it in Kotlin?

I am facing some very basic problem (that never faced in java before) and might be due my lack of knowledge in Kotlin.
I am currently trying to read a YML file. So Im doing it in this way:
private val factory = YamlConfigurationFactory(LinkedHashMap::class.java, validator, objectMapper, "dw")
Best on Dropwizard guide for configurations.
https://www.dropwizard.io/1.3.12/docs/manual/testing.html
So later in my function I do this"
val yml = File(Paths.get("config.yml").toUri())
var keyValues = factory.build(yml)
When using my debugger I can see there is a Map with key->values, just as it should be.
now when I do keyValues.get("my-key")
type inference failed. the value of the type parameter k should be mentioned in input types
Tried this but no luck
var keyValues = LinkedHashMap<String, Any>()
keyValues = factory.build(yml)
The YamlConfigurationFactory requires a class to map to, but I dont know if there is a more direct way to specify a Kotlin class than with the current solution +.kotlin, like
LinkedHashMap::class.java.kotlin
Here it also throws an error.
Ideas?
Well, this is a typical problem with JVM generics. Class<LinkedHashMap> carries no info on what are the actual types of its keys and values, so the keyValues variable always ends up with the type LinkedHashMap<*, *> simply because it can't be checked at compile time. There are two ways around this:
Unsafe Cast
This is how you would deal with the problem in standard Java: just cast the LinkedHashMap<*, *> to LinkedHashMap<String, Any> (or whatever is the actual expected type). This produces a warning because the compiler can't verify the cast is safe, but it is also generally known such situations are often unavoidable when dealing with JVM generics and serialisation.
YamlConfigurationFactory(LinkedHashMap::class.java, ...) as LinkedHashMap<String, Any>
Type Inference Magic
When using Kotlin, you can avoid the cast by actually creating instance of Class<LinkedHashMap<String, Any>> explicitly. Of course, since this is still JVM, you lose all the type info at runtime, but it should be enough to tell the type inference engine what your result should be. However, you'll need a special helper method for this (or at least I haven't found a simpler solution yet), but that method needs to be declared just once somewhere in your project:
inline fun <reified T> classOf(): Class<T> = T::class.java
...
val factory = YamlConfigurationFactory(classOf<LinkedHashMap<String, Any>>(), ...)
Using this "hack", you'll get an instance of LinkedHashMap directly, however, always remember that this is just extra info for the type inference engine but effectively it just hides the unsafe cast. Also, you can't use this if the type is not known at compile type (reified).

Why Can't Kotlin Infer The Type For Comparator

Reading the Java interop document about SAM Conversions, I expected the Kotlin function
Collections.sortWith(comparator: kotlin.Comparator<in T> /* = java.util.Comparator<in T> */)
to be able to take a lambda function without needing to explicitly specify the parameter is a Comparator. However the following code gives type inference failed:
val someNumbers = arrayListOf(1, 5, 2)
someNumbers.sortWith({ x, y -> 1 })
whereas:
val someNumbers = arrayListOf(1, 5, 2)
someNumbers.sortWith(Comparator { x, y -> 1 })
compiles and runs correctly
After reading the comments from the Kotlin issue 'SAM for Kotlin classes' I learned a lot regarding the SAM conversion and why typealias was introduced, but not yet why this specific behaviour wasn't solved yet... and I am not the only one as the issue and its comments show.
Summarizing, the SAM conversion was only considered for Java interfaces (compare also this comment). Jetbrains did work on (or still needs to do) a bigger refactoring and tries to solve that issue so that SAMs are also available for Kotlin functions themselves (compare also this comment). They are trying to support SAM conversion for kotlin functions in a separate issue, which could come with 1.3. As I am currently testing 1.3: I did not see anything regarding this yet. So maybe, if you like the SAM conversion as I do, you may want to upvote either SAM for Kotlin classes or SAM conversion for kotlin function or both.
By the way: a very similar example was also used by Ilya Gorbunov using arrayOf().sort.

Jinq in Kotlin - how to convert lambda into java SerializedLambda?

Can I have serializable lambda in Kotlin? I am trying to use Jinq library from Kotlin, but it requires serializable lambdas. Is there any syntax that makes it possible?
Update:
My code:
var temp=anyDao.streamAll(Task::class.java)
.where<Exception,Task> { t->t.taskStatus== TaskStatus.accepted }
.collect(Collectors.toList<Task>());
I am getting this error:
Caused by: java.lang.IllegalArgumentException:
Could not extract code from lambda.
This error sometimes occurs because your lambda references objects that aren't Serializable.
All objects referenced in lambda are serializable (code results in no errors in java).
Update 2
After debugging it seems that kotlin lambda isn't translated into java.lang.invoke.SerializedLambda which is required by Jinq to get information from. So the problem is how to convert it to SerializedLambda.
I'm the maker of Jinq. I haven't had the time to look at Kotlin-support, but based on your description, I'm assuming that Kotlin compiles its lambdas into actual classes or something else. As such, Jinq would probably need some special code for cracking open Kotlin lambdas, and it may also need special code for handling any unusual Kotlin-isms in the generated code. Jinq should be capable of handling it because it was previously retrofitted to handle Scala lambdas.
If you file an issue in the Jinq github about it, along with a small Kotlin example (in both source and .class file form), then I can take a quick peek at what might be involved. If it's small, I can make those changes. Unfortunately, if it looks like a lot of work, I don't think I can really justify putting a lot of resources into adding Kotlin support to Jinq.
I have no experience on Jinq, but according to the implementation in GitHub and my experience of using Java Library in Kotlin.
ref: https://github.com/my2iu/Jinq/blob/master/api/src/org/jinq/orm/stream/JinqStream.java
You can always fall back to use the native Java Interface in Kotlin.
var temp = anyDao.streamAll(Task::class.java)
.where( JinqStream.Where<Task,Exception> { t -> t.taskStatus == TaskStatus.accepted } )
.collect(Collectors.toList<Task>());
// Alternatively, You you can import the interface first
import org.jinq.orm.stream.JinqStream.*
...
// then you can use Where instead of JinqStream.Where
var temp = anyDao.streamAll(Task::class.java)
.where(Where<Task,Exception> { t -> t.taskStatus == TaskStatus.accepted } )
.collect(Collectors.toList<Task>());
Or make a custom extension to wrap the implementation
fun JinqStream<T>.where(f: (T) -> Boolean): JinqStream<T> {
return this.where(JinqStream.Where<T,Exception> { f(it) })
}
Disclaimer: The above codes have not been tested.

How do I do LISP (apply) in Dart?

The docs say to use f.call.apply(arguments), but that seems to only work for object methods, not functions.
testapply.dart:
#!/usr/bin/env dart
say(a, b, c) {
print("${a}!");
print("${b}!");
print("${c}!");
}
main() {
var args = [1, 2, 3];
say.call.apply(args);
}
Trace:
$ dart testapply.dart
'/Users/andrew/Desktop/testapply.dart': Error: line 11 pos 2: Unresolved identifier 'Function 'say': static.'
say.call.apply(args);
^
Is there a way to do LISP (apply f args) without using objects?
Alternatively, is there a way to dynamically wrap an arbitrary function in an object so that it can be applied using f.call.apply(arguments)?
Alternatively, can Dart curry?
The documentation page you refer to says,
This functionality is not yet implemented, but is specified as part of version 0.07 of the Dart Programming Language Specification. Hopefully it will find its way into our implementations in due course, though it may be quite a while.
That may or may not be the issue...