I really like my new Escape Hybrid, but I've started to notice some interesting UI issues:
I was stopping at a traffic light yesterday. I'd been driving a while so everything was warmed up. The gas engine turned off as I dropped below 20MPH -- as expected.
If the radio's not on it gets eerily quiet when you stop. Cool.
Then I took my foot off the brake. I noticed something unexpected. The car started to creep forward, just like "normal."
Hmmm...
In a normal car, the creep happens because the gasoline engine has to keep running. The torque "leaks" through the automatic transmission's torque converter. But for a hybrid the gas engine is off, and an electrical engine doesn't really need to keep spinning. In fact I'll bet the electrical engine was at a dead stop, too, when my foot was on the brake. Where is the creep coming from?
I'm betting that it's designed into the system to comfort those of us used to an automatic transmission. It reinforces the concept that a hybrid is "just like a normal car, only more efficient."
I wonder how much time Ford wasted getting this behavior to feel right. Personally I'd just as soon my car stayed where I put it unless I explicitly tell it otherwise.
Thursday, March 31, 2005
Tuesday, March 22, 2005
Cross-Programmer Code
A lot of my programming work is intended to be portable across platforms where a platform is defined as a combination of operating system, computer architecture, and development tool set (compiler, etc.). ACE is a prime example of what it takes to achieve this goal.
However,
Even more important that platform portability is programmer portability. It is highly unlikely that any significant programming project will be developed and maintained by a single programmer for the life of the project. Every time a new programmer gets involved in a project the source code has to be "ported" into that programmer's model of the language.
Every programmer carries around a lot of mental baggage. Some of us are fresh-out-of-school apprentices -- lacking the pragmatic experience of a seasoned pro. Some of us are old fogies with fond memories of FORTRAN COMMON (who strive to recapture the glory using the Singleton pattern (chuckle.)) Some of us have been programming in C++ so long that we forget how arcane some of the "obvious" idioms are.
Fortunately, unlike computer architectures, compilers, etc. the port can work both ways. The code can be adapted to the understanding of the new programmer, or the new programmer's understanding can be adapted to the code. In fact there is usually much more of the latter adaptation than the former, although I have certainly been involved in situations in which it was easier to rewrite the code than to attempt understand it.
Recognizing how often programmers must adapt to unfamiliar code, and vice versa, we should make an effort to write programmer-portable code. With that in mind, I propose the "five programmer test."
Given a language feature or coding idiom, create a sample of code using that technique.
Select five programmers with skills ranging from average to superstar (below average programmers should be dumped on someone else's project.) Ask each of them to explain in English what the code does and to describe any limitations, consequences, etc. that need to be considered when using the technique.
If all five of them agree, then it's ok to use the technique.
If at least three of the five agree (and one of them is the superstar) then it's ok to use the technique, but it requires a comment to clarify the usage.
If fewer than three programmers understand the technique, or if any programmer "understands" the technique, but her explanation of what it does is way off base -- find another way to achieve the same goal that does pass the five-programmer test.
However,
Even more important that platform portability is programmer portability. It is highly unlikely that any significant programming project will be developed and maintained by a single programmer for the life of the project. Every time a new programmer gets involved in a project the source code has to be "ported" into that programmer's model of the language.
Every programmer carries around a lot of mental baggage. Some of us are fresh-out-of-school apprentices -- lacking the pragmatic experience of a seasoned pro. Some of us are old fogies with fond memories of FORTRAN COMMON (who strive to recapture the glory using the Singleton pattern (chuckle.)) Some of us have been programming in C++ so long that we forget how arcane some of the "obvious" idioms are.
Fortunately, unlike computer architectures, compilers, etc. the port can work both ways. The code can be adapted to the understanding of the new programmer, or the new programmer's understanding can be adapted to the code. In fact there is usually much more of the latter adaptation than the former, although I have certainly been involved in situations in which it was easier to rewrite the code than to attempt understand it.
Recognizing how often programmers must adapt to unfamiliar code, and vice versa, we should make an effort to write programmer-portable code. With that in mind, I propose the "five programmer test."
Given a language feature or coding idiom, create a sample of code using that technique.
Select five programmers with skills ranging from average to superstar (below average programmers should be dumped on someone else's project.) Ask each of them to explain in English what the code does and to describe any limitations, consequences, etc. that need to be considered when using the technique.
If all five of them agree, then it's ok to use the technique.
If at least three of the five agree (and one of them is the superstar) then it's ok to use the technique, but it requires a comment to clarify the usage.
If fewer than three programmers understand the technique, or if any programmer "understands" the technique, but her explanation of what it does is way off base -- find another way to achieve the same goal that does pass the five-programmer test.
Tuesday, March 15, 2005
Another Interview Question
Another good interview question is, "Once you fix all the syntax errors and get a clean compile, what type of errors are most likely to still be in your code?"
Wrong answer: "None." End of interview. Have a nice life.
Most common answer: "I don't know."
Followup question: "So how could you find out?"
When I first asked myself this question (shortly after reading Writing Solid Code) my solution was to create a "programmer's diary." This was a background program that I could pop up with a hot key. It opened up an edit window into which I could paste or type information. It date/time stamped the entry then appended it to a sequential file and disappeared.
To use it, I'd select/copy code containing an error, pop open the edit box and paste it, then annotate it to explain the error. I did not do any further analysis in-line. Instead I went back to whatever I was doing -- fixing the problem or running more tests or whatever...
After capturing data for about a month, I analyzed the file. I categorized the types of errors into classes like:
Then for each class of mistakes I asked myself:
In some cases this resulted in changes in my coding style. For some cases I added new types of tests to my set of tools. In others, just the increased awareness of my error-of-choice was enough to help me avoid the error.
I continued to use the diary for a couple of months afterwards, and yes, there was a noticable reduction in the types of errors I had specifically targeted. Without benefit of statistical analysis, I also think there was a significant overall reduction in uncaught-by-the-compiler errors.
The downside of all of this is when I get into an argument (oops, I mean a reasoned discussion) about programming style issues I tend to be dogmatic about my style. That's because I think it's based on emperical evidence rather than aesthetics or arbitrary preferences. This would be a lot more valid if I had used the diary recently. My emperical evidence is from sometime before 1995 -- and of course it is specific to one programmer. Programming has advanced considerably since then -- in particular exceptions and patterns like RAII have changed the way I program. I wonder if it's time to fire up the old diary program.
Wrong answer: "None." End of interview. Have a nice life.
Most common answer: "I don't know."
Followup question: "So how could you find out?"
When I first asked myself this question (shortly after reading Writing Solid Code) my solution was to create a "programmer's diary." This was a background program that I could pop up with a hot key. It opened up an edit window into which I could paste or type information. It date/time stamped the entry then appended it to a sequential file and disappeared.
To use it, I'd select/copy code containing an error, pop open the edit box and paste it, then annotate it to explain the error. I did not do any further analysis in-line. Instead I went back to whatever I was doing -- fixing the problem or running more tests or whatever...
After capturing data for about a month, I analyzed the file. I categorized the types of errors into classes like:
- uninitialized or improperly initialized variable;
- sense of a condition is backwards;
- failure to release resource when returning from a function;
- difficult to use, difficult to understand, or easy to break feature of the language (think "goto" although I'd already stopped using those.)
Then for each class of mistakes I asked myself:
- What can I change can I make to my coding style or work habits to prevent this type of error?
- What can I change can I make to detect this type of error sooner?
- What type of test would detect this type of error?
In some cases this resulted in changes in my coding style. For some cases I added new types of tests to my set of tools. In others, just the increased awareness of my error-of-choice was enough to help me avoid the error.
I continued to use the diary for a couple of months afterwards, and yes, there was a noticable reduction in the types of errors I had specifically targeted. Without benefit of statistical analysis, I also think there was a significant overall reduction in uncaught-by-the-compiler errors.
The downside of all of this is when I get into an argument (oops, I mean a reasoned discussion) about programming style issues I tend to be dogmatic about my style. That's because I think it's based on emperical evidence rather than aesthetics or arbitrary preferences. This would be a lot more valid if I had used the diary recently. My emperical evidence is from sometime before 1995 -- and of course it is specific to one programmer. Programming has advanced considerably since then -- in particular exceptions and patterns like RAII have changed the way I program. I wonder if it's time to fire up the old diary program.
Saturday, March 12, 2005
This one's for Jonathan
In the lobby where visitors sign in at Google, there's a Naked Juice vending machine.
The Computer History Museum
We visited the Computer History Museum yesterday. Lots of interesting artifacts including an Enigma machine, a Cray 1, etc. The item that captured my attention, though, was a white teapot. In fact, THE white teapot. If you've seen the test images from any 3D graphics program, you already know what the teapot looks like. And it does.
Thursday, March 10, 2005
Do you know the way to San Jose?
Do airplane trips ever just work? I mean have you ever gotten to the airport on time, sailed through security, found a comfortable seat next to a pleasant companion, arrived at your destination feeling refreshed and rested, and had your luggage make it, too?
Well...
Tina and I just flew to San Jose to visit Peter, and the perfect plane trip didn't happen (one more time.)
Let’s see,
Well...
Tina and I just flew to San Jose to visit Peter, and the perfect plane trip didn't happen (one more time.)
Let’s see,
- My computer fell out of the back of Dave's van as he dropped us off at the airport (nothing damaged, apparently.)
- When we checked our bags, they took my picture ID and wandered off with it. When I asked what was going on, they told me my name was on a "watch list." This must be the same evil Dale Wilson who is behind on his alimony payments and stiffed an eye-care place somewhere in Illinois. Kind of spooky knowing I have an evil twin.
- Next was Tina's turn with security. "Is this your bag, ma'am?" said the TSA guy. "Yes," replied Tina. "I'm going to have to ask you to open it up." By then I was through security myself, so I didn't hear the details, but after I stood around for quite a while, Tina finally made it through. Apparently they confiscated a vicious looking nail file and were deeply suspicious about the dangerous drugs that were Not In Their Original Ibuprofen Bottles!
- So the plane was a little bit late taking off.
- And we landed in Tulsa. Most of the passengers go off, but those of us who were heading on to Phoenix on the same flight rearranged ourselves and got comfortable for the next leg. One of the stewardesses stopped by to admire my beard. She said her husband also had a long beard, and was giving Tina some really unfortunate suggestions involving braids and tiny lights, when the PA system announced we all had to get off the plane and go to another gate. There was vague mention of a "maintenance issue."
When we got to the new gate, there was an enormous crowd. Much more than a planeful. It seems that they were putting us on a plane that was supposed to go to Dallas. Since the plane was going to Phoenix instead, now, the Dallas people were being sent to yet-another-gate where presumably they would eventually be put on their own replacement plane to replace the one we had just borrowed from them.
This being Southwest, we were given new boarding passes that let us board first -- even before "families traveling with small children." If you want to get on a Southwest airplane first, get yourself a mauve boarding pass (honest they called it mauve!) - So that got us on the plane in Tulsa. We were 45 minutes late, but we were on our way. Nothing much went wrong during the flight to Phoenix (unless you count peanuts, but they're normal for a Southwest flight.) As we made our final approach into Phoenix they announced that Southwest was holding all connecting flights, and would anyone going to San Jose go directly to gate C2. Of course, our plane docked at the far end of the D concourse, but it coulda been worse. We hiked on over to C2 in time to walk right onto the plane shortly before they closed the doors. Things were looking up -- this plane was half empty so we had no problems finding seats.
- Oops. Spoke too soon. As we arranged ourselves I realized that I had left the book I was reading on the other plane. "Do you think they'll let me go back and get it?" I asked Tina. Right.
- So on to San Jose. We made up the time somehow and actually got to San Jose on time! The only unfortunate part of this leg was when the stewardess decided to sing as we taxied in to the airport. I guess it was endearing. A personal touch sort of like the early episodes of American Idol. "A bit pitchy," said Randy, "but not too bad." "I don't think this was a good song selection for you," said Paula, "but you've got a, um, loud voice." "I've heard better performances from the taxi driver that brought us to the hotel." said Simon.
- Home free, eh? Our baggage made it! Calloo, Callay!
- Then we got to Peter's car, and I said -- where's my computer? The brief case containing my computer--which I had carried on, so I couldn't blame the airline--wasn't there! In near panic I headed back to the baggage claim area. Fortunately it was sitting on a chair waiting for me. Airport security hadn't confiscated it as an unaccompanied bag -- probably because there was a woman there watching it. She said she saw us leave it and couldn't figure out what to do, so
she was waiting a bit to see if we came back before calling security. Thank you, thank you, thank you.
And so we're in San Jose. I do so love traveling.
Tuesday, March 08, 2005
Guidance toward the-one-true-path.
Paul Colton wrote an interesting article for Byte about XAML. Once sentence in the article was a real attention grabber:
Wow. I'm *SO* glad Microsoft is willing and able to educate and guide me. ;->
XAML has many strengths, and Microsoft's ability to educate the marketplace and guide the .NET developer community may ultimately tip the balance to XAML.
Wow. I'm *SO* glad Microsoft is willing and able to educate and guide me. ;->
Monday, March 07, 2005
Thoughts Meandering From Interview Questions to Semantic Compilers.
I used to do a lot of interviews for programming positions. One of my favorite interview questions is:
(I know, that's two questions --- but hey, it's my interview (and my blog) so I make up the rules.)
There is no "right" aswer to this question, but there are a couple of wrong ones.
The worst answer is "I haven't read any programming books recently." The applicant can recover from this if she goes on to explain that she reads programming blogs, and magazines instead because the informaion is more current, but barring such a last-minute save, a negative answer is an interview stopper.
The next worst answer is a textbook required by a college course. If the interviewee is more than a couple of months out of college and hasn't learned anything since, well....
Responding with something like "How to write [fill-in-the specific-application] programs in [fill in the language] on [fill in the platform]" earns a barely passing grade. The interviewee is on the bubble and better come up with a reason why I should keep talking to them really quickly!
Oh yeah, and any book containing "for dummies" in the title is instant death <chuckle/>.
So, how would I respond to the question?
I might mention some recent read (ala "The Pragmatic Programmer.") or I might fall back on one of the very few books that have a profound impact on the way I program.
Looking back, there have been a lot of programming books, but very few that were life-changing. "Elements of Programming Style" counts (yes, that was a long time ago, but it's still worth reading.) Most programmers know about "Elements.." and it is actually used as a textbook in some college courses (which contradicts the "second-worst" judging criterion above. hmmm.)
Another book that had a major impact was "Writing Solid Code" by Steve Maguire. I'm not sure whether this was that good a book, or whether it just happened to be the right book at the right time for me. I should probably re-read it if I could find my copy.
One concept I acquired from "Writing Solid Code" is the idea of a compiler that checks semantics rather than (or in addition to) syntax. Wouldn't it be great if the compiler would tell you: "Yes, that's legal C++, but it's really not what you should have written." Actually, over time, compilers have gotten better at producing this type of warning messages. By flaging unused variables, statements with no effect, and such atrocities as:
if (a = b)
modern compilers bring your attention to possible semantic problems. This is a good thing.
But wouldn't it be nice if compilers could go further? If they could warn not only about obvious nonsense, but also questionable practices, bad algorithms, etc. we could write better programs faster.
One problem of course, is my "really cool technique" is your semantic abomination, and vice versa. In recent discussions here at work we haven't been able to agree on where the & should go in:
int & a;
Some say goes with a because you can say "int &a, b, *c;" to which I say -- not in MY semantic compiler you can't! Some say it goes with the int because it's "part of the type" to which I say, but how about const and static. Aren't they part of the type.
In case you haven't noticed, I think that & and * are first-class citizens and deserve to stand on their own rather than being piggybacked on another token -- but that's just my opinion and it is certainly subject to debate. It's also completely beside the point of this discussion.
Lack of agreement about what constitutes a good program makes it very difficult -- nay impossible -- to come up with a one-size-fits-all semantic compiler. So how about a compiler that "learns" your programming style, and flags departures? If you always indent by two, but happen to indent by four in one place -- well maybe that indicates the code is wrong. Better yet, if you always use braces (as you should (chuckle)) then an if statement with no braces should be flagged as an "error."
Hmmm. How well does this play on a team programming project?
Of course these are all "small scale" issues. The real benefit comes when the compiler can detect, for example, that you're doing a linear search of a (large enough) sorted list and suggest that a binary search would be a good idea here, or can look at an object full of get and set methods and advise you that you've really blown the encapsulization and should be writing domain-meaningful methods instead.
STL does makes some interesting strides in that area by declining to implement "unwise" methods on some containers. Java was also a step in this direction -- unfortunately a lot of the decisions that went into Java were one man's opinion so some valuable techinques were "tossed out with the bathwater." and some warts like uninitialized references made it into the language.
There's much more to be said on this topic, but this entry is getting too long. To be revisited...
What's the best book about programming you've ever read? What book should every programmer read?
(I know, that's two questions --- but hey, it's my interview (and my blog) so I make up the rules.)
There is no "right" aswer to this question, but there are a couple of wrong ones.
The worst answer is "I haven't read any programming books recently." The applicant can recover from this if she goes on to explain that she reads programming blogs, and magazines instead because the informaion is more current, but barring such a last-minute save, a negative answer is an interview stopper.
The next worst answer is a textbook required by a college course. If the interviewee is more than a couple of months out of college and hasn't learned anything since, well....
Responding with something like "How to write [fill-in-the specific-application] programs in [fill in the language] on [fill in the platform]" earns a barely passing grade. The interviewee is on the bubble and better come up with a reason why I should keep talking to them really quickly!
Oh yeah, and any book containing "for dummies" in the title is instant death <chuckle/>.
So, how would I respond to the question?
I might mention some recent read (ala "The Pragmatic Programmer.") or I might fall back on one of the very few books that have a profound impact on the way I program.
Looking back, there have been a lot of programming books, but very few that were life-changing. "Elements of Programming Style" counts (yes, that was a long time ago, but it's still worth reading.) Most programmers know about "Elements.." and it is actually used as a textbook in some college courses (which contradicts the "second-worst" judging criterion above. hmmm.)
Another book that had a major impact was "Writing Solid Code" by Steve Maguire. I'm not sure whether this was that good a book, or whether it just happened to be the right book at the right time for me. I should probably re-read it if I could find my copy.
One concept I acquired from "Writing Solid Code" is the idea of a compiler that checks semantics rather than (or in addition to) syntax. Wouldn't it be great if the compiler would tell you: "Yes, that's legal C++, but it's really not what you should have written." Actually, over time, compilers have gotten better at producing this type of warning messages. By flaging unused variables, statements with no effect, and such atrocities as:
if (a = b)
modern compilers bring your attention to possible semantic problems. This is a good thing.
But wouldn't it be nice if compilers could go further? If they could warn not only about obvious nonsense, but also questionable practices, bad algorithms, etc. we could write better programs faster.
One problem of course, is my "really cool technique" is your semantic abomination, and vice versa. In recent discussions here at work we haven't been able to agree on where the & should go in:
int & a;
Some say goes with a because you can say "int &a, b, *c;" to which I say -- not in MY semantic compiler you can't! Some say it goes with the int because it's "part of the type" to which I say, but how about const and static. Aren't they part of the type.
In case you haven't noticed, I think that & and * are first-class citizens and deserve to stand on their own rather than being piggybacked on another token -- but that's just my opinion and it is certainly subject to debate. It's also completely beside the point of this discussion.
Lack of agreement about what constitutes a good program makes it very difficult -- nay impossible -- to come up with a one-size-fits-all semantic compiler. So how about a compiler that "learns" your programming style, and flags departures? If you always indent by two, but happen to indent by four in one place -- well maybe that indicates the code is wrong. Better yet, if you always use braces (as you should (chuckle)) then an if statement with no braces should be flagged as an "error."
Hmmm. How well does this play on a team programming project?
Of course these are all "small scale" issues. The real benefit comes when the compiler can detect, for example, that you're doing a linear search of a (large enough) sorted list and suggest that a binary search would be a good idea here, or can look at an object full of get and set methods and advise you that you've really blown the encapsulization and should be writing domain-meaningful methods instead.
STL does makes some interesting strides in that area by declining to implement "unwise" methods on some containers. Java was also a step in this direction -- unfortunately a lot of the decisions that went into Java were one man's opinion so some valuable techinques were "tossed out with the bathwater." and some warts like uninitialized references made it into the language.
There's much more to be said on this topic, but this entry is getting too long. To be revisited...
Friday, March 04, 2005
Pet Peeve n+1: Thinking outside the box
The phrase "Think outside the box" ranks right up there with "Have a nice day :-)." and just barely below fingernails scraping on blackboard.
Most people use the phrase to mean "ignore the rules."
Trucker #1: Why are you stopping?
Trucker #2: Look at the sign on that overpass.
Trucker #1: Yeah, it says "Clearance 11 ft. 6 in." So what?
Trucker #2: The trailer we're pulling is 12 feet tall.
Trucker#1: (looks around) I don't see any cops. Let's go for it.
See. Trucker#1 is thinking outside the box the way most people use the phrase.
The origin of the phrase is a classic logic puzzle. Given nine points arranged in a 3x3 grid:
Draw a continuous series of four line segments that passes through each point exactly once.
The solution (which you know, right? (if not, there's a hint below)) involves extending the lines beyond the "borders" of the array. Hence, "Thinking outside the box."
You don't solve this puzzle by thinking "outside" the box. You solve it by realizing that there is no box outside of which to think! [Look again, do you see any box?]
Understanding the true constraints on a problem and finding creative solutions within those constraints -- good. Ignoring the constraints that happen to be inconvenient -- bad.
All of which applies to programming, too!
Hint:
Most people use the phrase to mean "ignore the rules."
Trucker #1: Why are you stopping?
Trucker #2: Look at the sign on that overpass.
Trucker #1: Yeah, it says "Clearance 11 ft. 6 in." So what?
Trucker #2: The trailer we're pulling is 12 feet tall.
Trucker#1: (looks around) I don't see any cops. Let's go for it.
See. Trucker#1 is thinking outside the box the way most people use the phrase.
The origin of the phrase is a classic logic puzzle. Given nine points arranged in a 3x3 grid:
X X X
X X X
X X X
Draw a continuous series of four line segments that passes through each point exactly once.
The solution (which you know, right? (if not, there's a hint below)) involves extending the lines beyond the "borders" of the array. Hence, "Thinking outside the box."
You don't solve this puzzle by thinking "outside" the box. You solve it by realizing that there is no box outside of which to think! [Look again, do you see any box?]
Understanding the true constraints on a problem and finding creative solutions within those constraints -- good. Ignoring the constraints that happen to be inconvenient -- bad.
All of which applies to programming, too!
Hint:
X X X x
X X X
X X X
x
Wednesday, March 02, 2005
The Sins of Intel
Another entry in my Hack series. This one's a threefer:
A lot of people complain about the Intel architecture. It must have been really easy for hardware designers to build systems around the early Intel chips, 'cause you'd never find a software developer praising their design. Early Intel chips (and some not-so-early chips) were much harder to program than they needed to be.
Sin #1: A + (-B) != A - B
One of my favorite Intel sins, is that the engineer(s) who designed the early chips did not understand binary arithmetic! The way the chip was designed 5 + (-1) [that's five plus negative 1] did not produce the same answer as 5 - 1 [five minus one]! That one deserves an extra exclamation mark!
To explain:
On a four bit machine 5 + (-1) looks like:
That 1 hanging out there is a carry bit. It is normal for a subtraction to generate a carry (it means you did NOT have to borrow!)
Unfortunately on Intel the flag that ends up holding that 1 is called the carry/borrow flag. If you add, it holds the carry. If you subtract it holds the borrow.
That means 5 + (-1) is four with a carry, whereas 5 - 1 is four without a borrow, but borrow and carry are stored in the same flag, so to do-the-right-thing with the carry bit you have to know how you got here.
The result is a lot of really sweet binary arithmetic techniques were just a little bit harder and messier (and hence a little bit less sweet) on the Intel machines.
Sin #2: Segment granularity
When Intel discovered they needed to go beyond the 16 bit address space of their early processors they added segment registers. This was a good move because it preserved compatibility with older software -- or at least made it relatively easy to migrate to the new processors.
The sin comes when you considered how the segment registers were factored into the address calculations. The segment registers have 16 bits -- making them easy to manipulate on a machine that's built around a 16 bit architecture, but in order to achieve the goal of extending the address space, the segment registers have to address units of memory larger than a single byte. Intel choose a 16 byte addressable chunk for the segment registers. That means the segment register is shifted four bits to the left when it takes part in the addressing calculations. The result is the 20 bit (one megabyte) address space that hampered the Intel processors for years! (Of course IBM and Microsoft managed to hack that into the 640K limit, but that's a different transgression.)
Suppose Intel had shifted the segment register by 8 bits rather than 4 bits. Downside is a granularity of 256 bytes rather than 16 bytes (big deal--not)
Upsides:
First of all, calculating the values to go into segment registers would have been much easier because it's a lot easier to move things by 8 bits than by four bits on an Intel chip, but thats only a minor advantage compared to the real plus which is that the address space just became 24 bits (16 megabytes rather than 1 megabyte) Admittedly 16 megabytes seems small today, but it took almost 10 years before we achieved that state. Countless man-centuries (yes and woman-centuries) were poured down the bottomless pit of extended memory and expanded memory hacks trying to compensate for Intel's short sightness.
Sin #3: The 80286
Ok so they forgot to figure out how to get from user mode back to kernel mode (D'oh) This inspired the truly byzantine technique of booting the whole damn machine to do a context switch back to the OS. Kool, eh!
A lot of people complain about the Intel architecture. It must have been really easy for hardware designers to build systems around the early Intel chips, 'cause you'd never find a software developer praising their design. Early Intel chips (and some not-so-early chips) were much harder to program than they needed to be.
Sin #1: A + (-B) != A - B
One of my favorite Intel sins, is that the engineer(s) who designed the early chips did not understand binary arithmetic! The way the chip was designed 5 + (-1) [that's five plus negative 1] did not produce the same answer as 5 - 1 [five minus one]! That one deserves an extra exclamation mark!
To explain:
On a four bit machine 5 + (-1) looks like:
0101
1111
1 0100
That 1 hanging out there is a carry bit. It is normal for a subtraction to generate a carry (it means you did NOT have to borrow!)
Unfortunately on Intel the flag that ends up holding that 1 is called the carry/borrow flag. If you add, it holds the carry. If you subtract it holds the borrow.
That means 5 + (-1) is four with a carry, whereas 5 - 1 is four without a borrow, but borrow and carry are stored in the same flag, so to do-the-right-thing with the carry bit you have to know how you got here.
The result is a lot of really sweet binary arithmetic techniques were just a little bit harder and messier (and hence a little bit less sweet) on the Intel machines.
Sin #2: Segment granularity
When Intel discovered they needed to go beyond the 16 bit address space of their early processors they added segment registers. This was a good move because it preserved compatibility with older software -- or at least made it relatively easy to migrate to the new processors.
The sin comes when you considered how the segment registers were factored into the address calculations. The segment registers have 16 bits -- making them easy to manipulate on a machine that's built around a 16 bit architecture, but in order to achieve the goal of extending the address space, the segment registers have to address units of memory larger than a single byte. Intel choose a 16 byte addressable chunk for the segment registers. That means the segment register is shifted four bits to the left when it takes part in the addressing calculations. The result is the 20 bit (one megabyte) address space that hampered the Intel processors for years! (Of course IBM and Microsoft managed to hack that into the 640K limit, but that's a different transgression.)
Suppose Intel had shifted the segment register by 8 bits rather than 4 bits. Downside is a granularity of 256 bytes rather than 16 bytes (big deal--not)
Upsides:
First of all, calculating the values to go into segment registers would have been much easier because it's a lot easier to move things by 8 bits than by four bits on an Intel chip, but thats only a minor advantage compared to the real plus which is that the address space just became 24 bits (16 megabytes rather than 1 megabyte) Admittedly 16 megabytes seems small today, but it took almost 10 years before we achieved that state. Countless man-centuries (yes and woman-centuries) were poured down the bottomless pit of extended memory and expanded memory hacks trying to compensate for Intel's short sightness.
Sin #3: The 80286
Ok so they forgot to figure out how to get from user mode back to kernel mode (D'oh) This inspired the truly byzantine technique of booting the whole damn machine to do a context switch back to the OS. Kool, eh!
Monday, February 28, 2005
Stealth wins
I finished weaving the "stealth scarf" (see previous dissussion) this weekend and just as I suspected the pattern is pretty much invisible. If you hold it at just the right angle in just the right light you can see it, but that's not what I was hoping for.
For my next bright idea.....
For my next bright idea.....
Wednesday, February 23, 2005
The AAM hack
Backgound
I was working on a graphics editor for the Zenith Z100 computer. This was a shrink-wrap product intended to be distributed by the thousands (well millions actually but Zenith didn't sell enough Z100's (sigh))
The Z100 had 640 x 225 x 8 color graphics capability (or 640 x 450 if you used an undocumented video mode) (Compare and contrast to CGA.) The Z100's graphics were memory mapped, but the layout of the memory was somewhat arcane. Converting a (X,Y) pixel address to a byte and bit address involved some calculations including a divide by 9
The problem
In a word: speed. One of my test patterns took 40 seconds to render to the screen. This is painfully slow -- probably slow enough to kill the project.
Profiling the C program showed that writing pixels to the screen dominated performance of the program. Profiling the pixel writing code showed that the divide by nine was dog-slow. This was on an Intel 8086 processor (an 8 bit processor with delusions of 16 bitness)
The Hacker
Dale (that would be me) Wilson
The Hack
I can't claim exclusivity for this hack. Other people found it and later it became pretty common, but I can claim that I found it myself.
The DIV instruction on the early Intel processors was a real cycle burner. Not only that, but it took a lot of setup and tied up a lot of registers on a machine that is extremely register-poor. It had to go. The good news is that the DIV instruction was a 32bit/16bit divide which is way more than necessary for this problem. In fact an 8 bit/4 bit divide would be sufficient.
My first approach to solving the problem was to implement Divide-By-Nine as a series of shifts and subtracts. Since the divisor was hard-wired the division could be done in straight line code. No branches, no testing the carry bit (oops, this is Intel, I mean the borrow bit). The result was about ten times faster than the DIV based code. The test pattern now showed up in four seconds vs the original 40 seconds. Good, but four seconds is still a bit sluggish.
Studying the Intel instruction set revealed all sorts of oddities. One interesting one was the AAM gap. The AAM instruction itself was a somewhat dorky instruction intended to be used as one step in multiplying BCD numbers. The acronym stands for Arithmetic Adjust after Multiply. Once you get past the noise about BCD multiplies (who multiplies BCD numbers? Maybe COBOL programmers (grin)) and look at what it actually does to the bits, you discover that it's really a divide instruction. It divides the AL register by ten and puts the quotient in AH and the remainder in AL.
The opcode for AAM is D4 0A. But looking at the Intel instruction set docs reveals that AAM is the only instruction with D4 as the first byte. That seems wasteful. And it is interesting that the second byte happens to be an "A" (i.e. a ten) A little experimenting (can you say self-modifying code (with a straight face?)) reveals that AAM is really a 8 bit "divide immediate" instruction. If you put a 09 in the second byte it divides by 9. If you put a '0' there, you get a divide-by-zero fault!
Back to the write-the-pixel fast algorithm. Out comes the shift-and-subtract sequence. In goes a AAM9 and voila, the render time is significantly under a second. Life is good. Ship the product. Everyone sees what a marvelous machine the Z100 is; Zenith rules; and we all become rich-n-famous (oops--except for that last sentence (sigh.))
Ok, judges. What's the score for this one on the sleazy(0) to righteous(10) scale?
Extenuating circumstances
I left one point of information out of the discussion above. I left the shift and subtract code in the program. At startup the program tested to be sure AAM9 did the right thing. If the test failed, it fell back to shift and divide.
My Rating
Since this is my own hack it's hard for me to be objective but without the startup check, I'll give it about a 3. Using undocumented features of the processor in commercial software is bad news. With the check, however, I'd go as high as a 6. After all is success in the market requires speed and this is the only way to get the speed...
As it turns out, however, this wasn't the only way to get the speed. In a later version of the program I switched from thinking about the screen as a collection of pixels to thinking about it as a collection of horizontal lines (some of which were very short.) This gained almost as much of a speed increase as the switch from shift-subtract to AAM9, and it didn't involve any undocumented ops.
And one last point.
You may wonder why I didn't use the "normal" technique of rendering into an off-screen buffer then blitting to the actual video buffer. Good question, and the answer comes back to available memory. Zenith sold Z100's with as little as 128K bytes of RAM for programs + operating system. (The video buffer was separate.). A screen buffer takes 54K which means there just wasn't enough RAM available to do an off-screen buffer right.
I was working on a graphics editor for the Zenith Z100 computer. This was a shrink-wrap product intended to be distributed by the thousands (well millions actually but Zenith didn't sell enough Z100's (sigh))
The Z100 had 640 x 225 x 8 color graphics capability (or 640 x 450 if you used an undocumented video mode) (Compare and contrast to
The problem
In a word: speed. One of my test patterns took 40 seconds to render to the screen. This is painfully slow -- probably slow enough to kill the project.
Profiling the C program showed that writing pixels to the screen dominated performance of the program. Profiling the pixel writing code showed that the divide by nine was dog-slow. This was on an Intel 8086 processor (an 8 bit processor with delusions of 16 bitness)
The Hacker
Dale (that would be me) Wilson
The Hack
I can't claim exclusivity for this hack. Other people found it and later it became pretty common, but I can claim that I found it myself.
The DIV instruction on the early Intel processors was a real cycle burner. Not only that, but it took a lot of setup and tied up a lot of registers on a machine that is extremely register-poor. It had to go. The good news is that the DIV instruction was a 32bit/16bit divide which is way more than necessary for this problem. In fact an 8 bit/4 bit divide would be sufficient.
My first approach to solving the problem was to implement Divide-By-Nine as a series of shifts and subtracts. Since the divisor was hard-wired the division could be done in straight line code. No branches, no testing the carry bit (oops, this is Intel, I mean the borrow bit). The result was about ten times faster than the DIV based code. The test pattern now showed up in four seconds vs the original 40 seconds. Good, but four seconds is still a bit sluggish.
Studying the Intel instruction set revealed all sorts of oddities. One interesting one was the AAM gap. The AAM instruction itself was a somewhat dorky instruction intended to be used as one step in multiplying BCD numbers. The acronym stands for Arithmetic Adjust after Multiply. Once you get past the noise about BCD multiplies (who multiplies BCD numbers? Maybe COBOL programmers (grin)) and look at what it actually does to the bits, you discover that it's really a divide instruction. It divides the AL register by ten and puts the quotient in AH and the remainder in AL.
The opcode for AAM is D4 0A. But looking at the Intel instruction set docs reveals that AAM is the only instruction with D4 as the first byte. That seems wasteful. And it is interesting that the second byte happens to be an "A" (i.e. a ten) A little experimenting (can you say self-modifying code (with a straight face?)) reveals that AAM is really a 8 bit "divide immediate" instruction. If you put a 09 in the second byte it divides by 9. If you put a '0' there, you get a divide-by-zero fault!
Back to the write-the-pixel fast algorithm. Out comes the shift-and-subtract sequence. In goes a AAM9 and voila, the render time is significantly under a second. Life is good. Ship the product. Everyone sees what a marvelous machine the Z100 is; Zenith rules; and we all become rich-n-famous (oops--except for that last sentence (sigh.))
Ok, judges. What's the score for this one on the sleazy(0) to righteous(10) scale?
Extenuating circumstances
I left one point of information out of the discussion above. I left the shift and subtract code in the program. At startup the program tested to be sure AAM9 did the right thing. If the test failed, it fell back to shift and divide.
My Rating
Since this is my own hack it's hard for me to be objective but without the startup check, I'll give it about a 3. Using undocumented features of the processor in commercial software is bad news. With the check, however, I'd go as high as a 6. After all is success in the market requires speed and this is the only way to get the speed...
As it turns out, however, this wasn't the only way to get the speed. In a later version of the program I switched from thinking about the screen as a collection of pixels to thinking about it as a collection of horizontal lines (some of which were very short.) This gained almost as much of a speed increase as the switch from shift-subtract to AAM9, and it didn't involve any undocumented ops.
And one last point.
You may wonder why I didn't use the "normal" technique of rendering into an off-screen buffer then blitting to the actual video buffer. Good question, and the answer comes back to available memory. Zenith sold Z100's with as little as 128K bytes of RAM for programs + operating system. (The video buffer was separate.). A screen buffer takes 54K which means there just wasn't enough RAM available to do an off-screen buffer right.
Monday, February 21, 2005
The FNO Hack
Background
Like the previous hack, this took place on a Honeywell 6000 computer running GCOS. We had an application that used a random access file for persistence in a high traffic environment (~50 allocations/second for sustained periods of time.)
To understand the hack you need to understand how floating point math was implemented on the Honeywell 6000 machine.
The H6000 worked with floating point numbers in the EAQ register where E is an eight bit exponent register and AQ is a double-word (72 bit) general purpose register used as a mantissa in this case. Floating point operations did not always produce normalized results, so a special instruction, FNO, normalized the current contents of the EAQ register.
Floating point normalization
Consider Avogadro's number = 6.022 × 10**23. Another way to express this is 0.602 x 10**24. The first version is normalized (base 10). The second is not. Notice the loss of precision. Binary normalization works the same way. To normalize a number you shift it left to get rid of leading zeroes and adjust the exponent appropriately.
The problem
The challenge was to control the allocation of blocks in the random file. Remember memory is tight, so a free list is not a good solution. Instead we used an allocation table with each bit corresponding to a block in the file.
How can you find an available block as fast as possible.
The hacker Bob ("If you need comments to understand my code, you shouldn't be reading it!") Miller
The hack
An important decision was to represent available blocks as one bits and used blocks as zero bits. This allowed testing 72 bits at a time when looking for an available block by loading the AQ register and branching if the result was non-zero. Thus the the algorithm was:
to get the available block number.
Rate this hack from 0 (slimey) to 10 (righteous).
Important factors in my rating of this hack are:
Although it uses an instruction for "the wrong purpose" if you read the description of the instruction in terms of how it maniuplates bits it does all the right things. In other words as long as Honewell doesn't decide to change how they represent floating point the hack should continue to work.
This is a high use function that has a direct and visible impact on performance.
Rating
I give it a 9 out of ten (If Bob had believed in comments it might actually be a 10).
Like the previous hack, this took place on a Honeywell 6000 computer running GCOS. We had an application that used a random access file for persistence in a high traffic environment (~50 allocations/second for sustained periods of time.)
To understand the hack you need to understand how floating point math was implemented on the Honeywell 6000 machine.
The H6000 worked with floating point numbers in the EAQ register where E is an eight bit exponent register and AQ is a double-word (72 bit) general purpose register used as a mantissa in this case. Floating point operations did not always produce normalized results, so a special instruction, FNO, normalized the current contents of the EAQ register.
Floating point normalization
Consider Avogadro's number = 6.022 × 10**23. Another way to express this is 0.602 x 10**24. The first version is normalized (base 10). The second is not. Notice the loss of precision. Binary normalization works the same way. To normalize a number you shift it left to get rid of leading zeroes and adjust the exponent appropriately.
The problem
The challenge was to control the allocation of blocks in the random file. Remember memory is tight, so a free list is not a good solution. Instead we used an allocation table with each bit corresponding to a block in the file.
How can you find an available block as fast as possible.
The hacker Bob ("If you need comments to understand my code, you shouldn't be reading it!") Miller
The hack
An important decision was to represent available blocks as one bits and used blocks as zero bits. This allowed testing 72 bits at a time when looking for an available block by loading the AQ register and branching if the result was non-zero. Thus the the algorithm was:
loop:
load AQ tablepointer (auto incremented by 2 words)
jump if zero to loop
and now the hack:
load the E register with zero
FNO (floating point normalize)
copy the E register to a general purpose register.
Add 36 * the word offset in the allocation table
to get the available block number.
Rate this hack from 0 (slimey) to 10 (righteous).
Important factors in my rating of this hack are:
Although it uses an instruction for "the wrong purpose" if you read the description of the instruction in terms of how it maniuplates bits it does all the right things. In other words as long as Honewell doesn't decide to change how they represent floating point the hack should continue to work.
This is a high use function that has a direct and visible impact on performance.
Rating
I give it a 9 out of ten (If Bob had believed in comments it might actually be a 10).
Friday, February 18, 2005
The IOCW hack
Setting the scene
The time is the early 1970's. The computer, a Honeywell 6000 running the GCOS operating system. Some characteristics of this system:
Addressing space was 18 bits, but fortunately the addressable unit was a four byte word so addressable space was one megabyte (where a byte has nine bits, but that's irrelevant). The OS had virtual memory but individual processes were still limited to the 1M space.
The system had a separate I/O processor (known as the IOC) that handled all input and output. The IOC was progammable using a very limited instruction set (I/O control words (IOCW)). To perform I/O you created one of these programs in your memory and asked the IOC to execute it. You could do scatter/gather I/O using IOCWs. You could also branch (but not conditionally) from one set of IOCWs to another.
When an application requested I/O the OS validated the IOCW's then started the I/O. The OS handled interrupts and status coming back from the IOC, then passed the results (and a limited form of interrupts) back to the application.
The Problem
Memory is at a premium, and dynamic memory allocation is tough in assembly language. Where do you put the IOCW's?
The Hacker
Jim Mettes (who happened to be my boss at the time.)
The Hack
Put an IOCW directly in the read buffer. The IOC fetches the instruction from the buffer first, then reads the data into the buffer -- overwriting the IOCW which is no longer needed. Four bytes (the size of an IOCW) saved!
At this point you should decide for yourself where this hack rates on the slimey to righteous scale. Zero is ultra-slime and 10 is mega-righteous.
The rest of the story.
Consider what happens when a recoverable I/O error happens. The IOC reports the error. The OS determines that it is retryable and asks that age-old question: "Abort, Retry, or Ignore?" In this case the question goes to the console operator, not the person running the program. "Retry" says the console operator because that's what his proceedure manual says to answer.
The OS tells the IOC to try again. The IOC refetches the IOCW -- but it's been overwritten by the data from the previous attempt. Remeber the point about the OS validating the IOCWs before issuing the I/O request? Guess what the designers of the OS forgot to do during the retry? If you were lucky you ended up with a core dump of your application. If you weren't quite so lucky the system administrators ended up with a core dump of the whole machine and came looking for your head!
The Score
I give it a 1. High danger, low payoff. And how do you tell your boss about it?
The time is the early 1970's. The computer, a Honeywell 6000 running the GCOS operating system. Some characteristics of this system:
Addressing space was 18 bits, but fortunately the addressable unit was a four byte word so addressable space was one megabyte (where a byte has nine bits, but that's irrelevant). The OS had virtual memory but individual processes were still limited to the 1M space.
The system had a separate I/O processor (known as the IOC) that handled all input and output. The IOC was progammable using a very limited instruction set (I/O control words (IOCW)). To perform I/O you created one of these programs in your memory and asked the IOC to execute it. You could do scatter/gather I/O using IOCWs. You could also branch (but not conditionally) from one set of IOCWs to another.
When an application requested I/O the OS validated the IOCW's then started the I/O. The OS handled interrupts and status coming back from the IOC, then passed the results (and a limited form of interrupts) back to the application.
The Problem
Memory is at a premium, and dynamic memory allocation is tough in assembly language. Where do you put the IOCW's?
The Hacker
Jim Mettes (who happened to be my boss at the time.)
The Hack
Put an IOCW directly in the read buffer. The IOC fetches the instruction from the buffer first, then reads the data into the buffer -- overwriting the IOCW which is no longer needed. Four bytes (the size of an IOCW) saved!
At this point you should decide for yourself where this hack rates on the slimey to righteous scale. Zero is ultra-slime and 10 is mega-righteous.
The rest of the story.
Consider what happens when a recoverable I/O error happens. The IOC reports the error. The OS determines that it is retryable and asks that age-old question: "Abort, Retry, or Ignore?" In this case the question goes to the console operator, not the person running the program. "Retry" says the console operator because that's what his proceedure manual says to answer.
The OS tells the IOC to try again. The IOC refetches the IOCW -- but it's been overwritten by the data from the previous attempt. Remeber the point about the OS validating the IOCWs before issuing the I/O request? Guess what the designers of the OS forgot to do during the retry? If you were lucky you ended up with a core dump of your application. If you weren't quite so lucky the system administrators ended up with a core dump of the whole machine and came looking for your head!
The Score
I give it a 1. High danger, low payoff. And how do you tell your boss about it?
Wednesday, February 16, 2005
Thought #2 for the day
Some code idioms are inherently bug-prone. High on my list of offenders:
abc() presumably returns a pointer to an object that has a widget method. But what if it doesn't have a pointer available?
now if abc returned a reference rather than a pointer....
Dale
abc()->widget();
abc() presumably returns a pointer to an object that has a widget method. But what if it doesn't have a pointer available?
Programmer: Doctor, it hurts when I do this.
Doctor: So don't do that!
now if abc returned a reference rather than a pointer....
Dale
Fragile programming
There was a time when I practiced defensive programming. The theory was that code should be able to handle anything thrown at it.
What a bad idea!
If you're writing a square root function and someone hands you a negative number, DON"T fix it for them. Abort, throw an exception, trigger an assert, whatever! Just be sure that they know as soon as possible that they've done you wrong. (A compile-time error would be ideal.)
This rant was triggered by code throughout ACE and TAO that looks like:
(Yes, the comments are really there in the code.)
Adding an ACE_ASSERT (and the missing brackets which should have been there in the first place) to one instance of this "idiom" revealed a longstanding design error in ACE's handling of Thread Specific Storage.
I'd rather work with fragile code than helpful code!
What a bad idea!
If you're writing a square root function and someone hands you a negative number, DON"T fix it for them. Abort, throw an exception, trigger an assert, whatever! Just be sure that they know as soon as possible that they've done you wrong. (A compile-time error would be ideal.)
This rant was triggered by code throughout ACE and TAO that looks like:
if (do_some_function () != 0)
return -1; // this should not happen
(Yes, the comments are really there in the code.)
Adding an ACE_ASSERT (and the missing brackets which should have been there in the first place) to one instance of this "idiom" revealed a longstanding design error in ACE's handling of Thread Specific Storage.
I'd rather work with fragile code than helpful code!
Just to be thorough, the code should be:
if (do_some_function () != 0)
{
ACE_ASSERT(false);
return -1;
}
not:
ACE_ASSERT (do_some_function () == 0);
Tuesday, February 15, 2005
Relativity values
In thinking about historical hacks I realized I needed to set the scene to make some of them understandable.
This started me thinking about the computing world and culture then vs. now. Everybody knows about the dramatic drop in price of electronics, but I'm not sure everyone has a gut feeling for the magnitude of the change. In fact, I often forget, and I lived thru it.
So: thought for today.
When I started working as a programmer, if I saved my entire salary (no food, no clothing, etc.) I could buy the computer I worked on in only 333 years.
Today I could buy a much more powerful machine every other day!
That helps to explain why we were willing to invest months and sometimes years of programmer time for relatively small gains in computer time. Thereby motivating hacks...
This started me thinking about the computing world and culture then vs. now. Everybody knows about the dramatic drop in price of electronics, but I'm not sure everyone has a gut feeling for the magnitude of the change. In fact, I often forget, and I lived thru it.
So: thought for today.
When I started working as a programmer, if I saved my entire salary (no food, no clothing, etc.) I could buy the computer I worked on in only 333 years.
Today I could buy a much more powerful machine every other day!
That helps to explain why we were willing to invest months and sometimes years of programmer time for relatively small gains in computer time. Thereby motivating hacks...
Friday, February 11, 2005
The Hack Spectrum
Near the end of an otherwise excellent presentation on the boost shared pointers(boost::shared_ptr), Jonathan showed a slide with the title "Tricks." On this slide it explained how to create a smart pointer to a stack based or static object. This immediately raised by "hack"les.
Pointing a smart pointer at an auto variable violates the semantics of the pointer. The fact that it is syntacticly correct is not an excuse. In fact I consider this a defect in the design of the smart pointer -- a well designed smart pointer would not allow such nonsense. [Note what constitutes a well design smart pointer [IMO] is another topic that I might get into later...]
Jonathan defended the trick by saying "as long as you know what you are doing, it's ok." Alas, that's not correct. A more accurate statement would be: "As long as you and every programer who touches the system either before or after you is aware of all of the implications of this trick, then it's not quite so bad." What makes this hack so insideous is that it doesn't break your code; I breaks mine, months or years later. What's worse, once I find the true cause of the "bug" in my code I have lost confidence in the reliability of smart pointer. This means that every time I use smart pointer I have to consider and either eliminate or allow for the possibility that some programmer will have violated the semantics of the pointer somewhere in the system.
In Jonathan's defense, the technique he described comes straight from Smart Pointer Programming Techniques page on the boost web site. My quibble is not with Jonathan, but with the author(s) of boost::shared_ptr and that web page.
This has made me ruminate for the last few days on the various hacks I have encountered, or in some cases perpetrated over the years I have been developing software. Using the terminology from my early days as a programmer, I realized that there is a spectrum of hacks ranging from a "slimey hack" (one that works but makes you want to wash your mind out with lysol after you read it) to a "righteous hack" (one that makes you step back in awe at its beauty and clarity.)
So I thought I'd document some of these historic hacks and explain where I think they fit on the slime-to-righteous scale. Watch this space...
Pointing a smart pointer at an auto variable violates the semantics of the pointer. The fact that it is syntacticly correct is not an excuse. In fact I consider this a defect in the design of the smart pointer -- a well designed smart pointer would not allow such nonsense. [Note what constitutes a well design smart pointer [IMO] is another topic that I might get into later...]
Jonathan defended the trick by saying "as long as you know what you are doing, it's ok." Alas, that's not correct. A more accurate statement would be: "As long as you and every programer who touches the system either before or after you is aware of all of the implications of this trick, then it's not quite so bad." What makes this hack so insideous is that it doesn't break your code; I breaks mine, months or years later. What's worse, once I find the true cause of the "bug" in my code I have lost confidence in the reliability of smart pointer. This means that every time I use smart pointer I have to consider and either eliminate or allow for the possibility that some programmer will have violated the semantics of the pointer somewhere in the system.
In Jonathan's defense, the technique he described comes straight from Smart Pointer Programming Techniques page on the boost web site. My quibble is not with Jonathan, but with the author(s) of boost::shared_ptr and that web page.
This has made me ruminate for the last few days on the various hacks I have encountered, or in some cases perpetrated over the years I have been developing software. Using the terminology from my early days as a programmer, I realized that there is a spectrum of hacks ranging from a "slimey hack" (one that works but makes you want to wash your mind out with lysol after you read it) to a "righteous hack" (one that makes you step back in awe at its beauty and clarity.)
So I thought I'd document some of these historic hacks and explain where I think they fit on the slime-to-righteous scale. Watch this space...
Thursday, February 10, 2005
Swig vs C#
I spent some time recently evaluating SWIG . It's a nice way to expose your C or C++ interfaces to perl or python (and possibly other languages) -- although it has some perfectly understandable limitation on what types you can use. These limitations are surmountable by writing some helper functions.
Unfortunately what the customer wanted was to access the interface "from .NET" (which I translated to: from C#. )
Swig has a -csharp option [Digression: Swig's argument are positional flags!!!!. That is "swig -csharp -c++ " doesnt work! You have to say swig -c++ -csharp. Not necessarily a confidence builder.] Unfortunately the entire documentation for the -csharp option consists of about 20 lines in the manual and these lines are not terribly helpful since they show how to access global C variables using Mono's version of C#.
"Google swig csharp" or "google swig c#" didn't produce anything more helpful. (actually this blog may now show up in that search and I've already explained more than any of the other hits did (chuckle))
There's a SWIG wiki page, but when I rummaged around on it the only relevant thing I found was a FAQ (with no answer) that turned out to be pretty useless.
Bottom line, I think it'll be easier to write a managed C++ bridge layer to expose the C++ interfaces to the .NET world. We'll see (if I ever get back to this issue.)
Unfortunately what the customer wanted was to access the interface "from .NET" (which I translated to: from C#. )
Swig has a -csharp option [Digression: Swig's argument are positional flags!!!!. That is "swig -csharp -c++ " doesnt work! You have to say swig -c++ -csharp. Not necessarily a confidence builder.] Unfortunately the entire documentation for the -csharp option consists of about 20 lines in the manual and these lines are not terribly helpful since they show how to access global C variables using Mono's version of C#.
"Google swig csharp" or "google swig c#" didn't produce anything more helpful. (actually this blog may now show up in that search and I've already explained more than any of the other hits did (chuckle))
There's a SWIG wiki page, but when I rummaged around on it the only relevant thing I found was a FAQ (with no answer) that turned out to be pretty useless.
Bottom line, I think it'll be easier to write a managed C++ bridge layer to expose the C++ interfaces to the .NET world. We'll see (if I ever get back to this issue.)
Subscribe to:
Comments (Atom)
