LabVIEW Idea Exchange

cancel
Showing results for 
Search instead for 
Did you mean: 
--thatguy

VI Scoped Type Def

Status: New

When creating a state machine it's often handy to use an enum that lists all your states.  

You then take that enum and make it a type def so that if/when you update the enum (to add or remove a state) throughout the states, all instances of the enum get updated.  

 

But the thing is, now this potentially simple state machine VI requires this secondary type def file.  No other VIs would need access to this type def so making it a seperate file just shouldn't be necessary.

 

Vi Scoped.jpgVi Scoped_2.jpg

 

14 Comments
AristosQueue (NI)
NI Employee (retired)

R&D speaking from technical perspective: Totally doable. In fact, this is basically what we did to create express VIs -- the subVI is saved inside the caller VI.

 

R&D workaround for today:

Put them both in the same library and make the typedef private. Now no one else can access it.

Save all three into an LLB. Now you have one file.

 

R&D philosophy (mine, personally, but I try hard to persuade my team):

I do not like your idea. I have a broader theory of how we should be adjusting G that I'd like to lay out for you and see what you think.

 

Let's take your situation. What happens if you decide to create a subVI out of one frame of your state machine? Suddenly you have a second VI that needs access to the same enum but no clear way to maintain the same exclusion that you had before.

 

Although we could implement your idea as requested, I don't like taking that kind of approach to G language design -- ever. Several proposed ideas have requested similar "file in file" features. The cojoining of the file structure on disk with the logical structure in memory creates many oddities that just don't exist in other languages. LabVIEW has a way to put things together in one file -- an LLB. I want to strengthen the LLB so that it can contain directory structure, the way a .zip file can, OR make it easier to just save and load things inside a .zip file directly. That removes forever the need for special types of things just to change their on-disk organization from many files to single file.

 

What remains after that is to just define the logical organziations, and the logical organizations with library owning both VI and typedef are clear and comprehensible to anyone approaching your project without them learning something special for different instances and without making every file a potential container.  Indeed, in this way, the organization is the same whether the enum is used by just one state machine VI or that VI and all of its subVIs. The trouble is the editor gestures required to implement this structure, but I think we can alleviate that difficulty by strengthening the editor, not by changing the language. If the editor guided developers more into creating a library/component/module/thingy (pick your favorite name for the concept) from the outset instead of creating a raw VI, then when you created that enum, it would be in the same component. Trivial to set the access scope to "private" as needed and trivial to add additional subVIs as they come along, without having to move things into a new form.

 

I am not alone in wanting to see LV move more into this vector. We have floated the idea in front of various customers, but I'm always curious to see how the idea strikes others.

AndyBrown
Member

I'm actually going to agree with the original idea from thatguy.  An editor's job is to make our job as developers easier, faster, and more successful.  There is the ease of editing and the ease of the management that comes with the created products.  That management most definitely includes source control.  LLBs not the best with source code control to say the least.

 

If we wrote things correctly the first time and project scope never changed there would be no need for this discussion, we wouldn't even need a typedef.  But things change and this concept is to simplify that case.  I do a lot of work with LVFPGA.  In some of our larger projects we may have 20+ separate state machines that do varied tasks.  When we create a state machine now we have to create and manage 2 files => the VI and the VI specific typedef for the enum that state machine that no other file is going to use.  I like the original suggestion because it keeps those together with less to manage.

 

I also don't see it as a file-in-file type of solution.  Yes typedefs can (and currently only) be stored to a separate file type called ctl, but that is LabVIEWs organization.  What you are actually storing in the VI is the information required to define that typedef.  If the R&D team decides it is easiest to implement it as a file-in-file solution that is just how you chose to implement it.  The arguement that this just doesn't exist in other languages in not correct.  When I write C/C++ code and I want to create a type definition, I'm not force to create a new file.  Of course I could put it in a header file and it could be accessed by other files.  However if I want to, I can simply add it to the C file I want to use it in.  Does that mean C supports file-in-file?

 

And if the functionality of my state-machine grows and I need to create sub-VIs that need access to this typedef?  Similar solution that already exists.  Right mouse click on the VI scoped typedef and click create type definition and the editor allows me the "promote" the VI scoped typedef to its own file that can me then accessed by multiple VIs.

 

In the end I'm open to whatever solution makes me more efficient as long as that efficiency is measured across all the actions that I need to do with the code I create, including source code control.

Systems Engineering - National Instruments
AristosQueue (NI)
NI Employee (retired)

Andy:

> LLBs not the best with source code control to say the least.

 

True. But we are talking about a situation where someone *wants* to put all the files into one file... that's the request that was made. So assume that you are a developer that wants a single file. What's the right answer?

 

> Right mouse click on the VI scoped typedef and click create type definition and

