Delegates OfType

I would like to make a semi-generic delegate that can look at my custom datatype that has a Name<String>, Tags<Hash<String>> and Values <Spread<T>> of numbers around within the algorithm.

Say I had a spread of spread of my datatype, and in the first slice the values are floats, the second doubles, and the third integers.

They could be concatenated as datatype objects and OfType could be used to split them apart further down.

But does a delegate require the explicit subdatatype or can it work with these objects generically?

without understanding what you are trying to do, yes a delegate can have a generic parameter.

in any case, after OfType the type is clear… so you wouldn’t need that anyway.

can you give more information about what you are trying to do? since everything is typed, you wouldn’t be able to store those together in into a typed collection, you would have to use object or any other super type for the type that is variable.

the objects are in fact used generically. what you seem to want is actually polymorphism.
So even if you create generic classes, the moment you connect some actual type anywhere, the whole thing will be typed accordingly. So you will have to decide about the actual type during patching, otherwise you will not be able to use any of it.

Spoken more broadly, Generics is a concept in .net, that will be resolved during compile time, dynamic Polymorphism on the other hand is resolved during runtime, and usually needs inheritance (of interfaces and base classes, etc), which vl has no grasp of right now.

edit: there are Adaptive nodes, but there is very little documentation about them. they might be a vl way to do what you want

Everything that you said above is very well explained. But this part is wrong. VL in fact has a very detailed knowledge of the relations of types. You just can’t edit that relationship yet (but this is coming).

For example: VL knows that a spread is a sequence and everything is an object. So if you somewhere need a sequence you can connect a spread.

Actually VL takes all that knowledge about types out-of the imported .NET assemblies. VL even knows if a type is value type or a reference type (struct or class) or if some type parameters of a generic type are co- or contra-variant. In fact: everything that you can state about a .NET type holds true for the VL counterpart. The only additional information that VL has is if a type is immutable or not.

The original posters question, being our guest, was asking about

  • if he can create instances of A < C > and B < C >. Yes you can (because of generics a.k.a. parametric polymorphism).
  • If you now want to cons (or concat) them into one spread: Yes you can (because of subtyping. (you might need to force one link by holding the SPACEBAR when closing the connection)).

So this way you could hold many objects in one spread and further down use an OfType [Sequence] (hidden in the Devlib) to split them up again (depending on the type that you need). Now this is just an example of how you can combine generics and subtyping. You can also use them in combination with delegates.

Actually we support all three kinds of polymorphism:

  • “Ad hoc polymorphism: when a function denotes different and potentially heterogeneous implementations depending on a limited range of individually specified types and combinations. Ad hoc polymorphism is supported in many languages using function overloading.” In VL it is supported via adpative nodes.
  • “Parametric polymorphism: when code is written without mention of any specific type and thus can be used transparently with any number of new types. In the object-oriented programming community, this is often known as generics or generic programming. In the functional programming community, this is often shortened to polymorphism.” Often in VL you don’t care about a type and your patch stays generic. you get types like this: A < B >
  • “Subtyping (also called subtype polymorphism or inclusion polymorphism): when a name denotes instances of many different classes related by some common superclass.[3] In the object-oriented programming community, this is often referred to as simply Inheritance.” VL has it. But until now you can’t built your own type relationships. Check alphas for a sneak preview at interface implementations. When creating a record or a class you also already built a relationship that says that an instance of your type is an object, no matter what.

But back to the question regarding delegates.
In fact delegates are very good suited for dealing with sub- and supertypes as their inputs are contra-variant and their outputs are co-variant.
What does it mean? It says that whenever you have to provide a function that needs to return an object you obviously can also return your special type. And if you get granted that your input is of some type T you still can treat it just as an object… Co- and contra-variance basically are just terms to model your intuition and lay it out in type theory. The question being if B is A and Z is Y is B < Z > a A < Y >? Anyways delegates have it.

In other words it helps you not shooting yourself in the foot by being a too rigid type system. Staticly typed languages like c# and VL always will have their issues of allowing too few, just because they can’t know/prove beforehand that the user is right in the particular case. So sometimes you can’t assign a simple vector to the other (even when they come with the same amount of bytes encoding the same x,y,z coordinates with floats) and sometimes you can’t assign B < Z > to A < Y > even though you know that B is an A and Z is a Y and you only read from it. The system will only allow this when the type parameter of A is set to be covariant, which in .NET can only be set on interfaces (in certain cases) and (actually) on delegates, but not on classes, which is a pity because you sometimes just know more than the underlying IL type system does. We share these restrictions with C#.

For the resilient ones: there is a “nice” counter example when covariance should NOT be allowed (though it is). This also is a reason why the array is not that prominent in VL. Covariance and Contravariance in C#, Part Two: Array Covariance | Microsoft Learn.

And this topic would spin outof control if you now take the example of “integers, floats and doubles are objects”. But as you did… For the even more resilient ones. Actually this is a unfortunate example as another specialty kicks in. Integers, floats an doubles indeed are treated as objects in most cases, but sometimes not. A spread of float is not implicitly convertible to a spread of object, even though a float is an object. Why? Because there is some optimization for when dealing with basic value types like floats. They don’t get boxed if not necessary. The whole spread then is in one blob of basic floats glued to each other. Those are not freely floating actual objects living on the heap / your RAM with runtime type information attached to them. They are just packed into one big blob of raw data and only when you access them again later on with e.g. GetSlice they behave like little separate objects again.

If possible give us a patch so that we know what exactly is the issue. Maybe the answer can be more to the point then.

3 Likes

@gregsn
great comment, thanks for the verbosity.

// todo: insert meme of a wise wizard reading stories from a cs tome and a whitty subline about “knowing” and “grasping”

Wow, that was a good post. I got the impression that vl made it possible to apply some amount of polymorphism. My idea was to create a type with some static subtypes (like string tags), and some generic subtypes like those seen in math nodes.
I’ll probably have to boil it down a bit in a dummy patch since the main one has a lot of distractions from this issue. Thanks @gregsn.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.