Basic type conversions


#1

I’m still not sure either this is a bug or a feature.

val skewX:Float = Math.atan((-c / d).toDouble()).toFloat()

I understand why I need the conversion from Double to Float, but why is there a conversion from Float to Double needed? In the docs you’re mentioning that it is required with nullable types because of boxing/unboxing problems, but I can’t see why I had to create this monstrosity in my case.

edit: If that’s not clear (and it probably isn’t) c and d are Floats and atan() takes a Double.


#2

That calls for an extension function on Math that does the conversion for you. There are some drawbacks though, so that may be why it doesn’t exist in the standard library (either Java or Kotlin)


#3

You mean there is (is supposed to be) an extension function for that? Even if there is, I can’t see why the explicit conversion from Float to Double is needed in this particular case - there’s no boxing/unboxing happening here.


#4

I don’t mean there is one, but you can easily write one for yourself, although it wouldn’t technically be an extension (can’t have the Math… prefix, but that is very verbose anyway). I’m in the middle on whether there should be one (and friends for the many similar functions in Math):

    inline fun atan(a:Float):Float = Math.atan(a.toDouble()).toFloat()

Btw. in your particular example, you should probably use Math.atan2 instead


#5

Yes, you’re more than right! :slight_smile: Was just porting it and didn’t even care to check that :slight_smile: Thanks!


#6

OK, I run into another thing yesterday and really have no idea why it has to work this way:

val src:ShortArray = ...
val dst:ShortArray = ...
val offset:Short = ...

for(i in src.indices)
    dst[i] = src[i] + offset // this won't compile
    dst[i] = (src[i] + offset).toShort() // this will

Why is the conversion needed here? Is it a bug? It looks like + operator returns an Int, no matter what the types of input params are.


#7

It is because: short + short = int.


#8

Well, yeah, but why? I mean why does it have to be like this?


#9

Because the Java spec says so: https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.2


#10

You mean all numerical operations in Java are carried out using 32-bit integers? That’s OK, but the problem here is how Kotlin handles this kind of things, not Java.

I mean there’s a complete information here which should allow the compiler to make this cast automatically - I’m adding two values of the same type and assigning it to a third value of the same type as well. If a cast is needed because of how things work internally it can and should be generated by the compiler - there’s no point in making me do it in the code every time I add two non-Ints, is it?


#11

And what is, if you add 1 to the max value of short?


#12

But it doesn’t matter - you’ll get an Int you can cast to Short. I’m talking about making the cast automatic, which is all about how operators are implemented - currently all of them return an Int, event if both values are not Ints.


#13

It is about making potential errors explicit.


#14

You’re adding two values of the same type - where’s this potential error there? If you needed a Short as a result, you should get it without making the cast. If you needed an Int as a result, you should cast both Shorts to Int and add the results, like this:

val shortResult:Short = shortA + shortB // potential overflow
val intResult:Int = shortA.toInt() + shortB.toInt() // no overflow

#15

The potential error is the overflow! You are simply assuming that the sum of both shorts is less then the maximum short value. This could be correct in some situations but it is not guaranteed. To avoid such bugs, the compiler behaves as is.


#16

But I need to assign it to Short anyway, so there’s gonna be an overflow this way or another. In some applications (like rendering with OpenGL) you’re forced to use Shorts (my original scenario was creating an index buffer, which has to use Shorts). The only problem here is I need to explicitly cast to Short before the assignment, because the compiler does not create this cast automatically, which would be perfectly safe in this scenario.


#17

But your specific scenario can not be generalized and baked into the compiler … But let’s stop here. It is like it is. And it is implemented properly in the compiler.


#18

Of course it can and should be baked into the compiler, because that’s how it works everywhere outside Java :slight_smile: When you’re adding two integers, there’s always a chance of overflow, making you do the cast manually doesn’t fix that - it just makes your code less readable.

And, when adding two Shorts like in this particular example, you want to have an Int as a result and don’t have to worry about the overflow, you simply cast your Shorts to Int before adding them, like so:

val intResult:Int = shortA.toInt() + shortB.toInt()

#19

And what about the adding of 2 Ints? Is that a Long? Furthermore, I see that Short / Short => Int, hmm?


#20

Can I ask a clarification question about your code, if you don’t mind, please. I do understand why you might want to have two ShortArray values in your code, but why would you declare offset of Short type? EDIT: Disregard. I see now. It is coming from one of your short array. Makes total sense for me now.