There seem to be some strange choices for infix operators that are omitted in Kotlin.
For example, int has no pow. Byte’s and is in an experimental library, and it has no shifts.
There seem to be some strange choices for infix operators that are omitted in Kotlin.
For example, int has no pow. Byte’s and is in an experimental library, and it has no shifts.
Not strange at all to me. To be pedantic, there aren’t really any “infix operators”, there are “infix” functions and “binary operators”. To go over your complains:
Java has no exponent operator either…why is it’s absence in Kotlin strange?
Have you ever taken a look at what the JVM bytecode does on byteVar & byteVar
? It’s actually more like ((int) byteVar) & ((int) byteVar)
(actually, the local var is an int in the first place because the JVM has no concept of byte per se, it’s just an int that undergoes narrowing as needed) So, knowing this, what type does byteVar & byteVar
return in Java? Kotlin prefers to not auto narrow/widen like Java does, so it’s the equivalent in Kotlin of byteVar.toInt() and byteVar.toInt()
. Now for the experimental Byte.and
, what would you expect it to return in Kotlin? Because Kotlin’s built-in arithmetic infix functions are expected to return the same type as their operands and they don’t support auto narrow/widen. A byte? That’s what the experimental and
does and it’s surprising behavior compared to Java. An int? That’s against Kotlin’s consistency of infix arithmetic functions. Regardless, not sure how it fits your “strange choice” for “omitted” since “byte and byte → byte” isn’t omitted, it’s just experimental…it’s the JVM where it’s omitted.
Same kinda deal w/ the shifts, your byte shifts in Java are actually int shifts and since Kotlin chooses to require explicit byte-to-int conversion unlike Java, it’s not gonna do it for you. The and is only supported because it is reasonable to expect what it’d do in place. Could you image the confusion a After some thought I do not believe that this is the reason for lack of infix fun Byte.shl(other: Byte) = (toInt() shl other.toInt()).toByte()
…people would go insane since you shifted on a 32 bit int and truncated instead of 8 bit shifting . Could emulate, but that’s surprisingly costly (i.e. the user would be surprised).shl
/shr
/ushr
on bytes. I do not know and too would be curious why (experimental) and
is ok but shl
is not. Some discussion at https://youtrack.jetbrains.com/issue/KT-14730 does mention the semantics are debatable, just not sure how in this case.
The only argument that can really be made here IMO is “why does Kotlin hamstring itself based on limitations in only one of its 3 platforms?” Unfortunately, this is the route they chose with a great many things.
While I agree with you there is a simple and good explanation for that. Kotlin decided to have java interop as one of the primary features. This is important because Kotlin tries to fight for the same platforms java does (js and native came later). Without java compatibility kotlin could never be seriously used for android and it also allows for a wide group of other jvm projects to switch to kotlin. This is one of the main reasons Kotlin is as popular as it is. It’s a great language but it also allows to easily switch to it.
As for Kotlin JS and Native, native is still experimental and JS was only released in Kotlin 1.2 I believe. This should explain why those platforms are not as influential as the jvm in regard to kotlins design.
There was a post about this:
Also I guess the KEEP for unsigned types might be interesting as well:
The power operation (**
in Groovy) is used quite rarely in mathematical tasks and could be easily replaced by infix function pow
. Introducing the whole new operator only for rarely used numeric operation is an overkill. Of course, one can always redefine those operations for different purpose, but the idea is not to do that, it just produces confusion.
By the way, I am not sure that developers were thinking about that aspect, but it is good idea to make power operation harder to write since it is not cheap, especially with non-integer power. So the number of power operations should be limited in code as much as possible.