Kinda wishing I could keep using Delphi

I’ve been reading the recent debate about a “Delphi Community Edition”. Most of it seems pretty abstract: “I think it would help the Delphi community if…”

That’s all well and good, but I thought I’d share something less theoretical: something that directly affects me, a longtime Delphi geek.

I’ve been using Delphi since its first release in 1995. I still have one of the original brochures somewhere, with the quote saying “It’s going to change our lives, you know.” That quote still sticks in my head, all these years later.

Delphi has been a pretty good tool to work with. Sure, the IDE freezes for half a minute at a time when you type an open paren, Ctrl+click doesn’t work half the time, and the IDE still can’t pull off a cross-unit rename refactoring (and, and, and…). But damn it, Delphi lets you write programs that work and work well. Good God, just try to find a decent unbound grid in .NET. Or a WinForms control — any WinForms control — that even begins to approach the quality of Toolbar2000 or VirtualTree.

My company got acquired, and is moving to .NET. On the one hand, I honestly can’t say I mind too much; .NET has some sweet libraries — way fewer cool GUI controls than Delphi, but more cool everything else. I love not having to write one set of code to deal with an array and a different set of code to deal with a list. The unified type system rocks for unit testing (no need to write a CheckEquals overload for every enum we’ve ever defined). And, of course, Delphi doesn’t have ReSharper. ‘Nuff said.

But I cut my Windows-programming teeth on Delphi (after banging my head against VB). Asked my comp sci department for a copy of Delphi instead of a cash scholarship, way back in ’95. Used it for my senior honors project. Knew it inside and out. Took at least one Delphi aptitude test where I was correcting the questions. Somehow I became one of the first Delphi conference bloggers. And Delphi has gotten me more than one job, and it got me where I am, working with a terrific team.

I’d really like to keep a copy of Delphi around, just to play around with for hobby projects. It’d be great to play with the new stuff in Delphi 2010. And to play with Prism. And, hell, just to show my appreciation for the product, by paying for a license now that my company won’t need to anymore.

But if it’s just for me, I can’t justify the price they want me to pay.

If it was $200, I’d find the money; Delphi is totally worth that. I might even be able to stretch to $300, especially if it included both Win32 and Prism. But $400, for an upgrade that’ll just need upgrading again in another year, and for just one platform?

At $400, I walk away. With regret.

The last version of Delphi that I own is Delphi 4 — after that, I was always able to convince my employer to buy it for me (or they already had it). So after December, when the “upgrade from any prior version” offer expires and even the painful $400 price-point goes through the roof, I’m probably going to be out of the Delphi business permanently.

And so we come to (presumably) unintended consequences. By setting their prices so high, the Delphi sales team is ensuring that, once I’m no longer paid to use Delphi, I’ll no longer be able to use Delphi. And so I won’t be able to stay current, and a couple years from now, I probably wouldn’t be able to get another Delphi job even if I could find one.

I suppose they need to run their business as they see fit. They have every right to set prices high enough to drive away their longtime customers, if that’s what they feel they need to do.

But I’m becoming painfully aware of what a lot of people have been saying for years: Delphi’s pricing is downright hostile to the hobbyist. They’re aiming strictly at the enterprise, and screw anyone else.

And that’s sad, because it’s the Inprise attitude, and the ALM attitude, all over again. They’ve got this “if we raise the price tag, we’ll get more money, and the money’s all that matters” mentality. It apparently never occurred to them that sometimes, lowering the price tag can multiply your income (and your customer base). Would that hold for Delphi? A lot of community members have been pretty vocal in thinking it will, and I’m becoming a believer.

But the sales department, so far, has stuck its fingers in its ears and pretended not to hear. And the dev team either can’t, or won’t, pressure them to change their minds.

I totally admire what the dev team has been doing lately. They’ve been making Delphi, well, Delphi again. They’ve been doing some serious moving and shaking. D2010 sounds sweet, and I’d love to play around with it.

But unless they fire the Borland/Inprise sales team, and hire some CodeGear folks, my Delphi days are numbered.

