I've noticed in Kotlin that there are already defined unaryPlus and unaryMinus operators on all of the number types.
What's the purpose of these operators? Are they in some way connected to the prefix forms of inc and dec?
Others have defined the basic meaning of unaryMinus and unaryPlus, and in reality on numeric types they may not actually even be called as functions. For example, coding +x or x.unaryPlus() generates the same bytecode (where x is type Int):
ILOAD 1
ISTORE 2
And the code -x or x.unaryMinus() generates the identical bytecode:
ILOAD 1
INEG
ISTORE 2
But there is more going on that this...
So why does the compiler even generate anything for +x? Some people will say that +x and x.unaryPlus() doesn't do anything, and that -x and x.unaryMinus() only reverses the sign. That isn't correct. In Java it is more complicated because it can involve widening and unboxing, see Unary Numeric Promotion which explains the full consequences of these operators. This has consequences for boxed values and types smaller than Int. For value of type Short and Byte these operators will return a new unboxed value widened of type Int. And since both operators have this more hidden functionality then both must generate bytecode even if you don't think +x does anything. By the way, this is similar to what C language does and it is called Usual Arithmetic Conversions.
Therefore this code is invalid:
val x: Short = 1
val y1: Short = +x // incompatible types
val y2: Short = x.unaryPlus() // incompatible types
val z1: Short = -x // incompatible types
val z2: Short = x.unaryMinus() // incompatible types
In these numeric cases on the base numeric types they are just compiler magic to allow for the idea of these operators to be equated to operator functions that you might want to overload in other classes.
For other uses such as Operator Overloading...
But they are there for more than just mathematical use and can be used on any class as an operator. Kotlin exposes operators as functions so that you can apply operator overloading on a specific set of operators which include unaryMinus and unaryPlus.
I could use these to define operators for my own or existing classes. For example I have a Set<Things> where Things is an enum class along with an unaryMinus() operator to negate the contents of the finite set of options:
enum class Things {
ONE, TWO, THREE, FOUR, FIVE
}
operator fun Set<Things>.unaryMinus() = Things.values().toSet().minus(this)
And then I can negate my enum set whenever I want:
val current = setOf(Things.THREE, Things.FIVE)
println(-current) // [ONE, TWO, FOUR]
println(-(-current)) // [THREE, FIVE]
Notice that I had to declare my extension function with the modifier operator or this will not work. The compiler will remind you if you forget this when you try to use the operator:
Error:(y, x) Kotlin: 'operator' modifier is required on 'unaryMinus' in 'com.my.favorite.package.SomeClass'
These operators are the signs of the integers. Here are some examples:
+5 calls 5.unaryPlus() and returns 5.
-5 calls 5.unaryMinus() and returns -5.
-(-5) calls 5.unaryMinus().unaryMinus() and returns 5.
The purpose of those operators is to be able to write:
val a = System.nanoTime()
val b = -a // a.unaryMinus()
val c = +b // b.unaryPlus()
They are not directly related to ++/inc and --/dec operators however they can be used in conjunction.
Notice that the following expressions are different:
--a // a = a.dec()
-(-a) // a.unaryMinus().unaryMinus()
fun main(){
var a = 34
var b = 56
println("Orignal value:"+ a)
println("Orignal value:"+ b
//The value will not change using .unaryPlus() will generate bytecode
println("After unary plus:" + a.unaryPlus())
//The value will invert the sign using .unaryMinus() will generate bytecode
println("After unary minus:" + b.unaryMinus())
}
Solution:
Orignal value:34
Orignal value:56
After unary plus:35
After unary minus:-55
Related
I would like to make plus mean something else, than addition. For example, creation of lazy expressions for computational graph. Unfortunately, class extensions cant override member functions. The following code will print 3:
operator fun Int.plus(other: Int) = listOf(this, other)
fun main() {
println( 1 + 2 )
}
Is is possible to force overriding?
No it is not possible. 1 + 2 is lowered into 1.plus(2), and there is a well defined order in how the compiler finds an appropriate plus method. Specification:
If a call is correct, for a callable f with an explicit receiver e
of type T the following sets are analyzed (in the given order):
Non-extension member callables named f of type T;
Extension callables named f, whose receiver type U conforms to type T, in the current scope and its upwards-linked scopes, ordered
by the size of the scope (smallest first), excluding the package
scope;
[...]
[...]
When analyzing these sets, the first set which contains any
applicable callable is picked for c-level partition, which gives us
the resulting overload candidate set.
So the plus method that is declared in Int is always found first, and the search stops there. Any extension you define will be ignored.
Hypothetically, if the built-in Int.plus is an implicitly imported extension function, then your code would have worked! Implicitly imported extensions are #6 on that list :)
My workaround for this situation is to use the "declare functions with almost any name by adding backticks" feature:
infix fun Int.`+`(other: Int) = listOf(this, other)
fun main() {
println( 1 `+` 2 )
}
This wouldn't work for some names that have reserved characters like square brackets, angle brackets, slashes, and dot (not an exhaustive list).
So for example:
var a = true
val test = if (a) -1 else -3.2
I was expecting the Type of the test should be the most closest intersection of the type-hierarchy i.e. for Int and Double is Number.
But looking at the IDE, it seems to have a type of {Comparable<{ Double & Int }> & Number}.
And the weird thing is, I cannot specify it like that (since {} is reserved for creating lambdas), I can only set it to a type of Number.
And another wierd thing is that if I try some function from Comparable interface, it throws some error:
// Warning at value 2
// The integer literal does not conform to the expected type {Double & Int}
test.compareTo(2)
3.compareTo(-1.1) // possible
2.3.compareTo(100) // possible
// But why not this is possible, while it has inferred type of Comparable?
test.compareTo(2)
Could somebody help in understanding the concept here? And few questions:
How does that type work all together, i.e. how could one variable hold two types at once?
How could one specify that type explicitly?
How do you use functions from Comparable interface, when test has implementaion of it?
& here means an intersection type (which isn't supported in the Kotlin language itself, but the compiler uses them internally). You can see it mentioned in the (incomplete) specification.
Intersection types are special non-denotable types used to express the fact that a value belongs to all of several types at the same time.
"Non-denotable" means exactly that you can't specify that type. I am not sure but I think the extra { } in types are supposed to indicate exactly this.
In particular, Comparable<Double & Int> means you can only compare test to something which is both Double and Int, but there are no such values. The compiler could probably simplify it to Comparable<Nothing>.
the most closest intersection of the type-hierarchy i.e. for Int and Double is Number.
It's least upper bound, which is closer to union, not intersection. The specification actually calls it "union types", but that's not the normal usage of that term.
This least upper bound is not Number because it also takes least upper bound of the Comparable interfaces which works out to Comparable<Double & Int> because Comparable is contravariant:
lub(Int, Double) =
Number & lub(Comparable<Int>, Comparable<Double>) =
Number & Comparable<Int & Double>
This calculation is described under type decaying:
All union types are subject to type decaying, when they are converted to a specific intersection type, representable within Kotlin type system.
The answer to question 1 is that the compiler is doing its best to infer the type, inventing new constraints to describe it as it goes.
The answer to question 2 is that you cannot.
The answer to question 3 is that you cannot, because Int is not comparable to Double and vice versa. So none of the methods from Comparable are actually usable, but the value definitely implements Comparable against something. This is not useful for Comparable, but could be for another interface. For example, imagine:
interface ZeroAndComparable<T> {
fun compareTo(t: T): Int
fun zero(): T
}
val foo : ZeroAndComparable<Int> = someZeroAndComparableInt()
val bar : ZeroAndComparable<Double> = someZeroAndComparableDouble()
val foobar = if (a) foo else bar
val zero : Any = foobar.zero() // should work
foobar.compareTo(something) // cannot work
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)