Avoiding ArgumentException

Lets have an imaginary function:

void Dream(string theme, int rating) {
    if (theme == null) { throw new ArgumentNullException(theme, "Theme must not be null."); }
    if (rating < 0) { throw new ArgumentOutOfRangeException(theme, "Theme must not be null."); }
    if (!OtherCheck(theme, rating)) { throw new ArgumentException(theme, "Some other reason."); }
    ...
}

On first look it looks fine. As always, devil is in the details. Let’s see how constructors for these functions look like:

public ArgumentNullException      (string paramName, string message)
public ArgumentOutOfRangeException(string paramName, string message)
public ArgumentException          (string message, string paramName)

Notice small difference in last line? Yes, order of arguments is different. Once this code is written you will probably never notice it unless you have code analysis turned on (CA2208). Unit tests will still catch correct exception and 95% developers will probably just skip over it because it “looks right”.

Would this be a critical bug? Well, not really. All properly written exception handling code will still work. Worst thing that might happen is for user to see wrong exception text. Chances are that this will be one of bugs that sits for ages although it is trivial to fix.

It is pointless to discuss whether ArgumentException has a bug in parameter ordering. Even if it is a bug (and I personally think it is), it will never get fixed. Fixing it would mean that you automatically break code for someone else and I cannot imagine any sensible person approving of this. Best that you can do is to just forget this class exists. ArgumentOutOfRangeException fits most of use cases for it anyhow.

PS: Everybody would probably be happier if ArgumentException was an abstract class.

PPS: Don’t let me get started ranting about ArgumentNullException and why it was wrong to have three argument exceptions in framework.

Brother MFC-J435W Startup

Illustration

I was trying to scan quite a big stack of documents in Brother’s MFC-J435W multifunctional device and I was hitting some driver error after couple of pages. What made whole affair annoying wasn’t the error. It was the fact that scanner would continue pulling pages. That made it impossible to easily continue scanning of nonfailed batch.

Proper behavior is to stop pulling new pages in case of an error. No programmer (and let’s face it, firmware and driver programmers are ones deciding about this) would think to continue printing after paper jam. Why would they think that pulling paper after scan has failed is any different? If something fails, stop the feeder!

Since printer was on for a long time I figured that quick reboot would make it work properly. First I was asked some stupid question about losing all fax data even though I haven’t used fax functionality on it. If you are going to stop user action with question, first check whether question is even necessary!

And, guess what, feeder starts working upon startup and picks each and every one of your papers through. For what purpose is this? And don’t tell me it is to verify feeder. Of what possible use is information that feeder is not working during startup?

Whether feeder is functional or not matters only when user attempts to use it. At that time you can do quick self-test if you really must. However, you might as well actually use feeder and scan pages. If you retrieve data and move pages through, it works. Yep, you can do self-test and actual work at the same time.

I find current behavior very annoying because somebody had to write code in order to make product worse. If they were lazy and made no effort to write verification procedure and include it in startup, everything would be fine.

Writing code is not hard. Knowing when to stop is.

PS: While I use Brother’s device as an example, most other devices make the same unnecessary check.

Dealing With Namespaces in XmlWriter

XmlTextWriter comes in really handy when all you need is serial XML output. With simple commands you can create well formed and nicely indented document:

using (var xw = new XmlTextWriter(stream)) {
    xw.WriteStartDocument(true);
    xw.Formatting = Formatting.Indented;
	xw.WriteStartElement("abc:Group");
    xw.WriteAttributeString("xmlns:abc", "http://www.example.com/something/");
    xw.WriteStartElement("abc:Element");
    ...
}

However, XmlTextWriter has limited formatting capabilities. If you want LF instead of Windows-style CRLF you will need to use something else. For me that “something else” was XmlWellFormedWriter.

To get XmlWellFormedWriter you just ask XmlWriter to create one for you. Direct replacement code would look close to this:

var settings = new XmlWriterSettings() {
	Encoding = new UTF8Encoding(false),
	Indent = true,
	IndentChars = "    ",
	NewLineChars = "\n"
};
using (var xw = XmlWriter.Create(stream, settings)) {
    xw.WriteStartDocument(true);
	xw.WriteStartElement("abc:Group");
    xw.WriteAttributeString("xmlns:abc", "http://www.example.com/something/");
    xw.WriteStartElement("abc:Element");
    ...
}

And, lo and behold, this code causes ArgumentException (Invalid name character in 'abc:Group'. The ':' character, hexadecimal value 0x3A, cannot be included in a name.). With XmlWellFormedWriter there is no cheating and manually creating XML namespaces. You can still use them, but code will look a bit different:

using (var xw = XmlWriter.Create(stream, settings)) {
    xw.WriteStartDocument(true);
    xw.WriteStartElement("abc", "Group", "http://www.example.com/something/");
    xw.WriteStartElement("abc", "Element", null);
    ...
}

PS: Yes, there is no guarantee that XmlWriter.Create will give you XmlWellFormedWriter. However, it will surely give you something close enough for this code to work.

Taking Over Standard Output

As I was running Java process from .NET program, occassionaly I would notice that program would got stuck. Long story short, I traced my issue to following exception:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    ...
    at java.awt.AWTEventMulticaster.focusLost(AWTEventMulticaster.java:230)
    at java.awt.Component.processFocusEvent(Component.java:6397)
    ...
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)

This exception is not something that would crash application. If I ran Java program from command prompt, exception would be printed out and program would continue.

What ended up being problem was fact that I was reading standard output from my .NET application only upon application exit. If Java application started printing too much stuff before that point, it would fill up the buffer and wait for somebody to read that data. Since there was nobody reading that data, it would wait indifinetely.

There is really easy way around it. Trick is to consume data as soon as it arrives with help of BeginOutputReadLine and OutputDataReceived handler:

process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += process_DataReceived;

process.Start();
process.BeginOutputReadLine();

if (process.HasExited) {
    //do something with collected data
}
private static void process_DataReceived(object sender, DataReceivedEventArgs e) {
    //store data somewhere (e.g. global StringBuilder)
}

OS X Trash

Illustration

As a developer I find it useful to show hidden files. And every time I borrow my USB to someone with OS X I find two new hidden folders: .Trashes and .Spotlight-V100. While these folders are important for OS X functioning (equivalents of Recycle bin and File Indexer) they are very annoying to see on USB. Only if there was a way to these folders more hidden…

Well, you can always set system attribute. While Windows don’t allow you to manage it through interface, this attribute is nothing special. Once you go to Command prompt, commands are really easy (assuming G: drive):

G:
ATTRIB +s +h .Spotlight-V100
ATTRIB +s +h .Trashes

Yes, folders will still be there but far from an eye. :)

P.S.: Just deleting these folders will not really work. They just re-appear next time USB goes to visit OS X.

P.P.S.: This “fix” will not work if you uncheck Hide protected operating system files option.

P.P.P.S.: And shame you OS X for not setting this attribute yourself.