If it possible, what should be done to get “any type ok” from VL patch?
Maybe it’s more generalized question — is there a way to achieve some level of genericity? For example, to get any pins from VVVV-patch and work with types and values in the VL-patch.
“any type ok” in beta is a trimmed-down version of Generics. Beta however has no compiler and all the types get agreed upon by nodes talking to each other when some connection is drawn. After the negotiation between the nodes is finished the type is clear and as with actual generics is safe to say that over the connection only certain data can flow.
Generics in .Net of course is much more complex and it doesn’t sound too trivial to combine the two worlds.
However, in some cases, you just want something to work, without all the elegance that generics promise: mainly the type safety. Did you try to work with objects and cast back and forth? I know it sounds like insane, but remember that .Net and other programming languages existed before generics were invented. And still there are many languages in the dynamic typing department. So I am just wondering if you are trying to end up with a beautiful synergy of beta and VL or you simply working on a project where you ran into the issue. For the later case: Try to work with Spreads of objects. These now can contain anything. Route them through your beta patches. And with OfType downstream you can filter for those of the right type. Is that an option for you? ObjectSpreadSketches.zip (5.5 KB)
@gregsn Actualy it was first case — I’m trying to explore deeper layers of these tools.
Why complex and well engineered libraries for VL use a lot of RegisterService nodes? How it connected with this topic and it can be useful at beta? How can be useful an access to VLFactory and what is this in nature?
By the way, your example is brilliant! Very appreciate!
Why complex and well-engineered libraries for VL use a lot of RegisterService nodes?
Are you talking about Kairos? This library makes heavy use of one particular design pattern: model & runtime separation.
Having an immutable model separated from the mutating runtime makes it easier to implement undo & redo. You don’t need commands and commands that undo commands. You only think about state snapshots: the model.
The runtime is the patch that does all the work since the model is just a description. Also: if the model is an object graph of one model referencing the other models (e.g. Children) then you need to synchronize and create the runtime equivalents for all your Children.
Now suppose that not all children are of the same runtime type. Let’s say there are different kinds of clips inside Kairos (constant, live or to be sampled data) modeled as different model types (inheriting from one common interface IClip). Then the question arises: How can we easily make sure that the right runtime patch gets created on sync? You could have a type switch, but then the library is closed and not open to additions by the user. Having a registry allows us to make it create an instance of the right runtime for a model.
There might be more cases for using RegisterService, but this one is the most prominent. And there are other ways of doing this: The model could have a method that creates the runtime and there are small pros and cons of the different ideas… Do I want to need to know the right runtime type within the model patch? How hard is the registration of all types with RegisterService? Do I know of all types at the time of registration? It’s still all about patterns that are still being evaluated.
How it connected with this topic and it can be useful at beta?
Not sure it is connected. Other than in “everything is connected”.
The service idea is about a living thing for which you need a partner object (another living thing) and you want the service factory to create that partner object for you. So it’s all about what’s happening on runtime. It’s a small idea that can make your life easier because you can delegate the task of this to some node and are left with some brainpower to focus on what you actually wanted to do.
The Generics chapter isn’t so much about runtime behavior. It is more about how to guarantee that we end up with type-safe patches. So generics are sometimes about performance, but often enough just about type-safety and some good feeling when patching when drawing connections. So it’s a bit about programming itself.
Regarding beta: The RegisterService stuff is helpful for beta, as VL is running inside beta. But not any further. The Generics stuff is a different topic and as said above it’s unlikely that we’ll try to combine the beta with the gamma generics approach. It’s one of the selling points of VL that there is this rich generics support.
How can be useful an access to VLFactory and what is this in nature?
The VLFactory is something that helps you create objects. Internally it is something like a Dictionary from Type to your delegate that says how to actually create the object.
This is huge! It’s hard to express how I appreciate such explanations. I need some time to understand every word in this explanation, but some things seem more clear at this point for me.
Can you do something simple to explain RegisterSevice? It’s interesting in both contexts - gamma and beta. Actually, I should bring some more attention to Mode-Runtime-Editor example you mentioned — I remember Nathan’s explanation, but I think I missed this one. UPD: I’ve seen this before, a very good explanation. But nothing about RegisterService as I remeber
Ideally, my ultimate goal in research is one little project I’ve been wanting to do for a long time. I want to write a library for interacting and mapping MIDI controllers. And I want to understand these technologies, because it would be great to write extensions for Elementa fluently, for example.
I can’t tell you when you need RegisterService. It’s the other way around. At some point, you realize that you need some B for some existing A. The VLFactory helps you to create the right B. But as said there there are other ways to do it. A might know how to create the right B.
Am I right that the RegisterService “operation” is called when the TryCreateService function is called exactly for specified in “Result” pin interface? I should call TryCreateService explicitly? At some point, I thought it must be some kind of “automatic process”.
I think I figured out what one of the main advantages of this approach is. In this context, we need to talk not about the Model-View-Editor, but about the composition patterns. The main problem that an ordinary VL user may have is the serialization problem. By registering services, this problem can be circumvented, since the behavior can be provided during composition, object creation, or updating. What about performance? Is this approach not expensive?
I wrote myself a tool in a couple of days that can manage my nanoKONTROL, with pages and states saved to an xml file and loaded after a reboot.