LabVIEW Idea Exchange

cancel
Showing results for 
Search instead for 
Did you mean: 
Tomi_Maila

Type Parameters and Parametrized Generic Types

Status: New

The goal of this idea is to make it easy for the LabVIEW ecosystem to create reusable libraries for LabVIEW that would be type independent. Let's think for a second dictionaries, also called as key-value stores. Dictionaries are data structures that allow storing and retrieving values with a specific key. To create a generic reusable strongly typed dictionary is currently impossible with the LabVIEW type system. One can create a dictionary that is type specific but then it's not reusable. Or one can create a reusable dictionary but then it's not strongly typed. Type Parameters and Parametrized Generic Types as explained in this idea would allow creating strongly typed dictionaries that are widely reusable across applications. Specifically type parameters and parametrized generic types would allow LabVIEW ecosystem to develop highly reusable strongly typed components to solve various common programming problems. This would allow National Instruments to put more focus on the core of the language as the LabVIEW ecosystem could solve much wider range of problems that preivously have required National Instruments to contribute.

 

Add a new control type Type Parameter to LabVIEW that augments the current Control, Type Def and Strict Type Def control types. The Type Parameter type would act like a regular Type Def control with one special and important distinction. You could wire anything to an input terminal expecting a specific Type Parameter type and the downstream type would adapt at compile time to the type wired to the type parameter input.

Type Parameter Definition

 

In a single VI type parameter could be used in multiple places but all instances of the type parameter would adapt to the same type.

 

Type Parameters

 

When a VI that uses Type Parameters in the front panel is used on a block diagram, the template VI is replaced by the compiler by a type specific instance that has adapted the type parameters to the type wired to the Type Parameter input. Notice below how in our VI the control and the indicator were of type Type Parameter with a default type of DBL and the instance got adapted to type U32 that was wired to the input.

Calling a VI with Type Parameter Inputs

The same type parameter could be used on multiple inputs of a VI.

Multiple Inputs of The Same Type Parameter

And all of the type parameters would adapt to the same type when the VI is being used.

Calling a VI with Multiple Type Parameter Inputs of the Same Type

Note that in the above example we chose the element of the array to be a specific type specified by a type parameter. However the arrays themselves could as well have been specified by a type parameter.

 

So far we have focused on VI boundary where type parameters adapt the whole VI to specific type or types if multiple different type parameters are being used in the connector pane of the VI. Type parameters can also be used in composite types (e.g. arrays, clusters, classes) and the downstream composite types would adapt to what is wired to the type parameter input.

 

Type Parameters with a Cluster

Note that x and y as instances of the same type parameter have to be of the same or compatible type.

Type Error With Type Parameters

 

Type parameters can also be used in class private data to create parameterized custom types. This is where type parameters become extremely powerful. Let's assume that we have a class 3D Vector.lvclass that has three instances of a "Data Element.ctl" Type Parameters. The default type of the Data Element is set to be DBL. The cluster private data has three instances of the Data Element, one for each of X, Y and Z.

Type Parameters in Class Private DAta

 

Now we could create a Create 3D Vector method VI for this class that allows us to construct type parametrized instance of the class type.

Creating a Type Parametrized Object

Now calling this Create 3D Vector.vi with string as the inputs for type parametrized inputs X, Y and Z will create an instance of class 3D Vector with compile time type 3D Vector[String].

Calling a VI that Creates a Type Parametrized Object

 

And this is where we now start seeing the superpowers of type parameters and parametrized types as well as generic type parameterized VIs that go along with them. Now we have a capability of creating custom VIs and custom types that both can adapt to different parameter types at usage time.

 

Let's get back to the question of dictionaries. We could easily construct a dictionary that allows the key type to be parametrized with one parameter and the value type to be parametrized with another parameter. For example we could use the dictionary with I32s as keys and Strings as values. Or we could use it with Strings as keys and File Paths as values. Constructor for such custom type would be trivial to create.

Type Parametrized Create Method for a Dictionary

 

Once we have constructed the dictionary we would naturally like to use it. We could now use method VIs of the Dictionary class to add and fetch elements from the dictionary. As an example Get Element By Key would look something like this in it's simplest form.

 

