Jump to content

How would you redesign the LV error cluster?


Recommended Posts

I went mucking around inside General Error Handler.vi and am aghast at what I found. It seems like error definition is split between error code lookup (defined in error files) and extra information jammed into the description string using bracketed tags (like call chain and suggestions for handling the error). Why we're forced to handle specific error codes anyway is beyond me. There isn't any way of knowing which codes will be thrown by a given function, and many of the first 100 codes are reused in mysterious ways all over NI's APIs. (e.g. error 7 coming from a property node inside the VI that establishes an SMTP connection)

 

Surely there's a better way to organize and transfer information about something having gone wrong? I realize that LV will always be dependent on returned error values from each function instead of cooler systems like exceptions, but there still seems to be a lot of opportunity for improving HOW those errors are encoded, decoded, and handled.

 

Has anybody spent time thinking about this? Should I just put the rug back down and pretend I never looked under it?

Link to post
Share on other sites

Two dusty threads from 2007 and 2009. I'll just lay this rug back down and walk away. 

Often times I find the most useful things tucked away in old threads that I missed.  Here is one semi-recently I saw showing one of the most useful express VIs I've seen.

 

https://lavag.org/topic/10836-is-this-the-most-useful-express-vi-ever/

 

It is an express VI that can perform specific actions, based on the error it gets.  Things like retry 4 times if you get error code X, or run a VI if you get code Y.  This can help in making of a central error handler for things like logging.  I'm not sure how this could improve the core of error handling but I like it a lot.

 

Certainly error in general could be done better in LabVIEW, but I have a hard time describing the way that they could be improved that wouldn't either break things, or have corner cases that are hard to handle.  Often times knowing what errors a function can return is part of the problem.  If I had a list of what errors I could expect from a given function (and the functions it calls) I would probably be easier to look at the potential errors and come up with custom actions for each, a selection.

 

Another issue I've heard others talk about, is that there isn't a standard way of formatting that source string.  It is flexible, but it isn't standard.  Adding more complicated data to the error wire, like the array of string for the call chain might help.

 

But honestly most of these things have been discussed in other threads (like the ones mentioned).  Looking at the crelf presentation there is the "Wouldn't it be cool if we could" slides which are pretty good list.

  • Like 1
Link to post
Share on other sites

Often times I find the most useful things tucked away in old threads that I missed.  Here is one semi-recently I saw showing one of the most useful express VIs I've seen.

 

https://lavag.org/topic/10836-is-this-the-most-useful-express-vi-ever/

 

woah. Never seen that one. That's all kinds of useful. I don't like that is an express VI (hidden design time config) but I can work around that with a polymorphic VI, Going to have a play and see how it pans out.

 

Error handling has never been adequately addressed. Everyone goes for a tactical solution to what is essentially a strategic problem. I've always thought it would be nice if we could capture the Automatic Error Handling of a VI with an event or two. Then we wouldn't need to error guess problems so much by knowing where to put an error dialogue or error cluster check on a wire. Every VI would effectively have an On Error event with zero coding and the VI hierarchy could enable bubbling..

Link to post
Share on other sites

woah. Never seen that one. That's all kinds of useful. I don't like that is an express VI (hidden design time config) but I can work around that with a polymorphic VI, Going to have a play and see how it pans out.

I KNOW RIGHT!  Where have you been all my life, and how did I not find it earlier?  Anyway I haven't taken to using it in real applications yet.  I understand the point you make about hiding design config, and that is true, but the amount of usefulness and features per pixel on the BD make it a winner in my mind.

 

The Error Event is a neat concept that I could see using.  With so much talk about error stuff in the past years I'm a little surprised something major hasn't come out yet, I mean other than the couple unofficial things mentioned earlier.  I suspect NI is working on major overhauls to error behind the scenes (as AQ has sorta mentioned) just will it ever make it into our hands, or its the R part of R&D?

Link to post
Share on other sites

I suspect NI is working on major overhauls to error behind the scenes (as AQ has sorta mentioned) just will it ever make it into our hands, or its the R part of R&D?

 

