LabVIEW Development Best Practices Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Error Classters : Improving Error Handling and Logging in LabVIEW

I gave this presentation at the Bay Area LabVIEW User Group meeting on November 10, 2015 and thought it might also be interesting to a broader audience. You may find the original slide stack here.

Abstract

Error Clusters are one of the most frequently used LabVIEW features. Error Clusters did not evolve over the years, yet still provide adequate error handling support for smaller applications. However, developers working on larger projects with emphasis on reusable code need something more flexible and scalable these days.

Presentation goes over design of an Error Handling & Logging Library that uses Error Classes instead of Error Clusters - which allows adding custom error data and altering error handling/logging functionality without touching existing code.

Error Cluster wires are used to propagate both, native Error Cluster data and flattened Error Objects to Error Handling VIs without creating ripples throughout the code. 

Message 1 of 5
(6,418 Views)

Hi Dmitry, I want to say thank you, recently I have started to look at LVOOP and this presentation is a great point to see how to make a good LVOOP Design; I just have a question, what is the criteria or how works the "Is_Valid" method at ArT_Error_Interface class?

I will continue reviewing the presentation, your articles are very interesting I would like to attend group meetings but unfortunately it is impossible given my location.

Thanks for your attention.

0 Kudos
Message 2 of 5
(5,279 Views)

AYanez wrote:

I just have a question, what is the criteria or how works the "Is_Valid" method at ArT_Error_Interface class?

That’s a very good question …

Short answer:

ArT_Error_Interface class has a single private data item - Is Valid? (a boolean) and a public method Is_Valid, returning Is Valid? value to caller.

Long answer:

  1. Current LVOOP implementation does not support Class Constructors. Chances are future versions would not be adding constructor support either (would be nice to hear from NI R&D that the latter statement is incorrect). One can drop a Class Constant on a BD and get a ‘default’ Object value on the wire.
  2. However, simply allocating memory for an Object and setting its private data to default values  in most cases is not good enough. Constructors in C++, C#, Java, etc. allow setting specific private data values and executing code (like opening a file reference) to bring new Object to a ‘valid’ state before returning its reference to callers.
  3. Being deprived of a Constructor concept in G I am using Is Valid? to allow checking that an Object value on the wire came out of (or passed through) a ‘constructor’ method call, by setting Is Valid?  to TRUE as the last step of executing ‘constructor’ method. This is done by calling ArT_Error_Interface.Set_Valid (bool) protected method with a TRUE value.
  4. I find this to be a ‘practical’ (i.e. reasonably simple and not too leaky) way of getting around lack of Constructors in G. It is based on deliberately/religiously following ‘rules’:
    1. A Class Developer has to call Set_Valid() method inside each ‘constructor’
    2. A Child Class has to have at least one ‘constructor’ method
    3. Child Class methods have to check Is_Valid prior to executing their payload – similar to checking Error In input by any well-behaved VI.
  5. Above ‘rules’ have to be observed by developers. G Compiler does not enforce them, so instead of broken VIs I have to watch for runtime errors – which always takes more time and effort, especially in a team environment with looming deadlines …
0 Kudos
Message 3 of 5
(5,279 Views)

I realise this is an old post but I've been reading through the presentation to get ideas on building better error handling into my work, one thing I've not managed to puzzle out is this:

on the slide referencing the flattening and unflattening of ArT_Error objects you refer to generating internal errors if this conversion fails however the class performing this conversion is the ArT_Error_Interface class which on it's own has no capability of generating error objects - this is all done in the ArT_Host_Error (a child class) or the ArT class and it's children, could you shed any light on this or has your error strategy moved away from this methodology?

0 Kudos
Message 4 of 5
(4,119 Views)

 

Hi IFW,

 

There is a more recent presentation on the subject: SOLID Error Handling I gave at NIWeek in 2017. It is based on this one (2015), but has an improved structure, ~30% new/updated slides and shows a “No Error” case frame on the flatten/unflatten slide you’ve been asking about.

 

on the slide referencing the flattening and unflattening of ArT_Error objects you refer to generating internal errors if this conversion fails however the class performing this conversion is the ArT_Error_Interface class which on it's own has no capability of generating error objects - this is all done in the ArT_Host_Error (a child class) or the ArT class and it's children, could you shed any light on this or has your error strategy moved away from this methodology?

 

Well, a simple answer is: ArT_Error_Interface class has a protected method Set_Internal_Error that is not shown on slide #20 since Protected virtual folder on the screenshot is collapsed …

 

I did not cover this part in any of the “Error Handling” presentations since

  • It would add another 4-5 slides and spill over the usual 50 min presentation time slot threshold
  • It is a detail that might confuse most people and divert attention from my main talking points

But since you’ve asked here is the Set_Internal_Error BD:

 

image.png

 

It creates and returns an “internal error” object. And, by design, this happens to be an instance of ArT_Host_Error class … Which brings us to the actual question:

 

How can a Parent class (ArT_Error_Interface) create an instance of one of its Child classes (ArT_Host_Error), without introducing a static dependency on such Child class?

 

Quite simple 😊 :

  1. Set_Internal_Error is a protected static dispatch method. It calls a dynamic dispatch method Set_Internal_Error_Payload (icon has magenta background)
  2. Set_Internal_Error_Payload method is a must override method for all ArT_Error_Interface child classes. It creates an error object of a type passed to its dynamic dispatch input (top left)
  3. Set_Internal_Error wires an output of Internal_Error_Class method to Set_Internal_Error_Payload method dynamic dispatch input.
  4. Internal_Error_Class is a LV2-style global (a singleton) implementing an ArT_Error_Interface class variable. This variable keeps the actual type of internal error objects.
  5. ArT_Error_Interface class variable is initialized inside a call to ArTLib_Init method with an error object type passed from the caller (ArT_Host_Error by default). ArTLib_Init must be the first call to ArTLib reuse library. To ensure this - I make the call in Application Assembler class “constructor”
  6. ArTLib_Init method is a top-level method of ArTLib library, which contains both, ArT_Error_Interface class and ArT_Host Error class. ArTLib “knows” about both classes. So, setting ArT_Error_Interface class variable to ArT_Host_Error class instance does not result in a circular dependency 😊

 Hope this answers your question …

 

 

0 Kudos
Message 5 of 5
(4,105 Views)