Do I need all of these toLong()s and toInt()s?


#1

In my Rational number implementation, I find myself doing a lot of conversions of longs to ints and back again in order to, in particular around https://github.com/sanity/kotlin-rational/blob/master/src/main/java/rational/Rational.kt#L39.  If I don't do these conversions I end up getting various Required: jet.Int Found: jet.Long errors (or the other way around).

Am I doing something wrong here?  It seems that Kotlin is more sensitive to mismatches between Ints and Longs than Java - is this the case?


#2

Yes, Kotlin is more picky about types than Java. There're no implicit type conversions in Kotlin, they are bad and dangerous. See the "Java Puzzlers" book.

You don’t need all of those toLong()'s, though. Only a few:

``

                   val bits = java.lang.Double.doubleToLongBits(numberAsDouble)
                   val sign = bits ushr 63
                   val exponent = (((bits ushr 52) xor (sign shl 11)) - 1023)
                   val fraction = (bits shl 12)
                   var a = 1.toLong() // here
                   var b = 1.toLong() // here
                   var i = 63
                   while (i >= 12) {
                   a = a * 2 + ((fraction.ushr(i)) and 1)
                   b *= 2
                   i–
                   }
                   if (exponent > 0)
                   a *= 1 shl exponent.toInt()
                   else
                   b *= 1 shl -exponent.toInt()
                   if (sign == 1.toLong()) // here
                   a *= -1
                   Rational(a, b)


#3

Actually, you don't have to do

fun Rational(number: Number): Rational =   when (number) {            is Int -> Rational(number.toLong(), 1)            is Long -> Rational(number, 1)            is Rational -> number            else -> {           // ...         }      } }

You can do simply this instead:

fun Rational(number: Int): Rational {   // ... }

fun Rational(number: Long): Rational {
  // …
}

fun Rational(number: Rational): Rational {
  // …
}


fun Rational(number: Object): Rational {
  // …
}

You are already doing this in your code with this constructor:

fun Rational(str: String): Rational {   // ... }

I guess you could solve a lot of those type problems by making use of parameter polymorphism. Also, Kotlin supports multi-methods. The code below will print "as .... string ..." and not "some object" as in Java.

open class MyObject() {

  fun foo(str: String) {
  println("as … " + str)
  }

  fun foo(obj: Object) {
  println(“some object”)
  }
}

public fun main(args : Array<String>) {
  MyObject().foo(“string …”)
}


#4

Yes, Kotlin is more picky about types than Java. There're no implicit type conversions in Kotlin, they are bad and dangerous. See the "Java Puzzlers" book.

My might consider Groovy if this is too strict for you:

class Test {

  @CompileStatic
  def static main(args)
  {
  def String str = new HashSet<?>()
  println str
  }
}


This compiles fine in Groovy 2.0 and prints “[]” to the console. I think it’s a bug, though. But I don’t know enough Groovy to tell.

P.S.: This was ironic


#5

Ah, interesting - so it will always pick the more specific method?  That's good - I'll make the change.


#6

That's ok, I prefer static typing :-)


#7

This here is not so bad:

fun Rational(number: Number): Rational =   when (number) {            is Int -> Rational(number.toLong(), 1)            is Long -> Rational(number, 1)            is Rational -> number            else -> {           // ...   }   } }

Problem is that people can do this:

fun Foo(bar: Bar): Foo =   when (bar) {            is Elefant -> ...            is Tomato -> ....            else -> {           // ...   }   } }

This is why I don't like this when-is clause that much as you can always use it as some way out in case you don't understand what your own code is doing. Greetings from Niklaus Wirth... Not offering it does not prevent people from doing this, though:

if(bar instanceof Elefant) {   // ... } else if(bar instanceof Tomato) {   // ... }

So it is hard to argue against this when-is thing. It is taken from Erlang, I know. But there it is needed as Erlang is not object-oriented and you can't make use of late binding and hence overloading/polymorphism. But I'm still looking for some nice sample where this when-is clause is really useful in an OO world ...