I’ve always hated change. Life will go on, of course. But still, I’ll miss Delphi.

Intolerant cat

We’ve known for a long time that Noel (our princess kitty) is lactose-intolerant. She loves anything dairy, will stick her face right into your glass of milk if you’re not quick enough to block her, will steal cheese any time she gets the chance — but if she does manage to get anything dairy, she’ll throw it right back up (usually on the carpet) within five minutes. (I’ve tried to explain to her that, in this house, we throw up on the linoleum, but so far with little success.)

Tonight I made Mexican pizzas for supper, which involves browning a pound of ground beef. I slopped a little bit out of the skillet during the process, and even though I did remember to cover the skillet before I left the kitchen, I forgot to clean up the bit of spilled hamburger.

Not long thereafter, I heard Noel throwing up in the hallway. (Yes, of course on the carpet.) And after I had shut her in the bathroom and gone to get the paper towels, sure enough, I found a small bit of hamburger amidst the mess.

Apparently she’s not just lactose-intolerant, she’s cow-intolerant.

Upcoming Omaha developer-ish conferences: BarCamp and HDC

BarCamp Omaha is October 2-3 (Friday evening to Saturday). I’ve never been to a BarCamp, but it promises to be intriguing — the session schedule is planned on a whiteboard Saturday morning, and anyone who wants to run a session, can. It’s not just a tech conference; they say the major tracks will be Tech, Creative, and Entrepreneurship.

I understand that BarCamps are usually free, but this one costs $5. But (a) that’s cheap (heck, I thought the HDC was cheap at $200 — but then again, I’m not paying for the HDC out of my own pocket) and (b) you get the full conference experience for that $5: free T-shirt (great, another one to go into the drawer), free breakfast, free lunch, and free pop and snacks all day. Free food is the primary reason for going to a conference, so it should feel just like home.

I’m toying with the idea of speaking at BarCamp (haven’t really decided yet). Their FAQ says the time slots are only 30 minutes, and I’m wondering if I should take a stab at a 31 Minutes of ReSharper. It’d take some serious editing, mind you, given that my original material was 31 days.

The Heartland Developers Conference (HDC), a Microsoft-themed conference here in Omaha, is October 15-16. I guess I don’t really need to hype it, since it’s 100% sold out this year (I wonder how long until they need to start spilling over into the first floor of the Qwest Center?). But I’m looking forward to it just like every year, because the second-day breakfast always has all the free bacon you can eat.

Oh, and they always have some pretty awesome sessions, too. A couple years ago they had Scott Guthrie from Microsoft do one of the keynotes, if that gives you any idea (at the time, he was Microsoft’s General Manager in charge of the CLR, ASP.NET, Silverlight, WPF, and IIS, among other things). They get good people and a lot of interesting content. I can pretty much register without even looking at the session list, and know that every timeslot will have a session that’s well worth my while — and even with the economy the way it is, my boss was happy to pay all our conference registrations. There’s benefits to making something cheap. (Delphi sales department, are you listening?)

Writing: Generic character names

One of the excuses I use for not writing is names. I can easily spend so much time thinking of names for my characters that I lose interest in the story idea entirely.

In a quest to write more, and make fewer excuses (or at least write my excuses down so I can say I’m writing), I’ve devised a cunning plan. I’ve come up with a small set of pre-canned character names. Then I can just use and re-use those same names for daily writing exercises, scenes, vignettes, short stories, whatever I happen to be writing on a small scale. No more “I spent my whole writing timeslot thinking of a name for my throwaway character”. And for large-scale writing — well. Let’s focus on writing something first, and worry about large-scale later.

A few years ago, at work, we needed to sketch out some scenarios with multiple users using our software. We named our fictitious users “Bob”, “Ned”, and “Lloyd”. (Why those specific names? Well, Bob and Ned are short, and since we were using these as login names, we were typing them a lot. As for Lloyd, I guess it’s just a cool name.)

For fiction, those would be a good start — but I wanted to have female names on tap as well. I figured three names, each with a male and female variant, would be just right; that way I’d be able to deal with three characters, in any gender mix, while only having to memorize three names.

