Animesh Sahu
09/25/2020, 5:04 PMfun <T, E : SomeType<T>> function() {}
Then both T and E needed to be specifed
And for example this:
fun <T, E : SomeType<T>> function(v: T) {}
if we pass function(5)
(T) as one of the parameter then E is automatically taken as SomeType<T>, but why cannot we have half implicit parameter like function<Int>()
that could implicitly say about the second parameter?
Or does it exist, I'm just not noticing it?Nir
09/25/2020, 5:05 PMasad.awadia
09/25/2020, 5:47 PMNir
09/25/2020, 6:02 PMfun <T, E : MutableList<T>> foo(e: E, t: T): E {
e.add(t)
return e;
}
fun <T> foo(e: MutableList<T>, t: T) ...
asad.awadia
09/25/2020, 6:08 PMNir
09/25/2020, 6:23 PMbsimmons
09/25/2020, 7:17 PMNir
09/25/2020, 7:19 PMfun <T, E : List<T>> foo(e: E, t: T): E {
return e + t
}
Ruckus
09/25/2020, 10:11 PMplus
it's defined on List
. You can't guarantee the result is anything other than List
. No E
.Nir
09/25/2020, 10:57 PMAnimesh Sahu
09/26/2020, 3:26 AMinterface Event<E, C: ObservableCollection<E>> {
val collection: C
}
// Series of events like ElementAddEvent, ElementReplaceEvent, etc.
class ElementAddEvent<E, C : ObservableCollection<E>>(
val element: E,
override val collection: C
) : Event<E, C>
If I wanted to give out this, without loosing the type safety,
inline fun <E, C : ObservableCollection<E>, reified T : Event<E, C>> C.on(
scope: CoroutineScope,
noinline consumer: suspend (T) -> Unit
): Job =
events.buffer(Channel.UNLIMITED)
.filterIsInstance<T>().onEach {
runCatching { consumer(it) }.onFailure { /*Log exceptions*/ }
}.catch { /*Log exceptions*/ }
.launchIn(scope)
Now, to call it, we have to pass all three E
the element type, C
the collection type, and T
the event-type.
Well, C and E comes from the collection it was called on, so I guess only T should be a required parameter.
Then again, if I try to specify the Event type, ElementAddEvent<E, C : ObservableCollection<E>>
We have to pass the E and C here inside as well, that too comes from the type of Collection, it seems to redundant to call the function like:
observableList.on<Int, ObservableList<Int>, ElementAddEvent<Int, ObservableList<Int>>> {
}
observableList.on<ElementAddEvent> {
}
That could have look much better now!bsimmons
09/26/2020, 5:37 AMEvent<E>
everywhere. Explicit is better than implicit. Personally, I think doing this makes the code MUCH clearly that the original. (And at worst, you can typealias
)
Here is what I think you want. (Also, I'm not sure what a ObservableCollection
is, so I just changed it to Flow
which seems to work)Animesh Sahu
09/26/2020, 7:21 AMevent
, that is a flow of Event<>) from where I'm overriding functions like add/remove/set and emitting the different types of event. ObservableList is similar to MutableList, and so on. So I wanted a type-safe event class, like for example if event is emitted from a ObservableList then collection should be ObservableList, and if event is emitted from a ObservableSet then collection variable in that case should be ObservableSet inside Event.
Next thing is .filterIsInstance<Event<E>>()
you've shown does nothing. I want to filter events like ElementAddEvent, ElementReplaceEvent, ElementRemoveEvent.Event<E>
from Flow<Event<E>>? It will just going to push all the Events at once. Its same as just not filtering any sub-type of event!bsimmons
09/26/2020, 1:37 PMElementAddEvent<Int>
. I've tried to recreate your ObservableCollection<E>
as you specified, but it's hard to know if I got that part right.
Does this look better?Animesh Sahu
09/26/2020, 1:49 PM<T : CharSequence>
and pass <*>
and then try to get value, it opens as CharSequence but not actual type like String or StringBuilder for example (I learnt new thing today thanks! 🙂).bsimmons
09/26/2020, 2:15 PMEvents
in general, but don't care at all about the generic inside the Event
.
Every day is a learning day. Life, our teacher; and we, her students.Petter Måhlén
09/28/2020, 7:01 AMfun main() {
val collection: ObservableCollection<Event<Int>> = CustomObservableArrayList(flow {})
collection.on<ElementAddEvent<String>>(GlobalScope) {
println("We can successfully type infer this ElementAddEvent<Int> ${it.element + 1}.")
Unit
}
}
That, is to choose different values for inner type parameter denoted by the two stars? (String and Int in the example).Animesh Sahu
09/28/2020, 7:26 AMbsimmons
09/28/2020, 1:39 PMenum
instead of over-using the type system.)Animesh Sahu
09/28/2020, 1:58 PMbsimmons
09/28/2020, 2:39 PM<E: Map<F, Event<G>>>
). Maybe someday (but very likely not).
I think for your situation you will always have to pass at least two types. The base E
type, and then the reified type. So <E, reified T: Event<E>>
, not ideal, but if you truly want access to the reified instance, then both are neccessary.Animesh Sahu
09/28/2020, 2:45 PMkotlin
observableList.on { event: ElementAddEvent<Int> ->
}
It works, but I really wanted to shift this to Generics as IDE usually lands you on generic at autocompletion. And generic looks (alot) cleaner.
If there were optional generics, it could actually look better.bsimmons
09/28/2020, 2:55 PMInt
. I don't think it'll get much cleaner than that.