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. 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. https://blogs.msdn.microsoft.com/ericlippert/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance/.
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.