Well, I could come up with good female versions of “Bob” and “Ned”. No problem there. But what the heck is the female version of “Lloyd”?

Rather than doing actual research, I decided heck with Lloyd, I’d come up with another name instead, one that did have both male and female variants. I quickly settled on “Clyde”, since it’s as cool as “Lloyd”, but does have a readily recognizable female form.

I also threw in one catch-all pet name: “Spot”. (So of course, the first scene I decided to write involving a pet? A tiger.)

And to round it out, a couple of place names. I thought about familiar names like “Metropolis” and “Gotham”, but those are both recognizably the names of big cities, and won’t do any good for stuff that needs to happen in a small town, or in the country, or the desert, or the Antarctic, or the middle of a faerie forest, or an outpost on Mars. After some thought, I finally gave up and decided, once again, to keep it simple.

So here it is: my handy-dandy list of fiction-writing metasyntactic variables:

Role Male variant Female variant
Character #1 Bob Bobbi
Character #2 Ned Edna or Eddie
Character #3 Clyde Sue
Pet Spot
Place #1 Bobsville
Place #2 Nedsville

Feel free to steal these names for your own writing — or just the general idea. I’m all for fewer excuses for not writing.

Micro-rant: Ninject and IKernel

Ninject looks cool. So does Autofac, but Ninject has automatic self-binding.

But I hate how Ninject calls its container “IKernel”.

This is the one part of Ninject that you are guaranteed to use. (Well, I guess you need modules too — not that that name is much better.) IKernel is the single most visible part of the Ninject API. And its name is absolutely wretched.

It’s named for its implementation, with no regard to its usage. In real life, it isn’t a kernel; it belongs to the kernel module in Ninject’s modular implementation. Don’t get me wrong, I appreciate that it’s modular. But don’t make me, as a dev who just wants to use a DI framework, suffer through that implementation detail.

Nobody should have to care what a “kernel” is unless they’re writing their own. “Kernel” means nothing to someone using the container (which is almost everybody). The name is not just distracting, it’s outright misleading — it actively suggests “this is not a container”, when in fact it’s exactly a container, keeper of the Get<T> method.

I really want to give Ninject an honest try, but this seriously bugs me. Why not “IContainer”? Or something that isn’t a lie? (Yeah, I know they’re ninjas and all, but shouldn’t the subterfuge be reserved for the enemy?)

Small world

We’re planning to visit family in the Southwest this summer, and as part of our trip planning, I was looking at plane fares in New Mexico. The airline’s Web site helpfully suggested that there were “multiple airports” in the cities I had selected.


I love how they suggest the same, alternate, “in the same city” airport for both my “from” and “to” cities. But not as much as I love the alternate they picked.

Just for fun, I compared the fares if I went to or from the alternate airport. They cost more, but not by much.

WPF oddity of the day: attached/dependency properties and breakpoints

Silverlight doesn’t have any real support for ICommand, so I wrote an attached CommandBinder.Command property. Then it wasn’t working (at least when I compiled for WPF, which is a lot easier to debug), so I tried putting breakpoints in my SetCommand and CommandChanged methods. Neither ever got hit.

It turns out that WPF’s attached-property pattern is weird: you have to declare a getter and setter method, but they don’t get called.

Here’s some sample code for an attached property, just for reference:

public class CommandBinder
{
    public static DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached(
            "Command", typeof(ICommand), typeof(CommandBinder),
            new PropertyMetadata(CommandChanged));
 
    private static void CommandChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        // do something
    }
    public static ICommand GetCommand(DependencyObject d)
    {
        return (ICommand) d.GetValue(CommandProperty);
    }
    public static void SetCommand(DependencyObject d, ICommand value)
    {
        d.SetValue(CommandProperty, value);
    }
}

You have to have a setter method; otherwise you get a compiler error. (Apparently the compiler has some logic to enforce the design pattern.) But as far as the XAML parser is concerned, the setter method is more of an attribute — it says “Yeah, I’m settable.” The XAML loader doesn’t call SetCommand; it calls SetValue directly on the target object.