Don't be too sure. Not much has changed in the language since, probably, the event structure-maybe xcontrols etc. It's one of the reasons I still program in 2009. Recent updates have had some very low hanging fruit when it comes to new features. It's almost as if they are afraid to touch the core.

 

When AQ talks about things nowadays it is generally a user framework of some description. Serialisation, for example, should have been handled by the flatten primitives but AQ came up with the Character Lineator instead (can you serialise objects properly now?). If an error system does come forth, it is likely to be specific to the Actor Framework or some other marotte du jour and require obnoxious compromises when used outside of the framework. That is the fate of all tactical solutions IMO.

 

They can already catch errors at the VI boundary with the Automatic Error Handling and exposing an in-built event in the event structure would be extremely useful. If it could also broadcast and bubble through the hierarchy you would also have a strategy similar to other languages and you wouldn't have to code anything except filtering in the handler and how you react to the events. Additionally it would be completely backwards compatible.

Link to post
Share on other sites

Don't be too sure. Not much has changed in the language since, probably, the event structure-maybe xcontrols etc.

You can't be entirely serious.  Maybe you haven't used these new features but they are awesome and going back you realize what you are missing.  

 

But seriously since the event structure?  That was LabVIEW 6.x right? (maybe 7.0?).  Project explorer.  What about classes, and libraries in general?  VI Server has had major upgrades since then.  VI Scripting that is a ginormous feature.  XNodes (unofficial but still major new feature).  Static VI references, along with the other asyncronous tools (run dynamically).  Application builder API.  Icon editor API.  System Configuration API.  Was there even dynamic user events in 2009?  I know they didn't have priorities.  Event Inspection Window, Bookmark manager.  Events being lossy.  Conditional/concatenating tunnels.  QuickDrop and other QD related features.  Do they have make type def from a block diagram constant?  Native JSON and XML.  DVRs (couldn't remember the version they came).  Native FTP, HTTP, SMTP Email, WebDAV, Bluetooth.  Not sure when Network Streams, and network shared variables, and Web Services came about.  Libraries with licensing restrictions.  The list literally goes on and on.  I might not use all those features daily, but there have been major improvements over the years.  And 2015 has some really compelling features for me personally.

 

But this is true, that no one at NI is saying errors will be improved in the near future.

  • Like 1
Link to post
Share on other sites

You can't be entirely serious.  Maybe you haven't used these new features but they are awesome and going back you realize what you are missing.  

 

Project explorer.  What about classes, and libraries in general?  VI Server has had major upgrades since then.  VI Scripting that is a ginormous feature.  XNodes (unofficial but still major new feature).  Static VI references, along with the other asyncronous tools (run dynamically).  Application builder API.  Icon editor API.  System Configuration API.  Was there even dynamic user events in 2009?  I know they didn't have priorities.  Event Inspection Window, Bookmark manager.  Events being lossy.  Conditional/concatenating tunnels.  QuickDrop and other QD related features.  Do they have make type def from a block diagram constant?  Native JSON and XML.  DVRs (couldn't remember the version they came).  Native FTP, HTTP, SMTP Email, WebDAV, Bluetooth.  Not sure when Network Streams, and network shared variables, and Web Services came about.  Libraries with licensing restrictions.  The list literally goes on and on.  I might not use all those features daily, but there have been major improvements over the years.  And 2015 has some really compelling features for me personally.

 

But this is true, that no one at NI is saying errors will be improved in the near future.

 

APIs, quickdrop and most of the other stuff isn't language.Sure. There's a few good toolkits, and primitives that have been added over time but even the language aspects that you've listed; e.g classes and DVRs and most of the others are between 5 and 10 years old (2005 for classes?) and pretty much all the other stuff with a very small number of  exceptions is in 2009 (QD, DVR, bluetooth, XML, Web services, Shared variables and yes, dynamic user events) and those that aren't I have solutions for. Conditional tunnels and network streams I might give you but none of what you are talking about is project busting technology.

 