Get Element From Dictionary

 

 

Note that Dictionary In is type parametrized with two different type parameters Key Type and Value Type. In the class library there is a Type Parameter control Key Type.ctl and Value Type.ctl. Now type parameter Key Type.ctl is used both inside the private data of the class and on the fron panel as the Key input, the type of these two must be the same. The same is true for the Value Type element of private data and the Value indicator that both derive from Value Type.ctl type parameter. The has function is any function that can convert any LabVIEW types to some strings that we can use as keys for the variant attribute node. We are using variant attributes as the store implementation is this basic example.

 

Calling the Dictionary with integer as the type parameter and string as the value would look something like this.

 

Calling a Type Parametrized Dictionary

 

As you can see the 0 and empty string will define propagate as type parameter types for Key Type and Value Type in the dictionary wire. Now Add Element.vi would have to adapt to these elections for Key Type and Value Type the moment the Dictionary wire is connected. The Key input immediately change to type INT32 and the Value input to type String. Similar would be true if the wires would be connected in reverse order. Connecting University of Texas string to the Value input of Add Element and connecting number 1 of type INT32 to the Key input of the Add Element would immediately adapt the Dictionary in and Dictionary out inputs to be of type Dictionary[Key Type = INT32, Value Type = String]. A type error would occur if Dictionary in would be of different type.

 

Type Parametrized Generic Types are an extremely powerful concept to incldue in a language and this idea describes a feasible way to implement them in a visual dataflow model of LabVIEW. This is and has been for maybe ten years my absolute #1 feature I have wanted to see in LabVIEW. I think the time is right for me to officially make this request. Ideally Type Parameters can be bounded but that's a topic for a whole other idea post.

--
Tomi Maila
4 Comments
Tomi_Maila
Active Participant

From the technical implementation perspective Type Parameter controls are similar to type defenitions but they behave differently on the block diagram. When dropped on a block diagram or front panel or as part of a composite control or constant, type parameters behave exactly like type defs. However the type of the value with type parameter would be something along the lines of following:

 

Parametrized Type(Type Parameter = [Type Parameter Name], Type = [Default Type], Set = False)

 

The type would consist of three pieces of information:

  1. Type Parameter would be the name of the Type Parameter control that this type is tied to
  2. Type would be the actual edit time type of the typed construct (e.g. constant, control, wire, ...)
  3. Set would indicate if the type has been set to some specific type or if the type is unset. For constants and controls this would always be False. 

Parametrized Types would have a scope of a single VI. Within the scope of a VI a specific Type Parameter could be only be set to a single specific actual (non-parametrized) type.

 

Setting a type for a type parameter could occur on the block diagram of the VI. There are several ways it could be set:

  •  Type parameter is used inside a cluster is being set when a value is written to the cluster element using a bundle node or in-place element structure
  • Type parameter is used inside an array array element or subset is being set
  • Type parameter is used inside a class private data and a value of the class private data is being set by a bundle node or in-place element structure
  • Type parameter is used on an indicator and the value of that indicator is written with a non-parametrized type

If type parameter is set on the block diagram in one of the above ways (the list is probably not exhaustive) then the type parameter gets statically linked to a specific type within the scope of that VI. However type parameter does not get set if the type wired to parametrized type in one of the above ways is the same parametrized type. In this case the type parameter remains unset in the scope of the VI. If the type wired to the parametrized type is another but different parametrized type then these two types get linked and can only be associated with the same type in the scope of that VI.

 

When a VI using a parametrized type is being used on a block diagram of another VI, LabVIEW replaces the VI with an instance VI much the same way as express VIs are replaced with an instance VI. A new instance is created for each occurance of the VI as a subVI on a block diagram of any other VI. From now on we will call thse type parametrized subVI instances or just subVI instances.

 

If a subVI instance may use parametrized types on it's connector pane either directly or as part of a compound type (array, cluster, class). These parametrized types would have a scope of the VI that has the subVI on its block diagram. If the parametrized type gets set on the block diagram by for example wiring a non-parametrized value to an subVI input with a parametrized type then the instance subVI will adapt to this type. The original VI from with the subVI instance originated remains untouched and can be considered as the template for the subVI instance. But for the subVI instance LabVIEW would compile a VI that matches the type wired to the input with a parametrized type. For unset parametrized types LabVIEW would use the default type for generating the subVI instance.

 

