Showing posts with label Debugging. Show all posts
Showing posts with label Debugging. Show all posts

Thursday, December 6, 2012

Apparent binding problems with NotSupportedException in PresentationFramework

I ran into this problem twice over the last couple weeks. Perhaps if I write an article, it'll help my future self (and just perhaps someone else) not spend so much time on it...

I put together a simple WPF form with a ListView. The ListLiew's View contained a GridView with columns bound to a POCO's properties. This was all done in XAML. In the constructor, I created an ObservableCollection to contain the objects and set it to the ListView's ItemsSource property. An event fired when interesting things happened. The event handler created the POCO object, set its properties and added it to the collection.

Everything should have worked.

However, when items were added to the collection, the debug window reported:
A first chance exception of type 'System.NotSupportedException' occurred in PresentationFramework.dll
Over the years, I've found data binding to be a challenge to get working. Part of the problem is it's mostly silent when it fails. So, data simply doesn't show up where it's expected with no indication as to why. Because of this, I assumed this is where the problem lay and spent significant time trying to figure out what was happening.

After quite a while I realized the event handler was called from a non-UI thread. I changed the line that added objects to the collection from:
ListViewDetails.Add(detailData);
to:
Dispatcher.Invoke((Action)(() =>
    ListViewDetails.Add(detailData)));
and everything worked properly. A simple solution once I realized what was wrong.

It'd be really nice if the debug window would output the exception message and not just the type. This would have told me immediately what was wrong and I wouldn't have spent so much time going down a dead-end road.

Friday, December 3, 2010

DRY vs KISS

Two developers are playing poker. The chips are all on the table and it's time to show their hands. One throws down the DRY hand. The other throws down KISS. Which hand wins? Who gets to take the pot home?

There are many guidelines in software development. These are two prominent ones: DRY and KISS. For those who haven't heard of them, DRY stands for Don't Repeat Yourself and KISS stands for Keep It Simple, Stupid.

The underlying principle behind DRY is that there should be one authoritative source for any artifact in a piece of software. This can take different forms depending on the context. One example might be a constant literal. If a literal, for example a numeric value or a string value, exists more than one place in a program, it's a bad thing. The duplication should be removed and replaced with a named constant. The constant becomes the authoritative source for the value. This also has the side effect of making the software more readable if a good name is chosen because the meaning can be conveyed, not just the value. Another example is duplicated code. If lines of code are copied and pasted, there becomes more than one authority for the code's behavior. Instead, those duplicated lines should be put in a function that can be called from the various places the behavior is needed.

The KISS principle is based on the idea that complexity makes code that's hard to understand, maintain and debug. Code that is hard to understand will have more bugs in it to begin with and take longer to get working properly. It will also be harder for the person who has to maintain it to make changes and hence will increase the cost of ownership over the lifetime of the product.

On the surface, I think most developers will agree that both these principles are good. However, I think there is disagreement upon which one trumps the other.

An argument could be made that removing duplication increases complexity. In the examples for DRY above, adding a function or constant declaration adds indirection. As you read the code, the value is not immediately obvious and the behavior is not readily apparent. You have to go somewhere or use some feature in the IDE to find the value or determine what the routine does. In addition to readability, as you write, you have extra work to make a separate function. It is much faster to simply copy what you need and paste it somewhere else.

I understand these arguments. I know first hand the temptation to grab a section of code and paste it somewhere else. I know the pain of slowing down and having to think deeply about how to not make the duplicate copy of the code. Given all that...

DRY trumps KISS every time.

When I look at the long term maintainability, having one place where behavior or values or anything else is defined is always the better thing. I've experienced first hand maintenance of code with high levels of duplication. I have made changes in one place without knowing about the duplication and not also fixing the same code elsewhere. I have seen others do the same thing. The testing and validation in these scenarios can get very painful. When maintaining software and making changes, dealing with a single authority is much more accurate and faster, even with increased indirection.

In addition to long term maintainability when behavior should be changed, not repeating yourself reduces the chance of copy and paste errors. More times than I care to count, I've found bugs where a block of code was copied and minor changes made throughout it. Missing even one thing that should be changed will result in insidious bugs setting up residence in your application. Many times these won't be caught until much later in the product's life-cycle, increasing the cost of fixing them.