Where's the inheritable FP controls? Where's the event driven VISA? Where's the inheritance that actually inherits methods and properties without recreating them? (I'm looking at you x-controls :P ). Where's the thousands of events to choose from in the event structure (maximise, minimise, open etc).. Why are there still bugs from 8.x? :D

 

Perhaps I'm being harsh. It's probably because I've looked every year at upgrading on a wave of enthusiasm. Then I weigh project risk vs features I might actually use it seems there are too few pros once the eye candy is taken out. Upgrade to LV2013 because of a JSON primitive? Almost did but it was a real pain to use than the open source one, so back to 2009. :wub:

  • Like 1
Link to post
Share on other sites

Where's the inheritable FP controls? Where's the event driven VISA? Where's the inheritance that actually inherits methods and properties without recreating them? (I'm looking at you x-controls :P ). Where's the thousands of events to choose from in the event structure (maximise, minimise, open etc).. Why are there still bugs from 8.x? :D

Okay a few good points there.  But let me ask this having honestly not known the answer, what new language features does C++ today have, that it didn't have last year, or 5 years ago?  If we talk about other more abstracted languages like Visual Basic we may get a different answer of which I also don't know the answer.  But just like LabVIEW they might be features that I won't fully appreciate unless I'm an expert with it.

 

Where's the thousands of events to choose from in the event structure (maximise, minimise, open etc).. Why are there still bugs from 8.x?

Correct me if I'm wrong but isn't this panel resize or pane resize?  And what good is the minimize?  Is it to stop updating the UI with new things when the window isn't being seen?  I'm guessing (with no real information) that this might actually happen anyway.  If this isn't the case then you should make an idea exchange post on this.  

 

Maybe LabVIEW is just so awesome it doesn't need major new features...eh maybe it's just you get used to what you have.  There are major features I could want, and see as language changers.  Certainly XNodes is a bit of that, I mean code that writes code as you interact with it, is a big deal.

 

Also my argument sorta started with trying to say how 2014 is better than 7.x because you listed events and XControls as changes in the language.  With that in mind look back at my list.  Now I need to look back at the 2015 beta and look for language changes.  I think there are features that will make you go 'wow' for sure but I can't remember any specifics on language changing.

 

BTW so sorry OP for doing this, I had forgotten the original topic, beer for you if you're going to NI Week.  :beer_mug: And two for you Shaun if you're going  :beer_mug:  :beer_mug:

Link to post
Share on other sites

Back on-topic: (No worries, hooovahh!)

 

I used and studied RyanK's CEH back when he published it. I found two major (IMO) problems with the approach:

  1. CEH handles errors asynchronously
    Based on my experience as an app developer, I believe error handling should be done synchronously. ("Handling" involves clearing an error and responding to it gracefully, even if that response is to ignore the error or translate it into other information like a "timed out" Boolean parameter.) If the error can't be handled sync, then it can be reported to a higher-level entity async for logging, display to an operator, or handling at a broader scope than the "thread" (LV loop) that threw the error and failed to handle it locally. Broad-scope handling actions in my RT apps often look like resetting the application's operating mode or forcing output signals to fail over to a safe state until the operator reviews and clears the critical error.

    I think ShaunR's suggestion of an "Error Event" has the same flaw: events are asynchornous in LV. What I think we need is an "Error Callback" so it's handled synchronously with context-sensitive dispatch of which handler to use. On that note...
     
  2. CEH is insensitive to context
    An error code has no context whatsoever. Error 7 ("File not found") might be safely ignored in some processes, but it might represent a critical failure in others. It gets thrown by native APIs that have nothing to do with file access, too, so you might not think to deifne a general-purpose handler for code 7 that addresses an unexpected API or app process. Errors should be handled as close to where they're thrown as possible, so the handling code can be written in the same design context as the code that generated the error.
Edited by Stobber
Link to post
Share on other sites

 

Back on-topic: (No worries, hooovahh!)

 