> the editor allows me the "promote" the VI scoped typedef to its own file that can

> me then accessed by multiple VIs

 

Nope. Doesn't work. You've just made the typedef available to ALL VIs. The goal is to go from a typedef that is accessible to ONLY ONE VI to a typedef that is accessible ONLY TWO VIs. Big difference.

 

> When I write C/C++ code and I want to create a type definition, I'm not force to create a new file.

 

Let's be very careful here when comparing C++ with G.

 

C++...

You put a typedef in a C++ file... that makes it available to *all* the functions in that file.

If you want to scope the typedef to just one function, you have to put it inside that function.

If you want to use the typedef in a finite set of functions, you have to create some sort of scope wrapper, generally a class or struct, and make the typedef private to that scope.

 

G...

LabVIEW's equivalent of function is VI. LabVIEW offers you the ability to save every VI as a separate file or as a single file (LLB). The method of getting all the functions in a single file is different, mostly because it would be hard to have a single panel/diagram canvas on which you defined multiple VIs (trust me -- I've tried for a couple years to build such a thing for various reasons... regardless of whether it is a good idea or not, it is not easy to achieve a usable thing). So in the *editor* you have different windows for the functions, but the behavior on disk can be identical to C++... all one file.

 

C++ ...

The typedef in x.cpp is not available in y.cpp. True. But that's a quirk of the C++ compiler -- they do not resolve names outside of the file level. You can, however, combine files. The most common is with a .h file, but it doesn't have to be a .h file. You can tell the C++ compiler "compile x.cpp and y.cpp by concatenating them together and then compiling." If a C++ developer wanted to, he/she *could* save every function to a separate file -- there are actually source code control advantages to this -- and then compile them all as one. If a user did this, he/she would need a smarter editor environment that concatentated those files together and/or made it easier to navigate between functions, and told the compiler "concatenate these files when compiling". (The editor could also do #include for .cpp files.)

I'm highlighting all this in order to stress the difference between the language and the editor.

 

G...

Because VIs are often their own files, having a language divide between files for symbol resolution makes no sense for G -- you'd never be able to call a subVI. So G treats all files as being in the same namespace, whereas C++ does not. If you create a typedef, it is available to all the VIs, the same as if you create a typedef in a C++ file it is available to all the functions in that .cpp file.

 

Ok... with all that background in mind... the C++ equivalent of the Idea is this:

void x() {

typedef enum { a, b, c} MyEnum;

...

}

 

The MyEnum type is scoped to the function. We could, as I said, add that. It's additional syntax support. In C++ the marginal cost of such syntax is minimal. I'm arguing that the marginal syntax cost is much higher in G -- you would need some other settings/dialog/panel thing where you listed the additional types that are defined within each VI.

 

But C++ has another way to define and scope types:

 

class X {

private:

typedef enum { a, b, c} MyEnum;

public:

void x() {

...

}

}

 

The marginal cost of creating X is high if you have to type it out, but with a refactor tool like Resharper, it is very small. And if you pay that marginal cost, it makes other types of common refactors (breaking a complex state machine into subroutines) much cheaper and creates less disruption in the code. And it avoids adding another piece of syntax to the languge.

 

If the editor takes another step and just always puts a class wrapper around all functions (essentially the direction taken by C# although they did it at the language level by ruling out the existence of loose functions), then this cost is always already paid and ceases to exist entirely. THAT's the direction I'd like to bend LV, only substitute "library" for "class" because there's no need for it to be a type definition. (And this assumes some other changes to "library" that are outside the scope of today, which is why I spoke earlier of the "library/component/thingy"!)

 

The cost of creating an embedded file editor in a graphical environment is quite high. You have to find a new place to trigger the nested editor, you have to represent it special, and you have to change your scripting model to account for different types of ownership [as LabVIEW did with "Industrial RT" in LV 2009 where we allowed VIs to define shared variables]. That is a major change to every system out there that is trying to parse and manipulate the model of the language -- and I'm talking about end user cost, not the cost to NI, which is also high, but which I try to ignore when evaluating the goodnes/badnes of Ideas on the Exchange.

 

All of which brings us back to the "where does this thing get saved?" question. The logical containment of the typedef and the physical containment of the typedef are, I hope I've convinced you, not required to be joined. Nothing about one compels the nature of the other. Given that, I'd like to see us move to a model of one singular way to combine functions and types into a single file (which the LLB was fully capable of doing before LV 8.0) and make that independent of our choices for how we control access scope. Making those fully independent gives maximum flexibility for porting code, for making changes without breaking source code control histories, and generally makes the language and editor better able to adjust to whatever needs a user has.

 

At least, that's my theory. 🙂

--thatguy
Member

I'm loving the discussion, but I think we might be reading into it more than I had envisioned.

 

I was hoping that this would be way of removing some of the monotony of type def file management when (in my eyes) it wasn’t necessary for this albeit small use case.

 

I understand what you're saying about the workaround as it exists today.  However I have 2 issues with it:

  1. In the LLB other files within the LLB would have access to my typedef that I only want one VI to use.  Private ctls are still accessible by other private VIs as well as any public ones.
  2. It's just not really practical as work arounds go (the amount of work I have to do to implement this is more than what I’m trying to unburden myself of).  

 

I really don’t know anything about G, so maybe it has to be a file-in- file scenario.  I really wasn't expecting that to be the case.  I wasn’t expecting to double click the “VI scoped type def” constant and have a CTL window pop-up or any other kind of editor pop-up.  I just want it to be a constant that is linked by type to other copies of that constant within the single VI only (not subvis).  If it’s an enum, I can just edit the items and all copies of the constant now have access to the new items.  If it’s a cluster and I drag a new U8 into it then all instances of that constant now get a new U8.

 

To me your C++ equivalent idea is what I was thinking:

 

void x() {
typedef enum { a, b, c} MyEnum;
...
}

 

Now within the scope of my function/vi, I can have multiple MyEnums with different values.  But if I modify the type (lets say add element d) any of my instances of MyEnum can be set to ‘d’.  I don’t want MyEnum accessible to any other functions/subvis.  Because that wouldn’t be within the scope of the VI (i.e. “VI scoped”).

 

Now If I right click this “VI scoped type def” constant and say “Make Type Def”, this should create a separate .ctr file and it should behave like any other type def in LabVIEW today.  I suppose the C equivalent would be something like this.

 

typedef enum { a, b, c} MyEnum;
 
void x() {   // this represents a single VI
MyEnum varForX = a;
...
}
 
void y() {   // this represents a different VI
MyEnum varForY = b;
...
}
 

 

 

 

  

 

AristosQueue (NI)
NI Employee (retired)

> In the LLB other files within the LLB would have access to my typedef that I only

> want one VI to use.  Private ctls are still accessible by other private VIs as well as any public ones.

 

Nope... that's what the .lvlib is for. That sets the access scope. The .lvlib is saved inside the LLB as well. I should have asked your fluency with G before assuming you knew about the .lvlib files. The .lvlib file is the logical equivalent (as far as name symbol resolution is concerned) of the C file. It defines a scope and marks some of those files as public -- the equivalent of making them available in a header file to things outside of the library.

 

> It's just not really practical as work arounds go

 

Well, it achieves the effect of isolation and single file distribution. It isn't less work to create, but it does create the functionality. That's why I presented it to you.

 

> I just want it to be a constant that is linked by type to other copies of that constant within the

> single VI only (not subvis).  If it’s an enum, I can just edit the items and all copies of the

> constant now have access to the new items.

 

That's what I was talking about in the paragraph that starts, "The cost of creating an embedded file editor..."

 

Forget the word "file." Any definition (of a type, of a function, of anything else) needs an editor in a graphical language. I make the assumption that you want the editor for an enum used locally to look somewhat like the editor for the enum used globally. If those end up looking radically different, something is wrong.

 

So to implement your request as stated, you need a place to go inside the editor for a VI to see all the types defined within the VI and then you need a way to actually edit those types. In my opinion, system that makes you have to go to one place to edit an enum if it is defined locally and to a totally different place to edit an enum defined globally is a bad system. We can avoid that dichotomy by separating three things: the definition of the enum, the scoping of the enum and the on-disk location of the enum.

 

> Now If I right click this “VI scoped type def” constant and say “Make Type Def”, this should create a

> separate .ctr file and it should behave like any other type def in LabVIEW today.  I suppose the C

> equivalent would be something like this.

 

And what I'm trying to design is something so that the "limited to 1" and the "limited to 2" look identical and changing from "limited to 1" doesn't turn into "unlimited." 🙂

 

Mads
Active Participant

The way I interpreted the idea when I first read it was that this could be handled a bit like Run-Time Shortcut menus; If you define a shortcut menu for a control the editor will ask you if you want to save it to a file, or save it with the control. (On a side note I would normally opt for the former, but unfortunately that has buggy behaviour as controls then tend to lose their menu if you build an application...). 

 

So in this case the enum editor would ask you if you want to save it as part of the VI. If you try to edit an instance of it later, it will open the definition that is saved as part of the VI, just like shortcut menus saved as part of a control will let you edit that "embedded" menu.

 

Now, one of the arguments against this idea is that "what if you later decide to make a sub-VI of one of the cases in the state machine". Now that is something the idea explicitly excludes already(!). It is a way to speed things up when working within one VI, with no need to share the typedef outside of that VI. Just like the run-time shortcut menu saved to a control is never really available for any other controls, *but it is still edited by the same editor as the one that can save the menu to a file to make it usable across multiple controls*.

 

Based on this, I think the idea is solvable without breaking with the convensions of today's LabVIEW GUI (although it might break with the underlying file formats, but that's an implementation issue...).

 

PS. I've never really liked the "save with control" option for shortcut menus, it makes it way too easy to lose the menu (replace the control with another one, even the same but with a different theme, and you lose the menu with no notice!). But that issue would not apply to a typedef "saved with" the VI.

AndyBrown
Member
Two snippets from earlier posts concern me:
LabVIEW has a way to put things together in one file -- an LLB. I want to strengthen the LLB so that it can contain directory structure, the way a .zip file can, OR make it easier to just save and load things inside a .zip file directly. That removes forever the need for special types of things just to change their on-disk organization from many files to single file.

 

 

> LLBs not the best with source code control to say the least.

 

True. But we are talking about a situation where someone *wants* to put all the files into one file... that's the request that was made. So assume that you are a developer that wants a single file. What's the right answer?

 

 

Hopefully R&D has source code compatibility near the top of the criteria list when evaluating each new feature of LabVIEW.  It is an essential way that we do business.  In fact I wish NI would put more of an emphasis on source code control compatibility but that is a topic for another thread.

Systems Engineering - National Instruments
johnsold
Knight of NI

For the specific case of a selector for the state of a state machine use a string rather than a typedef enum. The discussion of the relative merits of the two methods has beeen carried on extensively elsewhere and should not be repeated here.  The point I am making is that switching to strings completely solves the mutiple file issues - the fixed string values are coded into the VI.

 

AristosQueue (NI)
NI Employee (retired)

I was out on vacation last week. Back now.

 

AndyBrown wrote:

> Hopefully R&D has source code compatibility near the top of the criteria list

> when evaluating each new feature of LabVIEW. 

 

Yes. We do. We also have plenty of situations where SCC is not an issue or where users are conciously preferring the single file solution in spite of the SCC penalty. So, the question here is "when a single file is the desired solution, what is the behavior?" Arguments that multiple files is better don't apply. 🙂

 

I think you'll be pleased in about two-three years with some of the work being done on SCC and LV.

 

> For the specific case of a selector for the state of a state machine use a string rather than a typedef enum.

 

Yes. And it introduces other issues. As he says, the pros/cons are debated elsewhere. For myself, I'm on the side of "never ever use a string when an enum is an option." But I understand that some people like debugging typos have other opinions. 🙂

iZACHdx
Active Participant

It seems to me that the overall problem here is that LabVIEW does not have sufficient access scope control or file consolidation options across all types of files (.ctl, .lvlib, .lvclass, etc.). Being able to combine functions (VIs) into a single file is desirable in many scenarios, especially when you start talking about source control. We have all learned that having public functions allows us to provide helper methods underneath so that we have the ability to change the underlying implementation without the consumers of the public methods having to worry about those changes. This causes specific problems with source control when files need to be renamed (and possibly separated) in order to better describe functionality after refactoring or feature addition. Whenever this happens, LabVIEW is a source control nightmare. As the idea states, a potential mitigation strategy is to have the ability to combine items into a single file (just like in C++) so that the operations become more manageable in source control. As was noted, C++ neither requires nor excludes single files like LabVIEW tries to do all over the place. The potential solution was to use an llb, but by the sheer nature of the way the LabVIEW editor works with llbs, this functionality is prohibitively time consuming wheras the text-based counterpart is not. I don't see the functionality originally requested as such a stretch with LabVIEW in it's current form. If you open a lvlib file directly, LabVIEW opens a window that allows editing the relationships within the lvlib. There are multiple examples of this - the lvlib editor window, the llb manager window, the project window, etc. It is unfortunate that these items are not contained within a single file, but given these examples, I see no reason that we could not expand the behavior of these windows to also identify .ctls that are contained within a specific VI. If I launch a VI containing a ctl, show an associated "VI Component Editor" window (separate from the Front Panel and Block Diagram windows) where you display the ctl file as an item in a tree where the VI is the parent item. For the other windows, adapt the same strategy so that I can add "child" items under VIs and hence control the access scope. If it is under a VI, automatically mark it as private. Since the project window is basically the master of all the others in that it has the ability to show the relationships of just about all the LabVIEW file types, I should also be able to move my VI-owned ctrl outisde of the VI and "promote" it if I want to. For this operation, the ctl would then come out of the VI, be temporarily saved in the project, and the project should force me to save the ctl file as a separate one when I try to close (just like what happens when a new "Untitled" VI is created and exists in the project when it is closed).