0

I want to use higher order functions like map for open end ranges.

val from = LocalDate.now().minusDays(10)
val to = LocalDate.now()
(from ..< to).forEach(::println)

I tried to copy an example for ClosedRange<LocalDate> but it does not work.

package de.otto.di.extensions

import java.time.LocalDate

class OpenEndRangeLocalDateIterator(
    startDate: LocalDate,
    private val endExclusive: LocalDate,
    private val stepDays: Long
) : Iterator<LocalDate> {

  private var currentDate = startDate

  override fun hasNext() = currentDate.plusDays(stepDays) <= endExclusive

  override fun next(): LocalDate {
    val next = currentDate
    currentDate = currentDate.plusDays(stepDays)
    return next
  }
}

@OptIn(ExperimentalStdlibApi::class)
class OpenEndLocalDateRange(
    override val start: LocalDate,
    override val endExclusive: LocalDate,
    private val stepDays: Long = 1
) : Iterable<LocalDate>, OpenEndRange<LocalDate> {

  override fun iterator(): Iterator<LocalDate> =
      OpenEndRangeLocalDateIterator(start, endExclusive, stepDays)

  infix fun step(days: Long) = OpenEndLocalDateRange(start, endExclusive, days)
}

infix operator fun LocalDate.rangeUntil(to: LocalDate): OpenEndLocalDateRange =
   OpenEndLocalDateRange(this, to)

It is implemented for Int so I assume it must be possible somehow. How can I achieve this?

Ben Keil
  • 1,050
  • 1
  • 10
  • 30
  • I've provided an answer that 'solves your problem', but also I noticed that your `compareTo` function is recursive and will almost certainly cause a stack overflow. I don't think that you actually want `OpenEndLocalDateRange` to implement `Comparable` because that defines comparison relationship between `OpenEndedLocalDateRange` and `LocalDate` which doesn't make a lot of sense in most cases. – undermark5 Oct 19 '22 at 16:37

1 Answers1

0

The issue here is that you've defined the operator function to return OpenEndRange<LocalDate> rather than OpenEndedLocalDateRange. If you change the return type of your operator function that should fix the issue.

The reason why it isn't working as is is because OpenEndRange doesn't have the higher order functions defined for it (ClosedRange doesn't have them defined as well). Int has it because the operators return an IntRange which indirectly extends Iterable<Int> via IntProgression and Iterable has these higher order functions defined, so, the only missing piece is failing to return the correct type from your operator function.

undermark5
  • 775
  • 6
  • 17
  • I updated the code, but it still does not work. – Ben Keil Oct 19 '22 at 19:28
  • It looks like Kotlin does not recognise that this function exists at all. When I click on the operator I end up with `public operator fun > T.rangeUntil(that: T): OpenEndRange = ComparableOpenEndRange(this, that) ` – Ben Keil Oct 19 '22 at 19:30
  • 1
    You may need to import your implementation of the extension function. I've got the code all in the same file and clicking on the `..<` takes me to the defined extension function. If you've got them in different files, you need to make sure that you import the correct one. That being said, I'm also unable to run the code because `..<` as an operator is still new and IDE support is limited https://kotlinlang.org/docs/whatsnew1720.html#preview-of-the-operator-for-creating-open-ended-ranges – undermark5 Oct 19 '22 at 23:29
  • Alright, found how to enable the feature from watching this video https://www.youtube.com/watch?v=v0AHdAIBnbs Anyway, long of it is I have it working with everything all included in a single file, so double check that you are importing things correctly. – undermark5 Oct 19 '22 at 23:40
  • Also, even though it seems like this should be something implemented natively out of the box like it is for Int and Long or Char, but considering that previously you couldn't do `1.0 until 10.0` for the reasons described in that video, it also doesn't make sense to iterate over every value in there (there isn't a `forEach` defined for DoubleRange because it doesn't make sense as mathematically speaking there are infinitely many real numbers between any 2 integers, and no real discrete steps. – undermark5 Oct 19 '22 at 23:46
  • the problem was just that IntelliJ didn't import the extension function automatically. If you do this manually it works. – Ben Keil Oct 20 '22 at 06:26