Kairos icon indicating copy to clipboard operation
Kairos copied to clipboard

Implement Non Generic interface for Channel

Open natan-sinigaglia opened this issue 2 years ago • 4 comments

natan-sinigaglia avatar Sep 16 '22 17:09 natan-sinigaglia

I implemented that and it's available for review in vvvv prevews.

Channel (Ungeneric) is modelled as an abstract base class of Channel<T>. Therefore any channel is at the same time a channel with generic and ungeneric access. It's the same thing.

It's modelled in a way that any Channel<T>is also an ISubject<T>, which in turn is IObservable<T> and at the same time it's also ISubject<object> (...).

After playing with it, I found that this design of having one object with so many views (interfaces) onto it, might just be a bit too much. E.g. when connecting to a rective foreach: should T get infered? Or object? Or do you always want to specify? I guess not.

Maybe it's worth the extra route and try a few more different designs and decide then.

Currently thinking:

  • Channel<T>: ISubject<T>
  • has Property Ungeneric: Channel (Ungeneric), which is linked to Channel<T> in a way that changing one also changes the other.

This design might be more complicated to implement (the two things are subscribed to each other forever), it's two things after all, not one. Also the usage might be more complicated, as you always need to access the property, when going from ungeneric to generic. To be discussed: How to get back?

However, it might be worth the effort. We don't end up with this weird foreach topic.

Opinions?

gregsn avatar Sep 19 '22 12:09 gregsn

Having two channels while it should be one doesn't sound any easier. For example how can I put them even in a list when I need to access a property which is defined on the generic type.

You said while playing with it - can you elaborate on that? What did you do? Was it made up or was there some real use case behind it?

How about the non-generic version doesn't implement the reactive interfaces. Instead it gives accessors like AsObservable or AsObserver which handle the translation?

azeno avatar Sep 19 '22 12:09 azeno

Having two channels while it should be one doesn't sound any easier. For example how can I put them even in a list when I need to access a property which is defined on the generic type.

The whole purpose of the ungeneric version is to be able to do everything you'd be able to do with the generic version. With the sole difference that you work with object. But there could be a back-pointer to the generic thing still.

You said while playing with it - can you elaborate on that? What did you do? Was it made up or was there some real use case behind it?

It was "playing" on a technical level. I just tried to connect to a foreach, put some type annotations (in order to cast to the ungeneric version). Stuff like that. And then the mentioned type inference issue came up - the one that currently magically does work as wanted, but also can be considered as a type inference inaccuracy (currently infering T inside the region, when it's actually ambigious what you want to express).

How about the non-generic version doesn't implement the reactive interfaces. Instead it gives accessors like AsObservable or AsObserver which handle the translation?

Maybe. Yes. Or we have a UngenericChannel : Channel<object> where Channel<T> has a Partner property. UngenericChannel would be not more than a "type alias", not adding adding much to Channel<object>. So those two channels, one of type T, one of type object would be linked and can both be used for any channel business. They both are of type Channel...

gregsn avatar Sep 19 '22 16:09 gregsn

Or we model it in a way that

  • UngenericChannel has all the logic and
  • Channel<T> again is derived from it and just offers a generic view onto it.

This approach is known from Expression<T> https://learn.microsoft.com/de-de/dotnet/api/system.linq.expressions.expression?view=net-6.0 where the ungeneric Expression already covers everything.

From a performance standpoint: It's probably more efficient to do the boxing and casts that this approach entails, when compared to the approach that syncs two partner channels.

That said: As long as we want the ungeneric channel to be an IObservable<object> (to be able to easily connect it to a foreach) and the derived one to also be a IObservable<T>, we didn't really solve the issue yet... Only the partner approach can dissolve the ambiguity issue - or the AsObservable idea...

gregsn avatar Sep 19 '22 16:09 gregsn