I used and studied RyanK's CEH back when he published it. I found two major (IMO) problems with the approach:

  1. CEH handles errors asynchronously

    Based on my experience as an app developer, I believe error handling should be done synchronously. ("Handling" involves clearing an error and responding to it gracefully, even if that response is to ignore the error or translate it into other information like a "timed out" Boolean parameter.) If the error can't be handled sync, then it can be reported to a higher-level entity async for logging, display to an operator, or handling at a broader scope than the "thread" (LV loop) that threw the error and failed to handle it locally. Broad-scope handling actions in my RT apps often look like resetting the application's operating mode or forcing output signals to fail over to a safe state until the operator reviews and clears the critical error.

    I think ShaunR's suggestion of an "Error Event" has the same flaw: events are asynchornous in LV. What I think we need is an "Error Callback" so it's handled synchronously with context-sensitive dispatch of which handler to use. On that note...

     

  2. CEH is insensitive to context

    An error code has no context whatsoever. Error 7 ("File not found") might be safely ignored in some processes, but it might represent a critical failure in others. It gets thrown by native APIs that have nothing to do with file access, too, so you might not think to deifne a general-purpose handler for code 7 that addresses an unexpected API or app process. Errors should be handled as close to where they're thrown as possible, so the handling code can be written in the same design context as the code that generated the error.

 

I don't disagree in general, but the express VI settings help provide for some of this. For example a given instance of the express VI might be configured to clear error 7, while another instance is not. Still doesn't provide source, though, which I agree is unfortunate. The devzone paper also describes using it super-locally to handle things like retries. And of course in some cases there is nothing to do locally. Its the middle range of issues where the handling is more complicated than just retry but not bad enough to just shutdown where there are challenges using the SEH.

 

We ended up doing something I think is similar to what you described, but of limited usefulness since its within our framework. Code modules synchronously return error codes to the caller and provide a method for categorizing them (no error, trivial, critical, unknown) and then the calling code has a set of actions it can take, and the mapping from (module, classification)->(action) is all configuration based. The actions are things like shutdown, go to save state, log, or reinitialize module. The caller is also responsible for distributing error codes to any other module that cares, so for example control code can be informed if scan engine had an error.

Link to post
Share on other sites

Frankly, I don't think error handling code will ever be effectively abstracted to a framework or set of reuse components. The appropriate handler for each error in a finished app is too dependent on the data structures and running logic of that particular piece of code. The best I think we could do for one another is to create tutorials with example code for people to learn from.

 

It's the structure of the error cluster and the information it carries that stands to be improved. Standardizing what goes into the string would be nice, even if it's just a set of established tags or formatting that differentiates one section of data from another, so each team can embed whatever custom information they like without stomping on anyone else's. Defining a zero-allocation structure for memory-critical RT code would be really nice, too. I should finally to look through cref's slides from years ago...

Link to post
Share on other sites

I don't know if there is a good way to have a zero allocation structure because it would have to be something that would be used universally (or else you'll have some using a standard error and some with an rt error) but whose RT-ness could be turned off in favor of a more verbose output.

 

