New operators

Are there any possibilities of adding new operators to Kotlin? Like ^, &, | and : (map to) operators used in other languages.
I believe that Kotlin can grow fast and have any programmes requested features in time.

2 Likes

There are multiple discussions going on:

For the binary operators:

https://youtrack.jetbrains.com/issueMobile/KT-1440

For function literals:

(function literals do exist at the moment for annotations)

Ps. For the mapping note:

I wonder whether the Kotlin team are changing their minds on the bitwise operator issue because, when you read what @abreslav said in KT-1440 (albeit 5 years ago), this seems to be at odds with the puzzlement he expressed here at the hostility to making | and & into overloadable operators.

For my part, after donkey’s years of using the traditional bitwise operators, I soon started to like Kotlin’s infix operator approach as I found that it forced me to write more readable code. It may be that many others who responded to the survey have found the same.

However, I would admit that the lack of assignment forms for the infix functions and their different priority could be a problem for heavy users of these operators who might have been too busy with their bit shifting to be bothered to respond to the survey :slight_smile:

1 Like

Overloadable | and & operators are on the table for a future version of Kotlin (not 1.2).

2 Likes

How do you square the possible introduction of these overloadable operators with the existing and and or infix functions?

Is the idea that, as well as other uses, folks will be able to overload | and & to provide the same functionality as the infix functions but with the expected operator precedence and assignment forms as a bonus?

If so, they’re going to expect to be able to overload ^, <<, >> and ~ as well.

I imagine that, whatever you decide to do here, and, or and their brethren will remain as options because removing them now would be a huge breaking change.

The existing infix functions will definitely remain, possibly as deprecations.

People may expect to be able to overload all sorts oft things, but as far as I know supporting other overloaded operators is not on the table.

I have a suggestion for two new operators which, it seems to me, are lacking from a consistency perspective. The introduction of these would solve several old problems.

Kotlin got it right as far as making a clear distinction between == (structural equality) and === (referential equality). But there is one other important equality, namely comparative equality. By that I mean what the comparison operators refer to (<, <=, >=, >). There is one operator clearly missing in this series, namely “=”.

One could also put this as that there are operators expressing compareTo()<0, compareTo()>0 but not compareTo()=0.

Now, as “=” is regrettably already taken, something else would have to do, For the negation, I thing “<>” is an obvious choice, but for the positive version, perhaps “=?”, or possibly “><”.

These should be implemented in exactly the same way as the other comparison operators, i e by referring to compareTo().

This would solve:

a) testing equality between different types:

val a = 1
val b = 1L

a < b gives false
a > b gives false
a <= b gives true
a >= b gives true
a == b is not testable

With the new operators,
a =? b gives true, while
a <> b gives false.

b) custom numeric types
It is not possible to extend equals() on existing classes such as Int. But one can easily add compareTo(custom type):

class MyNumber(val v:Int) {
	operator fun compareTo(other: Int): Int {
		return v.compareTo(other)
	}	
	operator fun compareTo(other: myNumber): Int {
		return v.compareTo(other.v)
	}
}
operator fun Int.compareTo(other: Mynumber) = compareTo(other.v)

With the new operators, you can write:

val a = MyNumber(5)

if (a =? 5) …

See also Overloading == with different types of operands

c) the BigDecimal problem:

Comparing BigDecimals for numeric equality requires using compareTo(), not equals(), since equals also tests scale. With the new operators, you can use them consistently in all contexts where numeric equality is relevant.

see BigDecimal (Java Platform SE 8 )
also: BigDecimal comparison?

I believe this is a very much better way of solving these problems than the Groovy way (using compareTo for == instead of equals for objects implementing Comparable) or the Scala way (allowing user defined new operators). Letting == correspond to equals and separate operators to compareTo seems to me in line with Kotlin’s ambitions to be clear and simple.

1 Like

I think that having three different equals operators in the language runs very much against Kotlin’s ambitions to be clear and simple.

1 Like

Well, I think there is a saying that you should make everything as simple as possible, but not simpler. The problems remain, and having everyone implement their own work-arounds certainly does not make things more simple nor clear. If you want to write some business logic, for instance, you need BigDecimal or some equivalent, and it is not pretty to have to write:

value1.compareTo(value2)==0
instead of
value1 = value2

1 Like

Looks like this problem can be solved much more easily by providing a different implementation of BigDecimal than by adding a new operator (not existing in any other language) to Kotlin.

That would solve (BigValue1 == BigValue2) but not (BigValue == 5). The best I can do is define functions so I can write (BigValue == 5.B) or (BigValue eq 5), but the latter gets wrong precedence. The heart of the matter is that compareTo can handle different types, but equals can not (and should not). Actually, I think BigDecimal does the right thing in not equalling objects with different scales. It’s not just BigDecimal, it’s that something other than equals is needed for comparing different numeric types numerically. And compareTo works well in this regard, it’s just that the comparison test operators series is incomplete and so can’t be used for clear and consistent-looking code.

Unless I’m missing something fundamemental, it seems to me that the simplest solution to all of these issues with ‘ordered’ classes would be for the compiler to link the implementation of the '==' and '!=' operators for a class C :-

  1. To the compareTo() method (i.e. a return value of zero or non-zero) if it implements Comparable<C>; or

  2. To the equals() method as it does at present for all other cases.

The equality operators would then meld in with the comparison operators for ordered classes which seems to be what we all want.

@alanfo, yes, I think that is what Groovy does. That would be fine by me, though it breaks the simple connection between == and equals. But if we don’t want separate operators, it’s probably the best we can do. == will have to serve both purposes, and to distinguish manually we will have to use equals/compareTo. There is some discussions on this on the Groovy forums. But I don’t really suppose it’s feasible to change the operation of the == operator at this stage.

I agree that the chances of this being changed now are remote.

If this is the way that Groovy implements equality, then the likelihood is that it’s been considered already and rejected for some reason.

Another solution for Int vs Long comparison is implicit conversions, which, unlike new overloadable hieroglyphs :), is on the table (in the scope related to Kotlin Native, unsigned types, and making life better for those who twiddle bits using Kotlin).

@yole Note that an alternative implementation of BigDecimal will be faulty due to asymmetric equals.

I didn’t know that implicit conversions were being considered though I’ve always felt that implicit ‘widening’ conversions for the integral types (Int to Long, Short to Int etc.) are fairly harmless.

Can you say whether (the more dangerous) implicit conversions between integral and floating-point types are also on the table and whether this would apply to all versions of Kotlin, not just Native?

This will apply to all versions of Kotlin, not just Native.
Design is on a very early stage. Can’t provide any details yet. I personally would expect that “dangerous” conversions have to be explicit.

But wait, it just hit me that assignment is not an expression in Kotlin, right? So there would be no conflict in using = also for comparison. When you write
(if x = 5)
instead of the compiler emitting “only expressions are allowed in this context”, it could translate = to compareTo()==0, or, to minimize risk of breaking existing code, to some new method comparesAsEqual() (if it exists on both objects, those who want to use it could implement it as extensions).

This way, we don’t need a new (ugly) operator, but could use the quite natural =, which would be the obvious choice had it not been appropriated for assignment. (We could still add <> for testing negative).

Well, I certainly prefer that to your original proposal, though I’m more enthused now about what @Dmitry_Petrov_1 has said regarding the possibility that implicit widening conversions might be introduced which would solve the problems we have at present when testing equality between different integral types

I’m less concerned about equality comparisons between custom numeric types and integral types where I consider that it might not necessarily be a bad thing for these to remain explicit.

I like what @nbengtg is proposing (=