Hi! I'm trying to use contracts but I don't entire...
# getting-started
j
Hi! I'm trying to use contracts but I don't entirely get it. My problem is I want to have the return value of a member function on a data class help the compiler infer something about a value of that data class, and I don't understand if this is actually doable with contracts or not. Here's a minimal example:
Copy code
data class TimeRange(
  val from: Instant,
  val to: Instant?,
) {
  fun isOpenEnded(): Boolean {
    return this.to == null
  }
}
Optimally, I'd like to be able to use this helper and have the compiler still correctly infer whether
to
is null or not. If I now add a method to check if a TimeRange ends later than another, it might look like this (it's logically incorrect but nevermind that for the sake of the example)
Copy code
fun endsLaterThan(other: Timerange): Boolean {
    return this.isOpenEnded() || (!other.isOpenEnded() && (this.to > other.to))
}
However, this code does not work as-is, the compiler gives me trouble about nullability. To my human eyes and brain it's clear that the final statement
(<http://this.to|this.to> > <http://other.to|other.to>)
is only reachable if neither
<http://this.to|this.to>
or
<http://other.to|other.to>
is
null
, since that would short circuit the boolean operations. The compiler does not infer this, so I thought I might be able to help it along using contracts! I have tried to add something like this, but it does not seem to work since I'm using
implies
to say something about a member of the receiver and not just the receiver itself?
Copy code
fun isOpenEnded(): Boolean {
  contract {
    returns(true) implies this.to == null
    returns(false) implies this.to != null
  }

  return this.to == null
}
If there's a way to make this work, I'd love to know! Links to reading material about contracts in general is also appreciated 👍
d
Contracts don't work on members of receiver/parameter. Only on receiver/parameter itself.