Analogue of infix function from Kotlin in Java - kotlin

Trying to understand deeply in infix functions. Could you please give an example of solution from Java which could be solved by infix from Kotlin.
PS Please let me know if my question is incorrect if you want to devote it. It helps me asking better questions

Kotlin supports operator overloading and infix functions, Java doesn't support either.
These language features are just syntactic sugar. Everything you do with operators or infix functions can be done without, but they may help greatly with the readability of your code.
An infix function is like a named operator and can be called without dot and parentheses. The example from the documentation looks like this:
infix fun Int.shl(x: Int): Int { ... }
// calling the function using the infix notation
1 shl 2
// is the same as
1.shl(2)
Other example is for adjusting times. I like to define infix functions like
infix fun TemporalAmount.before(instant: Instant): Instant =
instant.minus(this)
Which allows me to write
val yesterday = Period.ofDays(1) before Instant.now()
instead of
val yesterday = Instant.now().minus(Period.ofDays(1))

There is no analogous concept in Java. As explained in the official documentation It just allows you to call the function without the . and () making it cleaner and less verbose. For example:
infix fun Int.shl(x: Int): Int { ... }
// calling the function using the infix notation
1 shl 2
// is the same as
1.shl(2)
As you can see this doesn't solve anything that can't be solved by a normal function call. It is just syntax sugar.

Related

Kotlin - reflection and type safety

I am writing a small library for programatically generating SQL queries.
The goal is that the API of this library can be used like that:
myQuery.where(
MyClass::id equal "foo",
MyClass::age notEqual 55
).findAll()
The signatures of both the where function, and the infix operators is under my control. Here are the relevant definitions that I have at the moment:
interface KpaFilter<BASE, FIELD>
infix fun <BASE: Any, FIELD: Any> KProperty1<BASE, FIELD>.equal(value: FIELD): KpaFilter<BASE, FIELD> { ... }
fun <BASE: Any> where(vararg filters: KpaFilter<BASE, *>?): KpaQuery<BASE>
Still, I cannot find a proper way to make this type safe. For example, I would like this to raise a compilation error, but unfortunately, it compiles:
val someFilter = MyClass::id equal 55 // id is a string
Is it possible to somehow modify the signatures of the declarations above and achieve this kind of type safety, without making the API more cumbersome than its current form?
If you don't mind using Kotlin internal APIs, there is a hidden feature in the compiler which does exactly this. The feature is enabled by annotating a parameter with #kotlin.internal.Exact:
#Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
infix fun <BASE: Any, FIELD: Any> KProperty1<BASE, #kotlin.internal.Exact FIELD>.equal(value: FIELD): KpaFilter<BASE, FIELD> { ... }
This works pretty well and can be used in regular Kotlin projects. Of course, we don't have guarantees it will be supported in the future.

Same type for receiver and argument in Kotlin function

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.

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)

How to override any operator if the first operand isn't your object

I gave Kotlin a try, because it's supposed to be a java without certain limitations like checked exceptions or no support for operator overriding (of course these limitations got their right to exists, like reduction of abusing or forced verbosity, but this question isn't why they should (not) exist). So I wrote a simple Vector2 class, which should support basic operators like +-*/.
There isn't a problem when your first and second operand both are from the type Vector2, but there is a problem when the first operand isn't from type Vector2. Take this example:
fun main(args: Array<String>) {
val vector = Vector2(2.0, 3.0) * 2.0
}
This works flawless because of this method in Vector2:
operator fun times(d: Double) = Vector2(x * d, y * d)
But what am I supposed to do if the two operands change place like this:
fun main(args: Array<String>) {
val vector = 2.0 * Vector2(2.0, 3.0)
}
I though of an operator overload of times() for the type Double:
// In 'Vector2.kt'
operator fun Double.times(vector: Vector2) = ...
but I don't know how to retrieve the double value to multiply it with the vector.
Could anybody help? Thanks in advance!
When you define an extension function, the receiver (the object the function is called on) is always available as this, in the body of your implementation.
operator fun Double.times(vector: Vector2): Vector2 = vector * this
You could implement that any way you'd like, I just reversed the operands to shorten the example.

Kotlin-js: Define number of decimals

Let's imagine something like this:
var num: Float = 0.0f
num = 2.4 * 3.5 / 3.8
num has several decimals, but I want only 2.
In JS I would use num.toFixed(2).
Other answers here suggest to use "%.2f".format(num) or num.format(2). The latter needs a custom extension fun:
fun Double.format(digits: Int) = java.lang.String.format("%.${digits}f", this)
However, any of these options leads to a compiler error of "unresolved reference". I don't think is a question of imports cause the compiler would suggest it.
Is there an easy way to do this?
Kotlin standard library for JS doesn't have anything like Double.format yet, but you can implement it easily with aforementioned toFixed function available in javascript:
fun Double.format(digits: Int): String = this.asDynamic().toFixed(digits)
fun Float.format(digits: Int): String = this.asDynamic().toFixed(digits)
This works because Double and Float in Kotlin are represented with Number data type in JS, so you can call toFixed() function on instances of those types.