Just today I violated this principle... even after thinking "do I really want to do this?"... even with the draft of this article fresh in my mind... and I introduced a bug that took me a minute to figure out. I had these two lines:
const string name1 = "value one" ;
var value1 = !computeValueForName(name1);
That I duplicated and changed to this:
const string name2 = "value two" ;
var value2 = !computeValueForName(name1);
See the error? When I did, I promptly refactored this to:
var names = new [] { "value1" , "value2" };
var values = from n in names select !computeValueForName(n);
So, yeah, when I see violations of DRY I have almost a compulsive need to fix it. How about you?

Monday, January 2, 2006

Why are some object properties zero in the watch window?

This has to do with how the watch window works and the way properties are implemented.

First, the watch window simply provides a view of an area of memory. You can tell it to view the memory in different ways. Because it knows some things about that memory, it can do a limited amount of interpretation: view the contents of character pointers, view the contents of records and so forth.

Second, a bit of explanation as to how properties work. When a component is developed, the component writer declares a property with:
property NameOfProp: TypeOfProp read PropReader write PropWriter;
where:
NameOfProp is the name of the property accessed in the Object Inspector and in code.
TypeOfProp is the type of the property, e.g. Integer, String, TStrings.
PropReader is either a variable of type TypeOfProp or a function with a return type of TypeOfProp.
PropWriter is either a variable of type TypeOfProp or a procedure with a parameter of type TypeOfProp.
Notice the two options for readers and writers. They can be either a variable or a method. Some properties directly access a variable whereas others are the result of code executing. Those properties that fall into the first class can be evaluated without side effects in the watch window, since it looks at memory. Those properties that fall into the second class cannot be evaluated in the watch window without potentially causing side effects.

Because of the possible side effect issue, early versions of Delphi simply did not display the property value. Due to requests to allow this, the debugger was made to optionally show properties which use readers. To see these types of properties, right click on the watch item and select properties. Then check the option to allow function results.

If working in earlier versions of Delphi, where this option is not available, there are several ways to get around the problem:
  1. Create a temporary variable immediately prior to where you want to view a property and assign the property value to the variable. Then put the watch on the temporary variable. You may need to go to the Options page and turn optimizations off.
  2. Put a ShowMessage call in the code where you would normally set the breakpoint and create a message that displays the desired property.
  3. Put a Memo component on the visible form and add a line that displays the desired property where you would normally set the breakpoint.
  4. Set a breakpoint. Right click on the breakpoint in the breakpoint list window and select properties. Show the advanced options. Uncheck Break. In the evaluation section, put in the property name. Now, every time that breakpoint is hit, rather than stopping the debugger, it will write a line to the event log.

Why do I get an AV when accessing an array?

The most common AV problem with arrays is accessing an element beyond the proper range. Make sure range checking is on, at least for debugging.

Why do I get an AV when accessing a pointer (including a PChar) or object?

In the following discussion, the term pointer is used to generically refer to variables of explicit pointer types, PChars and objects. This was written from a Delphi perspective, but the techniques are generally applicable.

Remember, declaring a variable of any pointer type only allocates 4 bytes for the pointer. The pointer does not refer to anything. Before it can be referenced, it must be assigned a value. Depending on context, the pointer's value may come from any number of sources, including: memory allocation routines, a return value from a function, a constant, a variable or, in the case of objects, the constructor method. Not performing this step is a sure way to AV. Always check the return value of memory allocation functions to verify that the pointer was assigned a valid value.

Another way to AV sometimes is to access a pointer whose contents have already been freed. Depending on many factors, sometimes this will work and sometimes it will AV. This is especially easy to do if the variable's scope is greater than the current procedure. One good practice, particularly when variables have an object or global scope is to set their value to nil immediately after freeing it. No, this is not automatically done. If nothing else, following this practice will eliminate the "sometimes" nature of the problem.

Assuming the pointer has been assigned a valid value and it has not been freed, the final item to check is the value of the pointer when the AV occurs. If it is the same value, then the memory is being referenced (possibly through a typecast) incorrectly. Accessing a freed object can cause this too. If it is a different value, then the next task is to track down why. Probably something else in the program is accessing memory incorrectly, not causing an AV but corrupting this pointer. On cause of this is writing to array elements outside the bounds of the array. Turn on the range checking option to help determine if this is happening.

There are several ways to find this. 1) Do a very careful code review until the offending code is found. 2) Establish breakpoints between the time the value is correct and when it is bad with a watch on the pointer that's being changed. 3) Remove code between creation and known corruption until the problem goes away. 4) Use a tool that detects memory overwrites.