If there are nested VI hierarchies where subVI and its subVI both use parametrized types on their connector panes then the whole nested hierarchy of subVI instances would be generated to match a specific type when the type gets set to a concrete type at the outermost layer of such hierarchy.

 

To help debugging the developer can double click a subVI instance and the instance VI would be opened instead of the original VI. The instance VI opened would show the subVI as it is when the parametrized types are all tied to the concrete types as set by the calling VI. Pressing Ctrl + M would allow opening the original VI with the parametrized types untied. 

--
Tomi Maila
TimVargo
Member

Your suggestion is extremely well thought through Tomi, from both perspectives of implementation by the developer, and from its under-the-hood compiler details of operation.  Am I correct in thinking that this sort of boils down to providing a mechanism for weakly-typed variables in an otherwise strongly-typed language?  Although your description never uses the word "polymorphic", I can see describing this idea as polymorphism on steroids!  Smiley Happy  I also think that this could replace many situations that today would require creating a polymorphic VI, but without having to code all of its several (and mostly redundant) member VIs; resulting in smaller total code size, and fewer coding errors. A much better way of providing true function overloading.

 

In any case, your idea is something that could only be realized from within the LabVIEW core itself, and would represent a MAJOR new capability for developers.

 

I do have one suggestion: the developer needs to be able to recognize when a Type Parameter is being used, as opposed to a regular TypeDef.  This could be accomplished perhaps by using a unique color for the triangle in the terminal's upper corner that denotes a TypeDef, or by some symbol other than a triangle.


~Tim
Tomi_Maila
Active Participant

I think I'd change one thing to my original proposal related to how constants of type parametrized types or constants of compound types that have inner type parametrized types behave. I would change the behavior so that once a type parameter gets bound within a VI scope, then all constants, controls and indicators would also become bound and adapt to that same type right away.Let's assume for example that I have a cluster "Point" with elements x and y connected to a type parameter "Coordinate Type". Now let's assume the user would use a constant of type Point and then use a bundle node to set x to a DBL number. This would bind the x and y both in the constant to the new type DBL immediately. Once user disconnects the DBL number from the bundle node, the x and y elements in the constant would become unbound again.

 

Second there should be a right click menu option for constants, controls and indicators to allow the user to "bound" the type parameter to a concrete type. Continuing our previous example let's again assume that I have a cluster "Point" with elements x and y connected to a type parameter Coordinate Type. Let's assume there is a constant of cluster type "Point" where the type parameter "Coordinate Type" is not yet bound to a concrete type. Now user could right click on either x or y, select "Bind to type" from the right click menu and choose a concrete type from the controls (or new constants) palette. This action would now bound the type parameter in the scope of the VI to the type the user selected from the right click menu. The bound type parametrized constant would have some visual indication that it is bound. User could further right click a bound type parametrized type and select "Unbind from type". This would unbound the type parametrized constant from the type and make it available to be bound elsewhere to a different type.

 

Third once user changes the value of type parametrized value in a constant or control, that type parametrized value becomes bound to then current concrete type. In our point example let's assume that the Coordinate Type is bound to a specific type, say DBL. Now user changes the value of x in the constant Point cluster on the block diagram to be something else than the default value for type DBL (0). This would bind x and the Coordinate Type to DBL. This would have no effect because x was already bound somewhere else. However if the other bound is now removed, the Coordinate Type would remain to be bound to DBL because of the non-default-value of x in the constant. To remove the binding the user could either set the constant x to its default value or select the right click option "Unbind from type". 

 

This gets quite technical but I just wanted to log the proposed implementation details in a hope of NI implementing this feature for a version of LabVIEW released soon 🙂

--
Tomi Maila
Tomi_Maila
Active Participant

TimVargo, the idea introduced a specific way to implement generics in LabVIEW. Generics are also called parametric polymorphism in type theory, which means that they are types or functions that have multiple forms over a given parameter. I didn't want to use a LabVIEW term polymorphic as it could have been misleading.

--
Tomi Maila