Recently I was working with lists in kotlin and had the following snippet:
a = listOf(1, 2, 3, 4)
println(a[-2])
Of course this causes an IndexOutOfBoundsException so I thought it would be nice to extend this functionality. So I thought one could override the get operator in the List class:
operator fun <T> List<T>.get(index: Int): T =
// Here this should call the non-overridden version of
// get.
get(index % size)
I understand that extensions are just static methods and therefore cannot be overridden, but is there a way one can achieve something like this?
Of course you could just create another function
fun <T> List<T>.safeGet(index: Int): T = get(index % size)
but I'd like to know if there are other ways.
(I understand that index % size is a very naive way of doing what I want, but it's not the focus of my question and makes the code smaller.)
EDIT
When I wrote this question I thought the % operator would return always positive numbers when the right hand side is positive - like in python. I'm keeping the original question here just for consistency.
Since get operator is already defined in List, you cannot redefine get (with one Int parameter).
However, you can override invoke operator, which is not defined in List.
fun main(args: Array<String>) {
val a = listOf(1, 2, 3, 4)
println(a(-2))
}
// If `index` is negative, `index % size` will be non-positive by the definition of `rem` operator.
operator fun <T> List<T>.invoke(index: Int): T = if (index >= 0) get(index % size) else get((-index) % (-size))
although I think that creating a new extension method to List with an appropriate name will be more preferable option.
As a sidenote, (positive value) % (negative value) is non-negative, and (negative value) % (positive value) is non-positive.
% in Kotlin corresponds to rem in Haskell in the following example: https://stackoverflow.com/a/28027235/869330
You're trying something impossible, because extensions are always shadowed by members, even #JvmName cannot save you.
Workaround: use your second solution, or add a Unit parameter which is ugly (looks like a[x, Unit]) but can exist with its own get method together.
Another solution: create your own List implementation (recommended).
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.
I'm trying to recreate in Kotlin something I believe is possible in Pandas/Python. I would like to perform division such that a number (Int, Double, etc) is divided by a numeric vector. (I'm told this is possible, but haven't found a reference.) One example i've seen was part of a growth rate calculation
1.0 / data1['nYears']
Here 1.0 is divided by each value in data1['nYears'], and a column was returned containing the element-wise result. E.G., if the column contained 2 and 4, the result would be a new column containing .5 and .25.
Can this be done in Kotlin?
(FWIW, the reverse calculations (dividing a column by a scalar constant) are perhaps more important, but i thought i would start here.)
i found a partial solution in this using operator overloading with an extension function :
operator fun Int.div(vector: Vector<Int>) : Vector<Double> {
val result = Vector("", ArrayList<Double?>())
for (e in vector) {
if (e == null) {
result.add(null)
} else {
result.add(this / (e * 1.0))
}
}
return result
}
This works fine for Ints, but when I attempted to extend it to other numeric types I ran into trouble. For example, adding a similar method for doubles I got an error, i believe is caused by type erasure.
Platform declaration clash: The following declarations have the same JVM signature...
Next I tried providing a single method with an argument of (Vector ) to cover both cases, but got
None of the following functions can be called with the arguments supplied
Is there a way to do this in Kotlin?
The problem is that the names of the functions/operators are the same and would generate the same static Java function name. You can easily assign a new Java-name with the #JvmName annotation (see https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#handling-signature-clashes-with-jvmname).
Here an example from the standard libs:
#JvmName("sumOfInt")
fun Iterable<Int>.sum(): Int { ... }
#JvmName("sumOfFloat")
fun Iterable<Float>.sum(): Float { ... }
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.
In the 14th Kotlin Koan on operator overloading, I was suprised when after solving I viewed the answer and saw that the operator modifier was not required on the compareTo method:
data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) : Comparable<MyDate> {
override fun compareTo(other: MyDate) = when {
year != other.year -> year - other.year
month != other.month -> month - other.month
else -> dayOfMonth - other.dayOfMonth
}
}
The operator overloading docs linked to from the exercise explicitly says:
Functions that overload operators need to be marked with the operator
modifier.
So what's going on here? Why does this code compile? When exactly is operator required?
Why does this code compile?
This compiles because the overridden interface method, Comparable<T>.compareTo, is itself an operator fun.
/**
* Compares this object with the specified object for order. Returns zero if this object is equal
* to the specified [other] object, a negative number if it's less than [other], or a positive number
* if it's greater than [other].
*/
public operator fun compareTo(other: T): Int
As the function overrides this, it is also an operator function.
When exactly is operator required?
operator in general is required whenever you wish to be able to use a function as if it were an operator, since operator usages are simply compiled to function calls (except on primitive types, etc.)
That is, foo += bar, for example, is equivalent to foo.plusAssign(bar), foo[bar] = baz is equivalent to foo.set(bar, baz), etc.
Personally I prefer specifying operator wherever possible even if it is not required, for readability reasons.
If MyDate were not a Comparable, and you omitted the operator modifier, comparing two dates via <, >, <=, or >= would not compile.
I couldn't find anything in the specification on this, though. However in a polymorphic sense it makes sense - why should you be able to write a < b where the type of a and b are Comparables, but not when they are a MyDate? Since you wouldn't be able to remove the "operator-ness" of this function, it makes sense that operator should be inheritable from the superclass method.
Kotlin has many features that are enabled via particular conventions. Those can be identified by the use of an operator keyword. Examples are ranges, operator overloads, index operators, destructuring declarations and more.
If we want to compare two objects in Java, for sorting e.g., we implement the Comparable interface with its compareTo method. This is also done in Kotlin, but with much better support and a shorthand syntax. If you implement this method in a class, you can use all the nice operators like <, <=, >, >= with that class out of the box. These operators are translated to appropriate calls of compareTo by the compiler:
obj1 > obj2 ⇒ obj1.compareTo(obj2) > 0
The interface method compareTo in Comparable already defines the operator keyword, which makes it redundant to add the keyword in your own implementation.
In your example, the operator keyword is not mandatory since the overridden method already defines it.
In Java, operators are tied to specific Java types. For example, String and numeric types in Java can use the + operator for concatenation and addition, respectively. No other Java type can reuse this operator for its own benefit. Kotlin, on the contrary, provides a set of conventions to support limited Operator Overloading.
Let’s start with a simple data class:
data class Point(val x: Int, val y: Int)
We’re going to enhance this data class with a few operators.
In order to turn a Kotlin function with a pre-defined name into an operator, we should mark the function with the operator modifier. For example, we can overload the “+” operator:
operator fun Point.plus(other: Point) = Point(x + other.x, y + other.y)
This way we can add two Points with “+”:
val p1 = Point(0, 1)
val p2 = Point(1, 2)
println(p1 + p2)
Point(x=1, y=3)
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.