NotImplementedException vs. NotSupportedException

I’ve been wondering for a long time what the difference is between these two exceptions. They both seem to mean the exact same thing.

The docs for NotImplementedException say:

The exception that is thrown when a requested method or operation is not implemented.

Whereas the docs for NotSupportedException say:

The exception that is thrown when an invoked method is not supported, or when there is an attempt to read, seek, or write to a stream that does not support the invoked functionality.

Um, don’t “not implemented” and “not supported” kinda go together? Are they saying that there are things that aren’t supported, but that they went ahead and implemented anyway? And things that aren’t implemented, but are supported? Hey, you missed a couple of cases. Where’s the NeitherSupportedNorImplementedException? And obviously we need an exception we can throw if something is both supported and implemented. Gotta cover all the possible combinations. (Permutations? I always get those confused.)

So when I come upon a situation where I need to throw one of these, I’ve pretty much always just picked one at random, because I have no clue which one is “right”. I mean, it’s not like the docs explain it or anything. The notes about Stream are interesting, but there’s still nothing much to differentiate the two exceptions — going just from the descriptions, there’s no reason the streams couldn’t be throwing NotImplementedException instead.

Well, I recently talked my boss into ordering a copy of the .NET Framework Standard Library Annotated Reference, volume 1, by Brad Abrams. The book just arrived today, and I happened to think of this age-old question. So I looked up those two classes.

Here’s the description for NotImplementedException:

A number of the types and constructs, specified elsewhere in this Standard, are not required of CLI implementations that conform only to the Kernel Profile. For example, the floating-point feature set consists of the floating-point data types System.Single and System.Double. If support for these is omitted from an implementation, any attempt to reference a signature that includes the floating-point data types results in an exception of type System.NotImplementedException.

And for NotSupportedException:

System.NotSupportedException is thrown when it is never possible for the object to perform the requested operation. A typical scenario is when a base class declares a method that derived classes are required to implement, and the method is invoked on the base class. When a method throws System.NotSupportedException this usually indicates that the derived classes must provide an implementation of the method, and callers must invoke the method on the derived class. For scenarios where it is sometimes possible for the object to perform the requested operation, and the object state determines whether the operation can be performed, see System.InvalidOperationException.

Whoa. Way better descriptions. And they point out that there is a difference. NotImplementedException means that the base runtime doesn’t implement something (i.e., you wouldn’t expect to see it from Microsoft’s CLR, unless they do an embedded, more-stripped-down-than-the-Compact-Framework version). It’s thrown by the base runtime — not me. NotSupportedException is the one that means “this class doesn’t do that”. When I need one of these exceptions (e.g., if I’m writing a class descendant that doesn’t support a particular method), NotSupportedException is clearly the one I want.

I think this book is going to see a lot of use around here!

Determine whether user is logged in as admin (Whidbey)

I’m not actually coding in Whidbey yet, so this is mostly a bookmark so I can find it again later.

Brad Abrams posted code a while back showing how to use some of Whidbey’s new classes to determine whether the currently-logged-in user is an administrator. Looks like their wrappers for the security stuff might actually make the security APIs usable.

My bad

Oops.

Okay, Diamondback isn’t actually out yet. The Oslo launch event was a “build hype and take orders” event like the Delphi 8 launch at BorCon 2003. I should’ve noticed the “Pre-Order” on the order page.

Word is that it’ll be out in November sometime.

Diamondback released! (uh…)

Wow. Hallvard said Borland was planning a Delphi launch event for yesterday, but I figured it’d be like the Delphi 8 “launch” at last year’s BorCon — i.e., much hype and maybe the announcement of an actual release date.

Nope. Delphi 2005 is now available.

I knew it was coming fairly soon, since (a) the Diamondback preview turns into a pumpkin sometime around the 22nd of this month, (b) Allen said just after BorCon that the team was going into pure bug-fix mode and “nearing the end”, and (c) Danny said the version after Diamondback (“Whidbeyish” as I’ve been calling it) would come out in the Whidbey timeframe (Whidbey being “summerish” 2005), and they’ve gotta leave themselves time to actually code the thing. So obviously Diamondback was going to be soon. But, man… it’s out! And we’ve got four copies already on the way! Woohoo!

(I sure hope they fixed that little compiler bug…)

Correction: As David pointed out in my comments, Delphi 2005 has not been released. My bad.

