I have a simple "Observable" wrapper that I was pl...
# announcements
t
I have a simple "Observable" wrapper that I was playing with.
Copy code
class Slot<T> {
   private var _value:T
   var value:T
      get() = this._value
      set(newValue) {
         this._value = newValue
         // trigger notifications here
      }
I wanted to add a variant of the
value
interface for types of
T
that are
Comparable
that would filter out no op changes. So I added the following extension:
Copy code
var <T : Comparable<T>>Slot<T>.concisely:T
   get() = this.value
   set(newValue) {
      if (this.value != newValue) {
         this.value = newValue
      }
}
This works like a charm...
Slot<Int>(42).concisely = 42
does just what I want. The inner
value
doesn't get called. Where this falls apart is when I have a
T
that is an optional.
Slot<String?>("foo").concisely = "foo"
won't even compile:
Copy code
Type for parameter bound T in
var <T : Comparable<T>>Slot<T>.concisely:T
is not satisfied: inferred String? is not a subtype of Comparable<String?>
I have thrown various alternate incantations at my extension to try and accomodate optionals, but nothing seems to work. Is it even doable? What am I missing? I know that I can use
==
on optional types...
n
Have you tried using kotlin's lovely observable delegate? That should work for nullable Ts. (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.properties/-delegates/observable.html)
m
Why do you need
Comparable
for your use-case?
!=
is desugared into calls to
equals
, not
compareTo
If we go back to your original example, the problem is that
T : Comparable<T>
bound states that
T
should be a subtype of a non-nullable type, which can never be true for nullable
T
. If you really do need
Comparable
(which is unfortunately contravariant) and also want to support nullable types, you can cheat a little 😃
Copy code
var <T : Comparable<Q>?, Q : T> Slot<T>.concisely: T
    get() = this.value
    set(newValue) {
        if (this.value != newValue) {
            this.value = newValue
        }
    }
t
@nils I haven't tried that. We use our own because it ports back and forth between Swift and Kotlin easier just to have our own observable thing
@Marat Akhin Thank you! that worked like a charm. I don't entirely understand why. I used Comparable I guess because I wanted to specialize it for types that can be compared using ==/!=. Is there a type that captures that instead of comparable?
Or are all objects in kotlin implicitley able to be compared, so I don't need a type specific extension, just put the method up in Slot? I guess I should try that 😕
I did it, and it works. Durh. It's so easy to get caught in the 1:1 translation between Swift and Kotlin because so much is transliterable, until you find these edge cases.
m
That's exactly right, all Kotlin classes inherit from
Any
which provides equality )))