Java modifies kotlin class content to null - nullpointerexception

Kotlin has a brilliant null checks at compile time using separation to "nullable?" and "notnullable" objects. It has a KAnnotator to help determine that objects coming from Java are nullabale or not. But what if some part of not-nullable class is changed?
Consider we have a cat, which certainly has a head that can meeew. When we ask the cat to mew, it mews with its head:
package org.cat
class CatHead(){
fun mew(){
println("Mew")
}
}
class Cat(){
var head = CatHead()
fun mew(){
head.mew()
}
}
fun main(args:Array<String>){
val cat = Cat()
cat.mew()
}
Now lets add to this pretty picture a JAVA cat maniac (CatManiac.java), who cuts off a cats' heads as he gets:
import org.cat.*;
public class CatManiac {
public static void cutCatHead(Cat cat){
cat.setHead(null);
}
}
So if we pass a cat to a maniac, he definitely cuts its head. And how cat says mew without a head?
fun main(args:Array<String>){
val cat = Cat()
CatManiac.cutCatHead(cat)
cat.mew()
}
We get a runtime error inside kotlin because of null, at point of calling cat.mew():
Exception in thread "main" java.lang.IllegalArgumentException".
I believe it is a pretty common problem we can get while using Java libraries in Kotlin. Is there any way or any plans to warn/fight with that?
P.S. Something like KAnnotator looking for such things in your code?

There are checkers for Java code that will be extended for Kotlin code eventually.
For example, the one in IntelliJ will warn you about the problem right now. It's a part of the open-source Community Edition, so you can try it for yourself.
Meanwhile note that Kotlin gives you a great advantage over Java: it fail right at the point where the error is introduced. It's hard to pass a null through many Kotlin calls and only then get a failure. In Kotlin you mostly get a run-time error right where the illegal null is first introduced.

Related

Kotlin script: main function does not get called locally, unlike in online judge

I am trying to participate in online Codeforces contests using Kotlin.
My understanding is I should use Kotlin script if my code is contained within a single file.
If I run the following file locally (version 1.6.10):
kotlin just_main.main.kts
// just_main.main.kts
fun main() {
println("Hello World")
}
Nothing happens. I need to add an explicit call for it to actually execute main:
// top_level_call.main.kts
fun main() {
println("Hello World")
}
main()
So far, so normal. The problem occurs when I try to submit my solution to the Codeforces online judge. The judge expects no top-level code and runs the main function instead. So just_main runs fine, but top_level_call produces a compilation error:
Can't compile file:
program.kt:43:1: error: expecting a top level declaration
main()
^
This leads to the awkward situation of me having to add the main() call when I want to try my solution locally, but having to remove it every time I upload an attempt.
Is there a way to have my local Kotlin behave the same as the online judge, meaning implicitly running any main functions (meaning just_main would produce output)?
I haven't found a way to do this with Kotlin script files, but you can also use normal .kt files without having any classes in the file (my understanding is that Kotlin magically turns them into Java class bytecode/files):
kotlinc a.kt && kotlin AKt < a.in
This "runs" a.kt with standard input from a.in.
(And yes I only found this after I already wrote the question)

Unexpected tokens I'm following a tutorial and we do really the same code but the video was published on 2018

Log.d(tag:"MainActivity", msg:"Email is: " + email)
Log.d(tag:"MainActivity", msg:"Password: $password")
Log.d("MainActivity", "Email is: $email");
Log.d("MainActivity", "Password: $password")
The problem is, that you copied the so-called "Parameter Hints" by IntelliJ.
The parts of your code that end with a double-colon (tag: and msg:) aren't really part of the Kotlin code. Instead, the IDE that the creator of the tutorial was using showed hints for the names of the parameters.
Example
The function
fun add(a: Int, b: Int): Int {
return a + b
}
has two parameters, the first called a and the second called b.
This means when calling this code from IntelliJ, the IDE will show the following hints to the user so that he knows what parameters he is entering:
You can identify these hints by looking at them accurately. They have a different font, are boxed, and have a different background-color. Please note that these hints are not part of the Kotlin code and cannot be written in Kotlin, that's where your Syntax Error comes from.
Have fun learning Kotlin! 👍

Annotation class does not validate input as enum in Kotlin

I'd like to create annotation instead of enum use it for when statement
#Retention(AnnotationRetention.SOURCE)
#IntDef(SELECT.toLong(), WEAR.toLong(), BAND.toLong())
annotation class CurrentState
companion object {
const val SELECT = 0
const val WEAR = 1
const val BAND = 2
}
private fun handleFragment(#CurrentState state:Int) {
val fragment:Fragment =
when(state){
SELECT -> SelectDeviceFragment.newInstance()
WEAR -> ConnectWatchFragment.newInstance()
BAND -> SelectDeviceFragment.newInstance()
}
From my understanding, this code should prevent me from performing following code:
handleFragment(5)
and when statement should not ask me to add else statement, as expected from enum
What I'm doing wrong or misunderstand?
From https://discuss.kotlinlang.org/t/intdef-and-stringdef-not-being-checked-at-compile-time/7029:
This checking doesn’t come from the compiler, but from Android lint. Work to make android lint language independent is being done, but if I’m not mistaken you’ll need a newer version of Android Studio for it.
And Android Studio 3.1 blog post mentions lint checks for Kotlin as a feature (though it doesn't say whether this check specifically is supported).
The #IntDef annotation is part of the Android framework. The compiler is not aware of any specific semantics of this annotation, and is not able to use it for checking the exhaustiveness of when statements.
Moreover, even with the annotation, you can call handleFragment(5). Such code will not be a compiler error, it will only be reported as a lint warning.

Is there a better way to write CompletableFutrue.XXXasync() invocations in kotlin?

Java CompletableFuture<T> has a lot of async methods, static or instance, in this format
public <U> CompletableFuture<U> XXXasync(SomeFunctionalInterface<T> something, Executor executor)
If you have enough experience with FP in kotlin, you will immediately realize these function are extremely awkward to use in kotlin, because the SAM interface is not the last parameter.
aCompletableFutrue.thenComposeAsync(Function<SomeType, CompletableFuture<SomeOtherType>> {
// ^ WHAT A LONG TYPE NAME THAT NEED TO BE HAND WRITTEN
// do something that has to be written in multiple lines.
// for that sake of simplicity I use convert() to represent this process
convert(it)
}, executor)
That Function has a very very long generic signature that I don't know how to let IDE generate. It will be a plain in the butt if the type name become even longer or contains a ParameterizedType or has type variance annotations.
It also looks nasty because of the trailing , executor) on line 5.
Is there some missing functionality in kotlin or IDE that can help with the situation? At least I don't want to write that long SAM constructor all by myself.
Rejected solutions:
Using named parameter doesn't seem to work because this feature only works on a kotlin function.
Abandon async methods sounds bad from the very beginning.
Kotlin corountine is rejected because we are working with some silly Java libraries that accept CompletionStage only.
IF you calling the api from java that takes a functional interface parameter at last, you can just using lambda in kotlin.
val composed: CompletableFuture<String> = aCompletableFutrue.thenComposeAsync {
CompletableFuture.supplyAsync { it.toString() }
};
Secondly, if you don't like the java api method signature. you can write your own extension methods, for example:
fun <T, U> CompletableFuture<T>.thenComposeAsync(executor: Executor
, mapping: Function1<in T, out CompletionStage<U>>): CompletableFuture<U> {
return thenComposeAsync(Function<T,CompletionStage<U>>{mapping(it)}, executor)
}
THEN you can makes the lambda along the method.
aCompletableFutrue.thenComposeAsync(executor){
// do working
}

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.