Consistency issues

During the preparations for the upcoming video tutorial series I collected a few issues regarding consistency. So here is a thread to collect them all.

Adaptive vs. Generic
I am a bit unclear which of these terms is now being used for what. The Gray Book is also delivering results for both terms. I started wondering about it when I came across this error message - I would have expected it to say “Unable to resolve generic node”

Pin Groups
When exposing pin groups (like Math nodes or a Switch), only the first input gets a label.

grafik

Typo
When hovering the camera icon of a frame.

Pow
Why is there a generic/adaptive node, when it is only accepting floats?

Skia Renderer
Should have Control Box activated by default and have a title input pin, to align with the window style of Stride windows.

Stride Cameras
IMO the default camera for a SceneTexture and the normal Camera (without Orbit) should look exactly like the default OrbitCamera on a SceneWindow

Stride Windows
They don’t save their positions.

Circle / Rectangle
Maybe their defaults and label namings should be the same like their equivalents in Skia? Also the circle datatype does not have an anchor input.

Output bang
Please.

Animation Nodes
Can we please also have generic Oscillator and Damper nodes in the standard node set, instead of the single value, 2D and 3D versions?

grafik

3D Text
Simple 3D text rendering in the standard node set would be awesome… maybe the 3D text models of @bjoern could go into vanilla Stride?

Spread Nodes
The naming of RemoveSliceAt is not in line with the other nodes. Also InsertSlice should have the index pin on the very right.

Mouse Wheel
Has to be used differently in Stride and Skia. At least the naming should be fixed here.

Angles
Everything about angles in 3D feels contra everything else in VL (LFO direction, angles in 2D). One day I will create a separate forum post about it.

2 Likes

Generic

Generic is a term that was introduced by others. It refers to the existence of type parameters. Because of those it’s also known as parametric polymorphism. VL is a .Net language and thus shares a lot in this regard with C# and F#. So we also stuck the established term “generic”.

Parametric Polymorphism / Generics is mainly about type safety inside your code/patch, not so much about actually doing something. It’s just convenient to know that in a collection are only items of a certain type. Less guessing and less cast operations as if everything in a collection would be of type object (as it was in the early days of .Net).

There is more that could be said about the Generics in .Net (like restricting a type parameter with constraints), but the main point will not change: Parametric Polymorphism / Generics is about abstracting over the final data type, but it’s not abstracting over what to do.

Subtype polymorphism
The idea of having an abstract data type (like an interface) + many different implementations of that abstract datatype does allow to abtract over “what to do”. And when used together with generics you can trick yourself into believing that this is a feature of Generics, but actually it’s just the subtyping / virtual call idea that does the trick. It’s unrelated to the Generics feature.

Adaptive

Adaptive is a term we came up with, which is abstracting over what to do per type.
And we wanted to abstract over what to do in a very performant way without paying one tick at runtime. We didn’t want to go via a virtual call at runtime, because we wanted to induce the per-type implementations pretty much everwhere (+, *, …). So subtyping wasn’t an option.

And as this was quite some years before the C# team started to tackle the topic, we were free to pick a term for that. We were inspired by Haskells type classes, picked certain ideas, rejected others and finally came up with the idea that you want to able to abstract over “what to do” on a per-node-basis.

The adaptive system in short:

  • an adaptive node serves as a definition, which outlines the signature of the node
  • implementations for those adaptive nodes get found automatically
  • a generic patch can make use of adaptive nodes, postponing the decision on which implementations to pick. Such patch now not only has type parameters, but also node parameters. However we managed to hide this complexity from the user.
  • The implementations (+ for Float32, * for Float32, …) get fed to the generic Damper when using the Damper with that particular type. The nodes get picked and somehow get wired up at compile-time with the algorithm inside the generic Damper patch resulting in a very performant patch that works for the particular data type.

In short: Adaptive refers for what to do per type. Generic refers to the existence of a type parameter.

Another example on how to use the terms:

  • Lerp [Adaptive] defines the idea of lerping. It uses one type parameter. Thus it can also be refered to something “generic”. However we like to just call it the adaptive node.
  • All the implementations are typically not generic anymore. As they focus on different concrete types.
  • However, in this specific example, you can imagine to offer an implementation for all types that don’t come with a handcrafted solution: A generic Lerp operation, that makes use of adaptive +, * (Scale) and -, like so:
    grafik
    Let’s call this a generic implementation of an adaptive node.
5 Likes

Thanks for the detailed answer! Maybe it should be included it in the Gray Book in the Looking at Things section? Also there is a blank page about Generics in the Reference.

1 Like

