Kotlin: Why can't I use one of my functions? - kotlin

I am trying to use one of my defined functions that accepts a string yet the software won't compile.
fun passes(address: String) = Collections.frequency(addresses, address) <= CONNECTIONS_PER_IP
fun passes(remoteAddress: InetSocketAddress) = passes(remoteAddress.hostName)
I can't even call the string function using a custom string, for example passes("127.0.0.1").
None of the following functions can eb called with the arguments supplied.
passes(String) defined in abendigo.Firewall
passes(InetSocketAddress) defined in abendigo.Firewall

I presume you're using java.lang.String instead of kotlin.String in the Kotlin source code. Please use only kotlin.String instead, this is the type that string literals in Kotlin have (but in the bytecode it's still transformed to java.lang.String).

The issue was an import of java.lang.String. For some reason IntelliJ imported it.

Related

How to shadow member function with a custom Kotlin extension function? (like Kotlin stdlib does)

I am reading Kotlin in Action 2nd edition.
Chapter 3 says:
If the class has a member function with the same signature as an extension function, the member function always takes precedence
At the same the book demonstrates the CharSequence.split Kotlin's stdlib extension function (which API is less confusing than an API of Java's String#split).
The thing I do not understand is how this split extension functions takes precedence on the following call:
"12.345-6.A".split(".") // <-- Kotlin's extension function gets invoked here even though there is a member function on String class in Java with matching signature
The book also leaves the following comment on this case:
Kotlin hides the confusing method and provides as replacements several overloaded extensions named split that have different arguments
How does Kotlin hide a member function? Can I also shadow some member function which I do not like with my custom extension function? Or it is a trick which is only available to Kotlin language developers?
Actually Kotlin has a separate implementation of CharSequence and String.
These kotlin String/Charsequence does not have its split function. Kotlin team has made all those string implementation functions separately with help of extension functions.Your string will be referring to kotlin String instead of Java String.
If you need to create java String, you need to refer String with package like below.
var str : java.lang.String = java.lang.String("a b c")
str.split("")
Here it will always call Java split function.
Even if you create split function for java.lang.String , it will call only member function as you have read.
member function always takes precedence

Interoperability java-kotlin Nullable string crashing at runtime but why?

I have an alternative to my problem, but I still have 2 questions:
Why it's crashing
Why Intellij/compiler is not complaining
I provided a small example of my issue. Here is an overview (you can find the code just after)
Car.java is the java class with a simple getter annoted as nulllable
MyView.kt is the crashing at runtime example with no warning in Intellij or in gradle. (Crashing when the value is null)
MyView2.kt is not crashing at runtime (even if mType is null)
Library.kt (kotlin stdlib) is simply the expected call for the example (even if it's weird to see string.toString())
Car.java
#Nullable
private String mType;
#Nullable
public String getCarType() {
return mType;
}
MyView.kt (crashing)
val test: String = myCar.carType.toString()
MyView2.kt (not crashing)
val carType: String? = myCar.carType
val test2: String = carType.toString()
Library.kt (kotlin stdlib)
/**
* Returns a string representation of the object. Can be called with a null receiver, in which case
* it returns the string "null".
*/
public fun Any?.toString(): String
Thanks! I guess this is a corner case of the interop between kotlin and java? Or... someone is aware of a better explanation?
The clue to this difference is the optional marker ? in this line in MyView2.kt
val carType: String? = myCar.carType
- here you are declaring to the Kotlin compiler that you know that carType is nullable. (In turn the behaviour of .toString() will work even though it is called on a null object, as you showed from the docs.)
However things are different in MyView.kt because the code doesn't get as far as the .toString() call. Here you are directly using a platform type (i.e. Java) where null-safety rules cannot be deduced.
This documentation about Calling Java code from Kotlin explains:
Types of Java declarations are treated in Kotlin in a specific manner and called platform types. Null-checks are relaxed for such types, so that safety guarantees for them are the same as in Java

Does the jar library built from Kotlin code still have all the feature like accessing local Kotlin code

I am looking at this https://docs.gradle.org/current/samples/sample_building_kotlin_libraries.html
to build a Kotlin jar library. But I am wondering -- if consumer code of the library is also using Kotlin, can it have all the benefits like accessing to local Kotlin code? For example:
Nullability check
Suspend keyword restriction
Named parameters
...
I figured out the answer is YES as long as the jar is built with source files.
suspend
The suspend keyword changes the descriptor of the functions to have an interface, Continuation<ReturnType> at the end of the parameter list. So if you have
suspend fun foo(i: Int, l: Long): String in kotlin, it gets compiled and decompiled to Java:
public final Object foo(int i, long l, Continuation<? super String> $completion). This is why some libraries had Java friendly functions that wraps suspend function call in runBlocking.
Null Checks
This works across languages, when kotlin compiles a function or expression call that specifies a non-null value, it adds null checks to the code. For example:
fun bar(s1: String, s2: String) adds these check in the method body:
Intrinsics.checkParameterIsNotNull((Object)s1, "s1");
Intrinsics.checkParameterIsNotNull((Object)s2, "s2");
And throws an exception when it is null.

Why can't functions be directly used as lambdas in Kotlin?

In Kotlin we can't write:
arrayOf(1,2,3).forEach(println)
But we have to instead call forEach using ::println. This is because forEach expects a lambda, but println is a function. Why are these different types and is there any good reason why Kotlin doesn't automatically cast it for me like it does in Python?
Update:
There does seem to be a difference. Look at:
val addA: (Int)->Int = {it+1}
fun addB(i: Int) = i+1
fun main(args: Array<String>){
var x: Int=0
x.let(addA).let(::addB).let(::print)
}
The lambda doesn't need the ::, but the function does
I don't think that a lambda and a function are different types. The only type which exists is a function type and a lambda is one way of instantiating a function. Here in the documentation are all the ways to get an instance to a function type https://kotlinlang.org/docs/reference/lambdas.html#instantiating-a-function-type.
::println is a way if getting a reference to an existing declaration. So your question is why it is necessary to use ::. Maybe it is just to have a consistent way of getting a function reference in other cases as when you want a reference that point to a member of a particular instance as foo::toString.

Kotlin: Spread operator on calling JavaScript method

I try to write a type-safe wrapper for a JavaScript library.
I need to call a method from JavaScript with variable arguments
(e.g. method(args...)).
The Kotlin fun for this should work with variable arguments, too.
Because Kotlin supports a spread operator, I tried to use it, but Kotlin do not want this.
Example code:
val jsLibrary: dynamic = require("library") // library given by node's require here
fun method(vararg args: String) = jsLibrary.method(*args)
Edit: Forgot to write spread operator '*' in code already. Compiler returns error because of the spread operator.
The Kotlin compiler returns the error "Can't apply spread operator in dynamic call".
Any ideas how to implement a wrapper like this, or do I need any workaround?
Thanks for your help!
Use external fun with #JsModule annotation
#JsModule("library")
external fun method(vararg args: String): LibraryMethodReturnType
This will do require("library") for you under the hood. You'll have proper Kotlin types instead of dynamic right away. You'll have no "wrappers", meaning no extra JavaScript call at runtime.
There is a hacky solution if for you want to manually use require and dynamic types: use apply method to pass all the arguments as an array.
val jsLibrary: dynamic = require("library")
fun method(vararg args: String) = jsLibrary.method.apply(null, args)