I did some experimenting, and it looks like this applies to dependency properties as well. You have to declare a corresponding CLR property, or you’ll get a compiler error when you try to set the property in XAML; but the XAML loader never actually uses the property.

In both cases, your setter could actually do nothing at all, and the XAML would still set the property’s value correctly. (But then anyone who tried to set the property programmatically would be in for some head-scratching. So don’t do that.)

I had wondered, in the past, why you would pass a PropertyMetadata with a change-handler delegate, rather than just putting the on-change logic inside the SetXXX or property setter. Now I know.

(Actually, in my experimenting, I was able to get it to call the property setter. All I had to do was misspell the property name that I passed to DependencyProperty.Register. So that’s why I have to tell it the name (something else I had always wondered) — so it can do a dictionary lookup. If the dictionary lookup fails, it falls back on trusty-but-slow Reflection.)

So that explains why my SetCommand wasn’t being called. Why wasn’t CommandChanged firing either? Stupid mistake on my part — I hadn’t set the DataContext, so the binding expression failed.

Geek quote of the day: Git and Home Depot

Git is intimidating. It’s a distributed revision-control system, so it’d work online or off, and it’s got tons of cool toys (like git-bisect to automatically figure out which commit introduced a bug). But good luck figuring out which of the umpteen zillion commands you actually need to get something done. (I cheat — I IM my friend Sam and say, “Help?”)

Git has everything from fine-grained commands to handle a tiny part of a single commit, up through high-level commands that mow your lawn and make Julienne fries, and I have no idea how to tell which is which. Like I said, intimidating. Git has been described as not so much a revision-control system, but rather as a toolkit you can use to build your own revision-control system that works exactly the way you want it to. Which is kind of like writing your own lexer, parser, keyhole optimizer, runtime library, memory allocator, JIT compiler, and IDE, and designing custom hardware while you’re at it, and mining the silicon yourself, so you can write a programming language that works exactly the way you want it to.

And it doesn’t help that Git’s Windows support has been very slow in coming, though apparently now it’s mostly as good as on other platforms.

Yesterday I was working on a toy project that might amount to something someday, but that I was more likely to lose interest in after a few days. And I wanted revision control for it (I like diffs). But it didn’t feel worth creating a Subversion repository for something potentially throwaway. Git stores your repository right there in your working copy, which felt like a good fit. So I finally installed msysgit, and promptly found that it’s got some awesome features (I was skeptical of the index when I first heard about it, but it’s actually very cool, especially through the GUI — you can commit just certain lines from a file!… not sure how you run the unit tests on them, though), but that it’s got some stuff that truly sucks (the people who wrote the Git GUI have never heard of window resizing, word-wrapping, or context menus — and the terminology is deliberately confusing. If I can’t figure out how to revert a file, there’s a problem somewhere.)

While reading around, I happened across a mention of Mercurial, another distributed revision-control system, and I started sniffing around for comparisons between Mercurial and Git.

I hardly ever laugh out loud, but Jennie, from another room, called, “What’s so funny?”

From Use Mercurial, you Git!:

I ordered a version control system, not a toolkit for building one! If I’d wanted building blocks for rolling my own, I’d have gone to Home Depot and bought a 1 and a 0.

WPF design flaw of the day: no initial focus

When you write a WPF app and start it up, nothing has focus.

I’d call this a bug, but Microsoft has scads of testers. Somebody had to have noticed. So I can only conclude that somebody decided, on purpose, that when you write a WPF app and run it, the user shouldn’t be able to just start typing.

This is completely unlike the other two major GUI frameworks I’ve used (Delphi VCL and Windows Forms), where the app is usable by default: you open a window, your focus is in the first control in the tab order. I was therefore rather grumpy when I found out about the WPF brokenness.

Fortunately, after some digging around in Reflector, I found a nice, general fix. Adding this to the window’s constructor:

Loaded += (sender, e) =>
    MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));

will re-enable the standard behavior: initial focus is in the first control in the tab order.

This line could easily be pulled into a base class, so that all your windows can automatically inherit this behavior.