@chk thanks for all those. we’ll be editing your original post and add a ✅ on things that have been tackled.

2 Likes

Thank you, especially for the bang output!

I noticed that on nodes with pin groups no input gets a label now (tested with +, - and Switch). The MultiFlipFlop does though.

Coming back to the adaptive vs. generic discussion now… so as a fellow patcher, not diving too much into VL OOP world etc. I assume that this person should only be confronted with the term adaptive, until its necessary to clarify more how things are working in the background, right?

If yes - is it also safe to say, that pads and input pins are adaptive by nature?

Coming back to the adaptive vs. generic discussion now… so as a fellow patcher, not diving too much into VL OOP world etc. I assume that this person should only be confronted with the term generic, until its necessary to clarify more how things are working in the background, right?

I am not sure why you want to avoid the term “adaptive”. It captures the idea that a node “adapts its behavior” much better than the term “generic”. So it’s really two different things I would distinguish when teaching.
However, I have to agree, nodes like the generic Damper, which make use of adaptive nodes somehow themselves adapt their behavior, just by using adaptive nodes. So, yes this one I still called “generic”. So there is a slight issue right there. Maybe all nodes that are adaptive or use adaptive nodes should somehow be visualized in a certain way or be called “nodes with adaptive behavior”?

So, ok, I am no teacher, maybe you can get around using the term adaptive, but for me I feel like I would have learned a lot when from the beginning ppl would have told me that generic is not about doing things differently per type. It’s not doing anything, it’s about postponing the decision which type is used and avoiding the usage of object in order to be type-safe and specific in the user patch.

I guess you don’t want to explain how to create generic patches. So maybe you can even avoid both terms. If a pin doesn’t have a type yet, it’s type is still “open”. We see a type variable “T”. As soon as you connect something concrete - where the type of data flowing at runtime is known before running the program - then this particular pin now also is of that type. We know that only certain data is coming from upstream, flowing into that pin, so this pin now also is of that type (or rather the type of data flowing through it).

So. You can use terms like “still open”, “concrete”, “known type”, “unknown type”. You might be able to postpone using the term “generic” until the point where you create generic patches. You then also talk about working with “type variables” aka “type parameters” that are the heart of “generics”.

If yes - is it also safe to say, that pads and input pins are adaptive by nature?

No pins and pads don’t do anything. So they are not adaptive. Their type is not known when you create them, but as soon as you annotate a type or connect something the system figures out a type. I wouldn’t really talk about generics or adaptive here. I find this confusing. We are still in the process of building a patch. Type variables popping up and disappearing all the time in the process of building a patch is not something I would call generic or adaptive when in the end it’s about building up patches that aren’t generic when they are finished.

I hope I don’t make it more confusing for you than necessary. I was just trying to only introduce terms when necessary, and when I introduce them, then also explain them properly and use them - e.g. build a generic patch when explaining generics. Build an adaptive node when explaining adaptive… or just add an implementation to an already existing adaptive node…

Hope that helps

1 Like

@gregsn Sorry I meant they should only be confronted with the term adaptive! Totally misleading towards your extensive answer - maybe we revert this discussion from the start?

And we should define our expectations. I would say the terms are well defined and it’s about understanding what they stand for. The question is how to teach it. Do we agree on this?

Yes, that why I was asking in the first place, because I wanted to understand them myself. I did not find yet explanations in the Gray Book about these terms (only design guidelines), and they are being used in error messages.

So - I think I would avoid using the term Generics when teaching to beginners (as it could be a whole different universe), talk about the concept of adaptive nodes and that the type of pads, inputs and outputs is simply unknown by default when not connected or manually set. Does that sound good?

Sounds great! The fact that certain things are missing in the gray book was probably back then due to too much respect of the task of explaining the particular missing topics. But I feel better equipped now - also after valuable discussions like this - and will to try fill some gaps…

Thanks for your insistence - making this whole thing more approachable!

2 Likes

To my experience talking about Generics, Adaptives, and terms as such is actually not that difficult.
First, in a calssroom it should pop up as a “productive” question; As in, if we want move on, we must know what those terms mean; which is often unlikely in a beginner class.

However, i think, explaining these terms should not be really in the context of one node alone; it is often (if not always) about explaining what is happing in a group of connected nodes; like in an operation or in a patch.

1 Like

After the discussion above, I agree to this when it comes to the concept of Generics. But not for adaptive nodes. A single node can be adaptive (Switch, +, Filter), a patch can be generic. The concept of adaptive nodes is directly connected to the principle of data types and I think no beginner class can move on before getting this. It is also super important when it comes to debugging red nodes and links using the tooltips.

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