https://kotlinlang.org logo
#stdlib
Title
# stdlib
k

kevin.cianfarini

01/18/2023, 7:17 PM
I’m working with
OpenEndRange
and I’d like to understand the rational for why
ComparableOpenEndRange.equals
specifically checks if the
other
instance is
ComparableOpenEndRange
.
Copy code
override fun equals(other: Any?): Boolean {
        return other is ComparableOpenEndRange<*> && (isEmpty() && other.isEmpty() ||
                start == other.start && endExclusive == other.endExclusive)
    }
My use case is that I have a custom implementation of
OpenEndRange<LocalDateTime>
which I want to be equitable against
ComparableOpenEndRange
. My implementation of equals checks for this
Copy code
override fun equals(other: Any?): Boolean = when (other) {
        is LocalTimePeriod -> other.start == start && other.timeZone == timeZone && other.duration == duration
        is OpenEndRange<*> -> other.start == start && other.endExclusive == endExclusive
        else -> false
    }
And therefore equality checking works when my implementation is on the left side of the
==
operator. However when a comparable open range is on the left hand side of the operator, because my custom impl is not an instance of
ComparableOpenEndRange
, the equality check fails. I believe this is an oversight in the stdlib but I’m wondering if this is by design? If so, what is the rationale?
I can file a YouTrack bug if this is not desirable!
i

ilya.gorbunov

01/18/2023, 8:28 PM
OpenEndRange
same as
ClosedRange
does not define its equality contract, however its implementers can do.
The reason is that there can be different implementations of Open or Closed ranges with different properties and we don't want them to be considered equal just because their bounds are equal.
k

kevin.cianfarini

01/18/2023, 8:37 PM
Can you give an example of where that [lack] of contract would be useful for the stdlib?
i

ilya.gorbunov

01/20/2023, 8:23 PM
If two instances are being equal, that means that one can be substituted for another without change of behavior. However that's not the case with various range inheritors. For example, there can be
ClosedRange<Int>
that is instantiated in some generic code and the specialized
IntRange
. The latter is iterable but the former is not.
👍 1
2 Views