helo patchers,
here is the fourth in a series of blogposts about our forthcoming nextbigthing that we still call vvvv50 (50). If you haven’t already done so please first read the previous issues with the titles:
So “Generics”, uff, sounds so serious, I know. Still we have to mention them now because it will help you understand things further down the road. And you’ll be surprised how easy the concept is to grasp. Promised.
No generics in 45
In vvvv45 (45) we don’t have generic nodes. What we have instead is a lot of identical nodes like eg. “Zip” available for different datatypes. There is a Zip (Value), a Zip (String), a Zip (Color)… and the nodebrowser is full of such duplicates for a lot of nodes, like GetSlice, Select, Queue,… all of which are nodes where the operation they do for us is actually independent of the datatype they handle. We can call such operations “generic” in the sense that if for example you think of the functionality of a Zip it is not really important to know whether it zips slices of a spread of strings or a spread of colors. Easy? Yep.
In a 45 patch nodes like Zip already look generic because precious screen-space is saved by leaving out information that would not help in understanding the functionality of a patch. Still the nodebrowser is full of duplicates you have to explicitly choose between.
Only recently we’ve introduced a way for plugin developers to easily create duplicates of those generic nodes for their own datatypes but that is really only a workaround to the fact that we don’t have support for generics built right into 45. Still better than nothing, see: generic-nodes.
Generics in 50
Now when we say 50 has support for generics we can advertise that in two ways:
For the casual patcher
First, the nodebrowser will have less nodes to choose from because it can leave out many duplicates (well, it will have many more other nodes but at least no datatype-duplicates). If you want a Zip you don’t have to decide for which type you want it. Just place it in the patch, connect anything to it and you’re done. 50 will figure out what you mean.
In a 50 patch a zip is a zip is a zip and you can connect any datatype to it. So in this example the left zip is forced to operate on values and the right zip is forced to operate on colors only.
For the pro patcher
Secondly (and this is probably a bit more abstract to wrap your head around, but please try:) when you patch an operation you can be unspecific about the datatypes of its inputs and outputs. Sounds exciting? Here is an example: Consider someone patched the functionality of a Queue. This is what it could look like in 45 and 50:
Queue (Value) in 45 vs. Queue (Generic) in 50
Reading those two patches: The Inlets and Outlets (Item, Insert, ..) of both implementations are the same and the FrameDelay, as we’ve already learned, is replaced by a property (called “Items” here). And while both kind of look generic, in the 45 implementation we see the Itempin obviously is a value IOBox. Therefore we know that this is a specific implementation for values.
In the 50 implementation you see all the operations (clear, insert, take) are working on the generic collection type Spread, ie. they have not yet been forced to operate on a specific type like Spread of value or Spread of color. And you can easily identify pins, in- and outputs and the property that are generic as they are visualized in a different way (ie. only showing their contour). So here is a single implementation of a queue that works for any datatype at a time, even ones that you create yourself (more on that in the next post).
What you take away here is that 50 comes with a set of generic spread operations (insert, take, zip,…) for handling any kind of data and the problem you sometimes faced in 45 where individual spread operations were only available for specific datatypes, is no more.
And the best of it all which is really only a side-note here: For all those basic generic spread operations we don’t have to write a single line of code. In 50 we can magically make use of that functionality as it comes with the .net library. Besides the fact that this saves us a lot of time it also means those basic operations can be assumed virtually bug-free, not only because we didn’t write them but also because Microsoft has been taking care of testing that code since years.
That just for a little soothing happynew50 update. Now fasten your seatbelts for the next issue with the blockbuster title “Custom Datatypes”.
If what you just learned makes you feel like inserting coin, don’t hesitate and click: /downloads|vvvv.
Comments:
Comments are no longer accepted for this post.
As much as I enjoy the blog posts, I would really like to see a bit more complicated examples, for now it feels a little bit too much “hello world” style samples.
This one is actually a perfect example so let’s expand a little bit.
First this could be achieved to a certain extend with vvvv45 (on the exception of value/string/color/transform types which have a different interface for creation), since there is already a connection handler, so overriding this functionality can allow to have this (more or less store the type in a config pin to set connection). Adding functionality to draw in patch from plugins (custom iobox and pin editor) and that would be pretty much set.
So now let’s try to go out of the hello world case, and go into some real world scenarios.
1/Structs and “binary” compatible types.
Let’s say we connect a float to a zip node, now we can’t connect a Vector2 to it, whereas it could be totally acceptable (Vector2 is just two floats packed together, and with bit of il magic conversion is basically cost free, no need to copy memory at all).
2/Classes
Now things become more interesting :)
Let’s say we have two interfaces iDummy1
and we have 2 classes cTest1 and cTest2 (both implementing iDummy1)
Now we connect something outputting cTest1 to the zip node.
Two scenarios are now possible:
3/Conversion
Let’s now say we use Color4 and Vector4 (from SharpDX).
In c# you can just do:
Vector4 v = new Vector4(some data here) Color4 c = v;
Since there’s an implicit operator under the hood.
So would this Zip node (as example) which has a Vector4 input connected also accept a Color4 next to it (otherwise we end up in same situation having converter nodes everywhere)?
hey vux!
thanks for your ideas on this!
Anyway we decided that is not a good idea to confront people with too much details. Why? Because we want everybody to be able to follow. These blog posts are intended as a glimpse on the big picture, not the potentially distracting details.
That said there may be some ways to improve the situation. But this should be discussed elsewhere.
quote:vux: 1/Structs and “binary” compatible types.
Let’s say we connect a float to a zip node, now we can’t connect a Vector2 to it, whereas it could be totally acceptable (Vector2 is just two floats packed together, and with bit of il magic conversion is basically cost free, no need to copy memory at all).
In vvvv45 these are already different nodes: they generate different output! So it feels natural that a zip in vvvv50 at least treats those cases differently. I guess we agree on that.
We now can discuss about
I guess a spread of (1, 2, 3) makes a bad spread of 2d vectors and implicit conversion should not occur. The other case that you have a spread of 2d vectors which should convert into a spread of values is of course thinkable. Let me just tell you that we have it on our radar and also already combine generics with some few implicit conversions.
2/Classes The type inference which is running in the background is taking care of subtype realtionships, yes.
It is maybe of importance to explain that a zip node is not fixed to a certain type once the first connection has been made. After every single change of the patch - like a new connection - the system will take a fresh unbiased look at the patch and figure out the types for the generic nodes.
That way it typically figures out the right type for you, which might be a super type of two classes. And in the rare cases where it doesn’t, you will be able to interfere and make type annotations or force a link that the system wouldn’t allow based on the currently infered types. After the forced link it will again look at the patch in a way that the new link is nothing special. It might then infere another type or might also give you a red link somewhere when the forced connection just doesn’t make any sense - to the system that is… ;)
3/Conversion As discussed before it is on our radar.
Thank you again for bearing with us!
i think our brains can handle more input.
and i really like what i see. can’t wait until node…
on the other hand: i just tried to remember the last “hello world” that shows how to implement a generic queue. and failed ;)
but you guys are still right: we are leaving out some details. feel invited to ask for more!
Well, I guess the point of these posts is to to review the current situation, give a simple example how things are changing and what the benefits are … without being able to play with it.
So, to me: Nailed it.