Excluding directories

I’m coding the directory exclusions feature of my Delphi-code-searching tool, and I wanted to get you guys’ feedback.

You’ll give the app a directory to start in, and it will automatically recurse through all subdirectories, except the ones you tell it to skip. I want this because we have some utilities in our code base that were for conversion to the current program version, so we no longer compile those tools as part of our current builds; so I don’t worry about them when I refactor, and I don’t want to search in them. One of my readers commented on wanting to exclude third-party code from searches. I think this “skip this directory” feature will be pretty useful.

I wrote the directory-recursing code this morning. The simple case (no exclusions) would basically look like this:

ArrayList arrayList = new ArrayList();
arrayList.Add(_parameters.RootDirectory);
for (int i = 0; i < arrayList.Count; ++i)
{
    DirectoryInfo thisDirectory = (DirectoryInfo) arrayList[i];
    arrayList.AddRange(thisDirectory.GetDirectories());
}

But if I want exclusions, the question arises: Where do I put that logic? There are two places that would make sense:

  • Instead of the AddRange, I could do a foreach through the GetDirectories() results, and only add directories to the ArrayList if they aren’t on the exclude list. This would mean that I would never recurse into the subdirectories of anything on the exclude list. (This is what I decided to have the code do for now.)
  • The other option would be to go from the starting directory and scan its entire directory tree, and then make a second pass to remove the excluded directories from the ArrayList. The difference here is that, if I exclude directory C:\Code\Foo, the ArrayList will still contain Foo’s subdirectories.

The difference is in whether “exclude directory X” means “ignore X and all its subdirectories”, or if it instead means “don’t process any of the files in X, but do include its subdirectories (unless I also exclude them specifically)”.

Which option do you think would be more useful? The second option gives you more fine-grained control; you can include or exclude individual directories at your discretion. But if what you really want is “exclude this entire directory tree”, then the first option would be better — unchecking all those directories one by one could be really cumbersome.

What do you think? Would you only use the first option? Only the second? Or would you really need the ability to choose, per exclusion, whether you’re skipping that directory tree or just the files in that directory?

Searching through Delphi code

I’m writing a tool that does a sort of “find in files” on Delphi source files. Yes, I know, there are zillions of such tools out there, but this one has a few extra features:

  • Ability to restrict your search only to comments, to compiler directives, to string literals, or to code. As far as I know, there are no other tools out there that have this feature.
  • Drag and drop from the search results into the Delphi editor, to open the files for editing
  • Full support for PCRE (Perl-compatible regular expressions), including positive and negative lookahead and lookbehind
  • Compound searches, e.g., “Find all files that do contain this string, but do not contain this string”
  • Lets you search within multiline comments and multiline strings (see examples below)
  • Option to search recursively but exclude certain directories
  • If you have the same filename multiple places in your source tree, will allow you to tell it that they’re really the same file (think VSS’s shared files), and only read the one with the most recent timestamp and/or shortest pathname
  • Will eventually have some degree of integration with VSS (check in, check out, undo checkout; icons change to show which files are/aren’t checked out), maybe plugin-style to allow for other SCMs
  • Will eventually let you add external tools (e.g., apps to reformat your source code), and run “check out, run the tool, check back in with an appropriate comment” as a single operation
  • Caches file contents in memory to speed future searches (but checks timestamps and reloads as needed)

An example: Suppose I have source code that looks like this.

raise EMyException.Create('This action is only available to system ' +
  'administrators and power users.');

I’ll be able to search on the text “system administrators” and get a match. Can’t do that with Find in Files, or GExperts grep, or ordinary grep. (Very useful for searching through DFMs, where you have no control over line breaks.)

Another example:

// This function will only work on Windows 9x. Windows NT
// 4.0 is not supported.

Searching on “NT 4” will get a match (if you enable the “loose whitespace” option, since it actually sees a newline between “NT” and ” 4.0″).

Another example: Suppose you have hundreds or thousands of units in your codebase, and there’s a class (TMyClass) in a commonly-used unit (call it unit MyGlobals). You want to move it into a different commonly-used unit (MyOtherGlobals). This will break any units that use TMyClass but don’t already have MyOtherGlobals in their uses clause. No problem: search for all files that do contain TMyClass, but do not contain MyOtherGlobals. Click “Check Out” to check the files out of VSS; drag them into the IDE; add MyOtherGlobals to their uses clauses; save; and click “Check In”. (Much simpler than the alternative, of just moving the class, compiling to see what breaks, and checking out and fixing one unit at a time.)