One option to aid in this could be to make wrapper functions which have conditional code so when it runs on RT and the flag "RTVerbose" is not set to true, all of the dynamic allocations are removed. Except really you don't want this at all. What you really want is the less verbose version when on RT, and RTVerbose!=true, and the code is inside of a timed loop or above normal priority VI, and currently I don't think there is a language construct to do this (although I've asked for it :( )

 

Back to the general point about how it would look, I personally tend to think it should be a int+a dictionary (ie variant lookup in our case). I suppose a class could do it too (base class is int-only, then verbose class has source, call chain, etc, then user classes have custom data) but then there is a ton of code needed to generically access that information. All that has basically already been written for variants with the various probes, xml flatteners, etc.

 

 

Some of the other threads mention multiple errors. I think the simple dictionary would also do a better job of handling multiple errors than something like an error stack. Just thinking out loud here, but it seems to me that for any given chunk of code there should only be one error--every other problem can be traced back to that. I think multiple errors come in handy in two situations:

1-Combining the error from parallel chunks

2-Init, where you want to know everything that went wrong so you can fix it.

(2) would really make more sense as a custom field, which is what I do now -- Tag not found, Append: Tag1, Tag2, Tag3 would be converted into MissingTags=["Tag1", "Tag2",...]

(1) would make more sense as a named error field -- ie rather than Error[0], Error[1], Error[2] you want to see FileLoggerError=7, FTPError="Thank you for using NI FTP", etc.

 

 

The only thing I'm really certain of is that I wish the boolean were gone forever :)

Link to post
Share on other sites

You know one thing to think about is no matter what type of changes are made to error redesign, there is going to be more overhead than the current implementation.  Having multiple errors in a history, or timestamp of when the error occurred, or having custom dialogs with images and text, variant attributes for meta data, or using classes to override features.  All of this is going to have more VIs to load into memory, and more processing power to perform actions.  And someone, somewhere is going to complain that they don't want all of that extra fluff when the 3 element cluster (or just the code) is all they need.  Especially on RT targets where performance is always trying to be optimized.  I think the benefit (if done right) will out weigh the cost, but maybe this is one reason why NI is apprehensive to change.

Link to post
Share on other sites

You know one thing to think about is no matter what type of changes are made to error redesign, there is going to be more overhead than the current implementation.  Having multiple errors in a history, or timestamp of when the error occurred, or having custom dialogs with images and text, variant attributes for meta data, or using classes to override features.  All of this is going to have more VIs to load into memory, and more processing power to perform actions.  And someone, somewhere is going to complain that they don't want all of that extra fluff when the 3 element cluster (or just the code) is all they need.  Especially on RT targets where performance is always trying to be optimized.  I think the benefit (if done right) will out weigh the cost, but maybe this is one reason why NI is apprehensive to change.

 

That's why I like the idea of an event on automatic error handling. You can still use the cluster, in fact, you would use the cluster to handle local error and recovery as per usual,if required. There may be a tiny overhead only when a listener is attached but since people nowadays seem to be throwing messages around like confetti; I don;t think they can complain about a couple of really useful ones when something goes wrong..

Edited by ShaunR
Link to post
Share on other sites

You know one thing to think about is no matter what type of changes are made to error redesign, there is going to be more overhead than the current implementation....All of this is going to have more VIs to load into memory, and more processing power to perform actions.  And someone, somewhere is going to complain that they don't want all of that extra fluff when the 3 element cluster (or just the code) is all they need.

 

Who says a redesign has to bolt on fancy new features that hog memory or demand extra CPU cycles? A totally functional redesign might just look like removing the Boolean from the cluster and defining a standard set of tags for segmenting metadata in the string!

 

 

There may be a tiny overhead only when a listener is attached but since people nowadays seem to be throwing messages around like confetti; I don;t think they can complain about a couple of really useful ones when something goes wrong..

 

Are you still clinging to the same computer you had when that dusty old copy of LV 7.1 was released? :P  Memory and CPU have gotten so big/fast that architecting applications with async message-based processes basically comes for free these days.

Edited by Stobber
Link to post
Share on other sites

Are you still clinging to the same computer you had when that dusty old copy of LV 7.1 was released? :P  Memory and CPU have gotten so big/fast that architecting applications with async message-based processes basically comes for free these days.

 

Debugging them isn't free though :P

  • Like 1
Link to post
Share on other sites

Which is why error handling should be synchronous!!! ;)

Synchronous to what? Do you mean adheres to the LabVIEw dataflow that you broke with your free asynchronous messaging? :D

Edited by ShaunR
Link to post
Share on other sites

I'm not the one who decided to marry a dataflow language to an asynchronous execution model. Even a single BD with a couple of structures can break the damned paradigm.

Link to post
Share on other sites

I'm not the one who decided to marry a dataflow language to an asynchronous execution model. Even a single BD with a couple of structures can break the damned paradigm.

I imagined you writing that with exactly the look you have in your avatar ...lol.

  • Like 2
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.