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)
Related
Is there any difference between these two Kotlin extension functions?
fun Any?.f(o: Any?) = 100
fun <T> T.g(o: T) = 100
Is it possible to rewrite g in such a way that the type of its argument and receiver are forced to be the same?
That is, 10.g(5) and "x".g("y") are OK, but 10.g("y") does not compile.
Edit:
Given this, I guess the answer to my second question is no, uless one adds additional arguments.
I believe this is not possible officially at the time of writing this answer (Kotlin 1.7.20).
However, internally Kotlin compiler supports such case, it allows to change the default behavior and use exact type parameters. This is controlled by the internal #Exact annotation and it is used in many places across the Kotlin stdlib.
With some hacking we can enable this behavior in our own code:
#Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
fun <T> #kotlin.internal.Exact T.g(o: #kotlin.internal.Exact T) = 100
Of course, this is purely a hack and it may stop working in future versions of Kotlin.
Update
Answering your first question on whether there is a difference between using Any and T. Generic functions make the most sense if the type parameter is not only consumed, but also passed somewhere further. For example, if the function returns T or it receives an object that consumes T:
fun main() {
var result = 5.g(7)
}
fun <T> T.g(o: T): T = if (...) this else o
In this case result is of type Int. If we use Any instead of T, result would have to be Any as well.
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 is one of the languages that allow us to easily define behavior for various predefined operators, operation named operator overloading - https://kotlinlang.org/docs/reference/operator-overloading.html
My question is regarding the overloading part of the operation.
From what I see default the language only declares operators for the basic types - https://github.com/JetBrains/kotlin/blob/01a613dca4042dde8d2374ff0e6610cb9eddc415/core/builtins/native/kotlin/Primitives.kt
If I'm reading this correctly our custom types would not have any of this special methods - operators available by default. And indeed if we're to try
class A { }
val a = A()
System.out.println(a + a)
the compiler would try to find a suitable operator plus method to call but ultimately give a compilation error.
But if we do declare our own operator plus method
class A {
operator fun plus(other: A) = "Hello!"
}
val a = A()
System.out.println(a + a)
we would indeed have "Hello!" printed.
The above mechanism is called "operator overloading" but without a previous method with the same name we do not in fact use the OOP method overloading we all are accustomed to - https://en.wikipedia.org/wiki/Function_overloading.
So between the two mechanisms - operator overloading and method overloading there is really no connection, other than an unfortunate name clash?
Looks like you are confused about operators in general.
The thing about operators is that they are just inline functions and the operator keyword is just a language construct to give you the ability to group operators with classes.
Where you can find answers about this is definitely the source code. If we take a look at the tests, we can find the following:
// "Create local variable '-'" "false"
// ACTION: Create extension function 'A.minus'
// ACTION: Create member function 'A.minus'
// ACTION: Replace overloaded operator with function call
Sadly, I cannot find the source code where operator is transformed, but most certainly this must be the procedure where the operator overload is replaced with function call.
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
}
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.