I’m writing the code in .NET, mainly because of its fabulous regex library. (Ironically enough, I’m writing this tool, whose biggest selling point is a Delphi parser, in C#. Eh, big deal; the Delphi compiler is written in C.)

I already have proof-of-concepts working for all of these features. All that’s left is to tie them all together, which is what I’m working on now. I’m writing this utility because I need it at work (where I’ve already written, and am using, some of the proof-of-concepts). I’m writing the full tool on my own time so that I own the code.

Does anyone else need a tool like this? If so, I may polish it up and release it at some point. (Also let me know if there are any features you’d like added, or if you have a killer name for the app.)

Screening

Today is National Depression Screening Day, and I took a long lunch break and went and got screened. The results were news to me, but, in retrospect, really not that surprising.

It started out with a questionnaire, printed on 11×17 carbonless paper, so it essentially amounted to two pages of questions. “Name” was not one of them (not surprising, since the screening is free and anonymous), but “age” and “race” were; statistic-gathering, I presume. Then a bunch of “how often do you feel this way” and “check yes or no” questions. Those sorts of questions are always tough to answer definitively, but I muddled through and hoped that my mistakes would mostly cancel each other out. I talked to a counselor afterward, to go over the results and make sure they made sense, and they did. They fit pretty well, actually.

Here’s the executive summary:

  • Depression: Nope
  • Mood disorders (e.g., manic-depression): Nope
  • Anxiety: Yes, mild (not enough to call a disorder)
  • Post-traumatic stress disorder: N/A
  • Attention-deficit disorder: Ooo pretty

What was most amusing was that they weren’t even testing for ADD. The counselor picked up on it from my questionnaire, and asked me more questions about it. Then he got out the DSM-IV — the official diagnostic guide. I said yes (or sometimes just nodded ruefully) to six of the nine questions, and said “sorta, 50/50” to two others. And six is the official threshold for an official diagnosis. So there ya go. (I can assure you that nobody who knows me will be surprised.)

“We are Homer of Borg. You will be assim — mmm, donuts.”

Diamondback vs. our code base

Continuing where we left off in the Diamondback saga:

I was still attached to the idea of an undoable disk for the program files (and for Windows), so I set out to find another way to preserve source code across sessions.

One possibility, of course, would have been to keep everything in VSS. But it takes a while to do a get of our full code base, and I didn’t want to go there if I could avoid it. It would’ve meant a lot less time spent actually doing stuff, and a lot more time waiting. And it also would’ve meant checking a fair number of things into our live codebase when I wasn’t sure yet whether they’d work. Not really the best option.

What I wound up using was XCopy, using some of its fancier command-line switches. I started by doing a full get onto the virtual hard drive, then used attrib to turn off all the archive bits, and then committed the changes to the virtual hard disk, so it’d come up that way after every subsequent undo.

Then I wrote a couple of batch files. One would copy any files with the archive bit set (i.e., any files that had been modified during a compiler session) up to a network drive; I would run that before shutting down the virtual machine. The other batch file would copy all of the files off that network location and onto the hard disk, clearing the archive bits in the process.

All in all, I was pretty satisfied with the way that turned out. It was fast, it didn’t require a lot of space on the network drive (since all I was copying were any files I had actually changed, plus any .dcus that I had recompiled during a given session), and it was easy to work with. Cool!

This time, as I compiled all the packages, I created a project group as I went. (Actually, I had tried that last time, but was hampered Virtual PC’s frequent crashes.) The fact that it actually worked this time, combined with the fact that most of the files that needed patching (mostly $IFDEFs checking for compiler versions) were already patched and checked in by that point, made for smooth sailing.

End result: All packages compiled! Hallelujah!

Open up our main application, and try to compile. And it churns merrily along…

before coming back with “Access violation at address 02220A6C in module ‘dcc90.dll’. Read of address 00000030.”

Aw, no. No. No! Compile again; same result. Build; same result. Reboot and revert the hard drive, then compile again; same result. In desperation, go into Project Options, uncheck “Compile using runtime packages”, and compile again. Same result.

Damn!

So close.

I did tinker with it a little more; I created a new project, added one of our medium-dependency units, and tried compiling. Worked just great. Doesn’t look like there will be any simple repro I can boil this down to.

(On the other hand, I have a perfect repro that I could pack up and ship to Borland if they wanted it. Chalk up another advantage for virtual machines.)

I never did spend much more time chasing down exactly what was causing the problem, because I had already burned most of three days in this little escapade, and I really needed to get some real work done. Without the refactoring engine, as it turned out.

Sigh.

I’d submit a QualityCentral report, if QualityCentral knew about Diamondback. As it is, all I can do is hope someone from Borland reads this. I’ve got a ready-made Virtual PC hard disk ready to go, with easy repro steps!

I’ve actually thought about opening two sessions of Diamondback, and using one to debug the other, so that I can (with a little luck) get an actual stack trace when the error occurs. Haven’t gone that far yet, though.

So… here our grand saga ends. Kind of a letdown, isn’t it? I hope Danny finds this little bug before release. With luck, he’s already found it and fixed it. Here’s keeping my fingers crossed.

Religion of Jesus vs. religion about Jesus

Every Sunday (except during summer, when most things Unitarian go on summer vacation), my church has a First Hour discussion group before the church service. This week, Russ Alberts presented a topic called “World Religions: Who the Real Founder of Christianity Was”. Here’s the description from our e-mail newsletter:

Most lay Christians would say Jesus, but scholars name other men who really created the religion we know today as Christianity. Who were these men and how did they change it from Jesus’ religion to the religion of Jesus?

This is actually a topic that has interested me for a while — since high school, at least. Between this topic, and the fact I had promised to talk to our pastor about redesigning our Web site, actually got me out of bed this morning and to church for the first time since last spring. (I really should go more often — I always really like it once I’m there. It’s getting out of bed that’s the problem.)

I asked Russ if I could reprint the material from one of his handouts, and he said sure. It’s interesting stuff to ponder, especially if you’ve ever wondered how people reconciled Crusades with “turn the other cheek”, or why many Christian churches (especially the Catholics) restrict communion to members, even though Jesus dined with tax collectors and Gentiles.

As I’ve long since realized, most of the stuff I’ve never liked about Christianity never came from Jesus. I think that when Russ referred to the “cult of Jesus” in this table, he was referring to exactly that: the people who warped Jesus’ message to their own ends. Interesting stuff.

  Religion OF Jesus Religion ABOUT Jesus
Jesus Man God
Politics Apolitical.
Jesus did not care who was emperor
Political.
Allied with Constantine to make him emperor
Attitude toward Unjust Government Unconventional antagonism.
Only God rules in Israel; Do not pay taxes
Support government
Pay taxes.
War Near pacifist
Turn the other cheek when struck, but no comment on what to do when the other cheek is struck
Pro-war
Make war to support pro-Christian rulers
Kingdom of God It is here and now. No need to wait for a future time.
Non-apocalyptic
Must wait for death or for the return of Christ.
Apocalyptic
Religion is about Living the here and now Worship of the cult of Jesus
Religious tolerance Followed Jewish holidays, but ate, drank and socialized with people of all classes and religions. Pagan and Jew made no difference. Restricted ritual bread and wine to just fellow cult members. Gentiles and Jews are only equal after they have converted.
Holidays Observed Passover Reinterpreted Pagan holidays to the Cult of Jesus
Repentance Did not call for people to repent Emphasis on guilt and repentance
Jewish Scriptures Took a liberal interpretation. The Sabbath was made to serve man, not man to serve Sabbath. Completely reinterpreted to condemn Jews and make Christians the chosen people.

HP Printer Drivers

My wife recently got a new HP printer/scanner/fax, and I just got it put together earlier today. Then, this evening, I went through the process of installing the drivers on her computer.

Some observations.

  1. They didn’t make me click through the license agreement. Instead, their wizard’s Welcome page had a separate button that I could click if I wanted to see the license agreement.I remember (about six years ago) designing a Web site that had a member agreement, and the pains we went to with it. Users had to, at an absolute minimum, scroll all the way through it before we gave them a chance to accept. We were covering our ass. We wanted people to have no opportunity to say they never saw such-and-such clause in the agreement.

    Apparently not something that HP is worried about. (At least it’s better than the opposite extreme…)

  2. The license agreement (of course I read the license agreement; I always do — it gives me more to blog about) is very clear about only allowing you to install the software on one computer. However, this printer is meant (with the purchase of external hardware) to operate nicely on a network. They even go so far as to ask me, during installation, whether I’ll run it locally or on a network.Now, tell me: just how am I supposed to use this printer on a network if I can only install the print drivers on a single machine?
  3. During installation, I have to specify whether the printer will be hooked to this machine or to the network. That’s a stupid question, because in a lot of cases, the answer will be “both”. I want the printer to be on the network — but I want to make sure the damn thing works first.And I won’t be installing the wireless print server anytime soon, because it’s hard-coded to a 192.168.x.x IP address, and our home network is set to 10.x.x.x (otherwise it didn’t play well with a 192.168.x.x VPN I used to connect to). So I’ll have to reconfigure our network just so I can set up the print server, something I’m not too eager to do anytime soon.

    So apparently, I’ll have to uninstall and reinstall the HP software at that point, just so I can tell it that the printer is on the network now. How nice.

    (For crying out loud, why does it even care?)

  4. The printed instructions say that I should start the installer before I hook the printer up to the computer, and that the installer will tell me when it’s ready for me to connect the printer. Apparently nobody told this to the installer guys, because when it got to that point, the installer came across with more of an attitude of “Hey stupid, I’m still waiting for you to hook up the printer. How about I just sit here until you either hook it up or click Cancel.” How nice.
  5. They can’t seem to figure out how much software they want to install. As soon as I hooked up the printer, they detected it and installed the drivers. Then they dropped me back to the installer, which was still sitting at the “select whether you want local or network, and then click Next”. I waited a while, but nothing happened. I clicked Next a few more times, with no effect.Finally I happened to notice that there was another installer window (conveniently hiding behind the main wizard window, and conveniently non-modal so that the main installer still looked responsive) that was installing more software While You Wait. I switched to it and waited for it to finish.

    Then it dropped me back to the main installer wizard, which was finally on a new screen. (One which didn’t even have a Back button. I always think that’s a bit rude — I did do stuff before this. Show a grayed-out Back button if you must, but don’t deny that anything just happened. Unless they’ve got politicians writing installers now.) Anyway, this one said “Okay, we’re all set to install your software now.” Grrrh.

  6. Great job on the progress bars, guys. While they were installing this last bit of software (they never actually tell you what each chunk of software is), the progress bar started off nearly-empty, stepped forward until it was full, and then dropped back to nearly-empty only to start over again. And again. I’m guessing that that progress bar filled up around fifty times (I wasn’t counting). They weren’t even trying to track what it was actually doing. I’m not sure they even knew.After a while, I caught onto the pattern. They stepped the progress bar at a consistent rate of about 2 or 3 times per second (alas, at the time I didn’t think to clock it with my stopwatch) — the progress bar was obviously in its own little world while it waited for some other thread to run. They would start with 1 unit on the progress bar, then add 2 more units (so it’s at 3 now), then 3 more, then 4 more, then 5 more. When I started paying attention, it filled up when it added 8 (so the bar’s maximum was evidently set to 36 at that point). Then they fell back to 1 unit on the bar, but this time the maximum value was 35, so that 1 unit was a tiny bit larger piece of the total bar. Again, eight steps, but the last time they only had to add a block of 7 to fill the bar. Once the maximum value got down to 28, it only took seven steps to fill, then they started again. (Sheesh. Cryptanalysis of the HP progress bar.)

    The round where the maximum value got down to about 13, they got partway and then suddenly showed the bar as totally full, and then sat there for half a minute or so before declaring that the software installation was done. Rats. I was looking forward to seeing what was going to happen when they ran out of maximum values.

  7. After they finally got done installing everything they felt like installing, after they had me print the test page, after all that was done and the main wizard had closed and the printer was all installed and working……they told me that I had to reboot to complete the installation.

    Reboot. To install freaking printer drivers. For Bog’s sake, what are the HP programmers developing on? Windows 95?

Sigh.

You know it’s a sad state of affairs when you can write seven (lengthy) bullet points about installing your printer drivers. (Whether it’s the printer drivers themselves that are sad, or just me, is a valid topic for debate.)

Next time I install HP drivers, I think I’ll get a video camera, and MST3k the installer.