Cast objects from type name as string

Is there any way I can cast an object at runtime to a specific type from a type name?
Or, more specific to my actual use case: I have a model, with typed properties, here eg Float32 and Vector3, create a channel out of it, then select properties via their path. Is there any way I can get this typed without creating a pad? It looks like the info is there? Or in other words, couldn’t there be a Select by Path which returns a typed channel/value instead of T?

GetChannelType-Application_2023.04.28-15.46.24

GetChannelType.vl (11.8 KB)

thank you

In the newest vvvv gamma preview (5.1.0009)

channels got some more features:

  • Every Channel<T> now is also a Channel<object>
  • Select (ByPath) outputs a channel, where the type is determined by the property type

In your scenario, this means: you still can treat the Channel as a Channel<object>, but it’s also a Channel<Float32> or Channel<Vector3> depending on which property you choose.

GetChannelType.vl (13.6 KB)

2 Likes

Hi @gregsn, thanks for your help! This does sound like what I need, but I still don’t get it :)

Is this the patch you wanted to show me?


…because I’m not sure what I should see here…? Should I use the Spread<ObjectGraphNode> and do something with that?

This is a simplified version of what I would like to be able to do in the end:

thanks a lot!

I might lack the full picture of what you are trying to do, but it sounds a bit like you are trying to mix things that don’t mix well. I think this is a pretty tricky lesson to learn and I think everybody is at times stumbling over it.

I am talking about distinguishing all things which can get tackled at compile-time already vs. stuff that has to be postponed to runtime.

Compile-time topics:

  • generic types, type parameters T
  • VL is trying to figure out types. Those that get displayed even when in stopped mode. Those are the so-called compile-time types.
  • Adaptive node implementations can get picked already

Runtime-time topics:

  • objects and ungeneric types
  • TypeSwitch making use of runtime type (which you get via object.GetType)
  • MakeGenericVLTypeInfo → CreateInstance
  • or even things like CastAs again testing for certain types at runtime

The compile-time part is there in order to make it easy to use the system and to already know which pins can be connected.

But sometimes your application is so “dynamic” that you don’t know at compile-time. So suddenly you need to make peace with the idea of working on another level. A level where you can’t know the type of your pad. It’s not float, it’s not Vector3. So you need to make it of type object in thus postpone that decision to point when the program is running.


I have seen different approaches to dealing with this situation over time.

There are libraries that are non-generic in their core. And only offer a generic wrapper. Expression<TDelegate> Class (System.Linq.Expressions) | Microsoft Learn

If you want to, you as a user can make use of the non-generic part of the library, if you don’t know at compile-time which types will flow. And in other cases, it’s just more convenient to use the generic wrappers. Point being: you have the choice of which one to use. And it’s both supported.

In other cases, you will find libraries that only offer generic nodes and types. In those cases, you will need to instantiate them at runtime via reflection & by dynamically feeding the type arguments.

So, from library to library it’s a bit different how easy it is to postpone typing to the point in time where the program is already running. But what’s really important is: you need to be aware of what’s what. You can’t switch types with an LFO at runtime and would like the compile-time type to be switched in a pad. That’s just impossible.

2 Likes

Thank you for this detailed explanation @gregsn. It is a lot clearer now.
I’m sure this will help a lot of others too - it‘s obviously fundamental, but I didn’t really see/understand this difference between generics and objects just from trying to patch with them…

Ultimately this is what I really needed to hear. I came down this rabbit hole being almost convinced there must be some kind of voodoo trick to type a pad from a patch 😅 I can see now that this can’t work.

Thank you!

1 Like

As a side note:
In 5.1 the node which returns a channel whose type is determined by the property the given path points to will be found in Select (ByPath Dynamic) .

Select (ByPath) will stay the same as it was in 5.0

1 Like

@Elias

As I understand it, is it applied somehow in this way?
But I get “Object” in the output. Is it possible to get a “String”? If not, advise a suitable way to convert quickly.

image

ByPathDynamic.vl (9.7 KB)

The compile time type of the output of Select (ByPath Dynamic) is Channel<Object>. At compile time we only know that the output is a Channel holding some Object. Connecting it to say a Channel<String> is not allowed, because it could be that the output holds something different than a String, it could contain a Banana.
We therefor need to test what the output actually contains. We can do this with the Cast nodes. In your case you know that the static string you feed to the node points to a property of type String, you can therefor HardCast the output to a Channel<String>. Should you refactor your patch and that type would change, the HardCast will throw an exception (turns pink) telling you that your assumption no longer is true.
We could also imagine that you wouldn’t know, for example you would let the string point to different things based on a variable, then you’d need to test with a CastAs node for Channel<String> or Channel<Banana>.
Another approach (and I believe that was kind of the initial question in this thread) is to ask the Channel<Object> of what runtime type it really is using the ClrTypeOfValues node. It would in your case tell you that it is a String, meaning you indeed have a Channel<String> in front of you. We could on the other hand also come up with an example where it would tell you that you have a Channel<Fruit> at hand, while the current value in that fruit channel is a Banana.

2 Likes

Now I forgot one important point: If you know where your path is pointing to and like in your case that will always be a String than there’s no point in using the dynamic version of the node, use instead the normal Select (ByPath) node where you connect a Channel<String> to its output and you’re good to go.

@Elias Thanks!
Obviously, I didn’t fully understand the concept and why a node like dynamic was being introduced.
Thank you for your explanation!

As I understand it now, is it useful with interfaces? It would be impossible without the “Dynamic” version?

What do you mean by interfaces? UIs?

@Elias I’m talking about program interfaces that are implemented by classes

As also discussed in the thread Generic interfaces Generic or even Adaptive constructs are very handy when juggling with types at compile-time or let’s call it construction-time of your program.
Dynamic versions that deal with Objects, and try to make sense of them at runtime, can deal with cases where only at runtime the exact data type becomes clear (when asking the object for its type).

Interfaces and types that implement them form a type hierarchy. That’s true whether or not you try to work with types at compile time or at runtime. So I guess “impossible without the dynamic version”: No. It’s really about WHEN you want to reason about types.


Maybe unrelated, but as I see some cast nodes mentioned above: There is a new node CastAs (Channel), which might help you at some point. Not sure. Give it a go. As most Channel operators it is a bi-directional binding. When you have an upper fruit channel and CastAs to a banana channel: throwing a banana into one of those channels will make it appear in the bound channel. Hope that helps.

2 Likes