JodaTime and Nullables


#1

I have recently started playing with JodaTime within Kotlin an noticed some behaviour that seems odd.  All the calls to JodaTime (DateTime.now() etc.) all return Nullable objects.  This is a bit annoying because it breaks any of my extension methods that expect DateTime.  For example the following function does some assertions on a DateTIme class,

fun Expectation<DateTime>.toBeOnOrBefore(val date: DateTime) : ExpectationChain<DateTime> {

  val targetJustDate = target.toDateMidnight() as DateMidnight

  val dateJustDate = date.toDateMidnight() as DateMidnight

  assertTrue(targetJustDate.isBefore(dateJustDate) || targetJustDate.isEqual(dateJustDate))

  return ExpectationChain(this)

}

However the using this method with Joda, because all calls seem to return a nullable type it's had to be hacked into something resembling this,

fun Expectation<DateTime?>.toBeOnOrBefore(val date: DateTime?) : ExpectationChain<DateTime?> {

  val targetJustDate = target?.toDateMidnight()

  val dateJustDate = date?.toDateMidnight()

  assertTrue((targetJustDate?.isBefore(dateJustDate)?.or(targetJustDate?.isEqual(dateJustDate) ?: false)) ?: false)

  return ExpectationChain(this)

}

Which is a bit crufty.  So my questions is 2 fold,

  1. Why does Kotlin treat these calls as returning Nullable types and can it be avoided?
  2. Is there are better way of handling extension functions in this case that may or may not be nullable (avoiding all the dereferencing etc.)?

#2

James,

Unfortunately, when using existing Java APIs, it’s not easy to be sure that specific method cannot return null. That’s why all methods are treated as returning/taking nullable types. If you sure that specific API method doesn’t return null, you can use “!!” postfix operator, e.g.:

DateTime.now()!!

Of course, it’s not very convenient, and it makes the code pretty dirty, but now it’s the easiest solution. It is expected that in next Kotlin milestone you will be able to define Kotlin signatures for existing APIs method using external annotations. So you’ll only have to declare that DateTime.now() cannot return null only once.

In future, we are going to add bytecode analyzer which would detect methods which can’t return null or parameters which cannot be null, so in some cases Kotlin signatures for existing APIs will need less manual work.


#3

Ah right.  Grand.  The !! method is still a lot easier than appending as <TYPE> after each call :)

Thanks


#4

So I started tinkering with this idea of kotlin signatures and for now I decided to just shim all the methods I need via a proxy class,

``

package kotlin.shim.org.joda.time

import org.joda.time as original
import java.util.Date

class DateTime(val inner: original.DateTime) {

  this() : this(original.DateTime())

  class object {
  fun now(): DateTime {
           return DateTime(original.DateTime.now()!!)
  }
  }

  fun toDate(): Date {
  return inner.toDate()!!
  }

  fun minusHours(val hours: Int) : DateTime {
  return DateTime(inner.minusHours(hours)!!)
  }

  fun minusDays(val days: Int) : DateTime {
  return DateTime(inner.minusDays(days)!!)
  }

  fun plusDays(val days: Int): DateTime {
  return DateTime(inner.plusDays(days)!!)
  }
}

It fits my needs right now anyway :slight_smile: