Fog Creek Software
Discussion Board




Joel & C++

Although Joel writes intelligent articles, I am a little dubious about his programming, and in particular, his C++ skills. Something I noticed that really reaks of an inexperienced C++ programmer is found in 'Hard Assed Bug Fixing' (http://www.joelonsoftware.com/articles/fog0000000014.html)

He gives the following example:

int foo( object& r )
{
    r.Blah();
    return 1;
}

Claiming that in user bug reports, the 'r' reference is NULL. He says, "that's completely impossible, there's no such thing as a NULL reference, C++ guarantees it". He continues on, blaming the bug on faulty hardware, or operating system software, or some other kind of aberrant glitch.

Blaming compilers, libraries, and hardware for problems is an immediate sign of an inexperience programmer. This is no exception. C++ does guarantee that there is no such thing as a NULL reference. C++ guarantees lots of things, it's strange how all the nasty bugs I have had to deal with involve things that C++ 'guarantees' can or can't happen.

As soon as the programmer does something which involves undefined behavior, however, all bets are off. C++ no longer makes any guarantees at all. Anything can happen. The program can fry your hard drive and send sexually explicit emails to your mother for all the C++ standard cares.

Of course, most implementations don't exhibit such interesting behavior: they do the most obvious thing. Simply, dereferencing a NULL pointer is undefined, and the most obvious thing to happen if you construct a reference by dereferencing a NULL pointer is to get a 'NULL reference'.

If you call Joel's function above, using the following code:

object* ptr = NULL;
foo(*ptr);

you can bet that on just about every C++ implementation there is, you will get a NULL reference. This is also perfectly standards-conforming. More simply, the complete program:

#include <iostream>

int main()
{
    char* ptr = 0;
    char& ref = *ptr;
    std::cout << (int)&ref << std::endl;
    return 0;
}

will output '0' on almost every C++ implementation there is, although a C++ implementation could do anything it wanted, since the program involves undefined behavior.

The problem Joel describes has nothing to do with dodgy hardware or software, it just had a typical NULL pointer dereference.

Also, when Joel talks about "C++" I fear he's probably talking about "C on Steroids" - i.e. he really writes C, with a few nice looking annotations C++ provides. He says, "I don't care how you do it, just let me concatenate strings without thinking about where the new bigger string will go and I'll be happy." with implication that C++ doesn't provide this. Well it does, here you go Joel:

string s1 = "blah";
string s2 = "blim";
string s3 = s1 + s2;

nice and simple. People who make C++ hideously complicated usually do so by choice (or because they don't know better). Admittedly, some C++ APIs (Microsoft's especially) are hideous, but if you write your code well, interfacing with APIs should only be a small part of your program.

What do other people think?

Just a Programmer
Monday, October 14, 2002

Well, I agree with his overall point which is unexpected hardware/software configurations of customer's computers can cause crashes.  I mean, how many of us have installed programs that run perfectly fine *except* for when McAfee Virus Scan is activated?  Sometimes the problem really is with the hardware/software configuration.

I guess the specific example was slightly confusing for the reason you gave.  Obviously if you don't initialize the object's state before dereferencing it, you're gonna get a fatal run-time exception.  I'm assuming that in Joel's example the object *was* initialized (offscreen) and that the program ran perfectly fine on test machines. 

Crimson
Tuesday, October 15, 2002

No, he clearly said that you can't have a NULL reference. He (incorrectly) assumed that a NULL reference was impossible, because of the C++ language guarantees, and thus assumed that any occurence of one had to be a problem out of his control. If it had been a NULL pointer, he would have attempted to fix it.

Problems like this, and indeed much weirder problems than this, can occur in C++. To prove that it's a problem with the underlying environment is difficult indeed - there are all sorts of subtle memory corruption bugs etc that can occur in C and C++. In this case however, it looks like it is a simple NULL pointer dereference that went unchecked...

Just a Programmer
Tuesday, October 15, 2002

I am not argueing you on the C++ stuff, but I am curious if you have a point besides showing Joel's ability, or lack thereof, as a C++ programmer.

Does you intend to proceed to showing his other opinions are suspect based on this proof? Or that the discussions on this forum suffer because of it?

I ask, because I don't think anyone here is interested in Joel's programming capabilities, unless they affect his articles. Most of the people who are interested in programming issues seem to be asking the general public of this forum, not Joel specifically.

Maybe you are right about Joel's programming example(s), or maybe he chose them too carelessly. Did you ask him privately? Because you seem to make an assumption about his intentions that only he can substantiate.

Erik
Tuesday, October 15, 2002

Any experienced C++ programmer worth his salt always checks for NULL pointers/referencing before trying to dereference the pointer/reference.  From the looks of things, it seems that Joel does know C++ but has not been in the 'trenches' enough to encounter a lot of weird bugs that can crop up...

Tim
Tuesday, October 15, 2002

int main()
{
    char* ptr = 0;
    char& ref = *ptr;  // BAD - SEGV now.
    std::cout << (int)&ref << std::endl;
    return 0;
}

Actually, you'll get a bad dereferenced pointer (SEGV signal on Posix), not a null reference.  I've never encountered a null reference in C++.

Forget the Joel good/bad thing.  Not important.

How about something else I had a discussion about yesterday...  why prefer C++ exceptions over return values for errors?

The only place I can find a use for C++ exceptions is when calling a constructor - because its the only way to find out if the constructor succeeded.  All others should be return values with effective int of errno.h (Unix) or HRESULT (Win32) style success/error codes.

What say thee?  The only way to write code which gracefully handles errors, is to handle all errors...

contractasaurus
Tuesday, October 15, 2002

Erik: Joel writes essays about programming. He indicates the primary languages he has experience with are C++ and Visual Basic. Even though his essays do not generally deal directly with technical issues, a lack of understanding of one of the two languages he claims to be experienced in is rather disconcerting.

Yes I have sent him a private email regarding this, but he hasn't responded as of yet. He probably gets lots of emails, so this is understandable.

Tim: Experienced C++ programmers don't necessarily check references for NULL before dereferencing, precisely for the reason Joel gives: there is no such thing as a NULL reference in C++. If you end up with such a thing, it means you failed to check for NULL before dereferencing a pointer.

You only need to check pointers for NULL before dereferencing. However, it's clear that Joel didn't do that in the code he gives, since if he had, he wouldn't have ended up with a NULL reference.

Just a Programmer
Tuesday, October 15, 2002

contractasaurus: What compiler is this on? I have checked under both gcc and MSVC++6 and I get a NULL reference. But true, a compiler could give a seg fault instead, depending on how exactly it implements references (indeed a compiler can generate code that does whatever it wants since the behavior is undefined).

Just a Programmer
Tuesday, October 15, 2002

The only place I can find a use for C++ exceptions is when calling a constructor - because its the only way to find out if the constructor succeeded.  All others should be return values with effective int of errno.h (Unix) or HRESULT (Win32) style success/error codes.

What say thee?  The only way to write code which gracefully handles errors, is to handle all errors...

contractasaurus

itstilldoesntmatter
Tuesday, October 15, 2002

Oooops, sorry, was a bit fast on <return> here...

contractasaurus:
first off, you can simply use another reference variable in the constructor to signal whether it failed or not:

class foo {
  foo(int &rc) {
      // things go wrong
      rc = -1;
  }
};

Problem here is that you cannot check it if you call this constructor withing another one etc. (Well, I _think_ (haven't time to check that now) you could if each constructor would check the value of rc first, but that is a consept I completely dislike)
Besides, exceptions sounds good to me. But my problem is that I never saw a project where exceptions were used consistently, and if some code has the usual return-value-based error handling while other use exceptions, you are on the best way to a complete mess.
If you use 'em from ground up they will probably make things look slick.

itdoesntmatter
Tuesday, October 15, 2002

--------------------------------------------------------------------
What say thee?  The only way to write code which gracefully handles errors, is to handle all errors...

----------------------------------------------- contractasaurus


The benefit of exceptions is that you can handle all the errors in a different place to where you get on with the real work.  This makes the code cleaner.

The other thing is that if you do exceptions right, you get a contract.  If a raise an exception, then it won't go away until it is handled.

Main calls function a.  Function a raises exception.  If Main doesn't handle the exception, the default handler will so you have to fix it.  There's no missing that error.

Return values have no such contract.

Main calls function a.  Funtion a returns a value that indicates an error.  Main fails to check for the value, but the system continues to work apparantly unharmed.  The error is missed and you're going to have trouble finding it next year.

Of course I'm new to C++.  I learnt exceptions in Java and wouldn't be without them.  Does something about their implementation in C++ make them less effective?

Ged Byrne
Tuesday, October 15, 2002

-------------------------------------------------------------------------
class object
{
public:
  void blah()
  {
    std::cout << "I'm good." << std::endl;
  }
};

int foo( object& r )
{
    r.blah();
    return 1;
};

object x;

int main() {
  std::cout << foo(x) << std::endl;

  char* ptr = 0;
  char& ref = *ptr;
  std::cout << (int)&ref << std::endl;

  std::cout << foo(ref);

}
---------------------------------------------------------------------


Crimson,

I'm trying your code.  This is as far as I get, but when I try to compile Bloodshed Dev++ (based on gcc) is giving the following error at compile time:

-----------------------------------------------------------------------
In function `int main()':
conversion from `char' to non-scalar type `object' requested
in passing argument 1 of `foo(object &)'
-----------------------------------------------------------------------

Sorry, as I say I'm new to C++.  What do I need to do to get foo to except my null reference?

Ged Byrne
Tuesday, October 15, 2002

I don't advise trying to get the NULL reference working with the foo example Joel gives because "object" isn't even a builtin type in C++ and so forth. Use the second example I gave.

As for error handling, exception handling has huge advantages. Having to check every pointer returned from a memory allocation routine for nullity is damn annoying. It makes your code huge. Exceptions are the only real way to handle things like this.

If it wasn't for exceptions, imagine how we'd have to access containers in C++. You'd have to go:

bool result = myvector.push_back(5);
if(result == false) {
    //handle vector failling to allocate
}

this is horrible. With exceptions you can handle it in far fewer places.

Of course, the big problem in C++ is that static exception specification checking is not supported, and so programmers will typically fail to be rigorous about exceptions. Strangely, C# has the same problem. I think this alone makes C# an inferior option to Java. Statis exception specification checking is a *big* deal.

There is, however, a C++ solution: PC-Lint (see www.gimpel.com) will perform static exception specification checking for you. If you use it on a project from the start, you will be almost guaranteed to have far less problems. For that matter, PC-Lint also does many other cool checks, like for possible NULL pointer dereferences. (full disclosure: other than being employed by a company that has purchased their software, I have no affiliation with Gimpel).

Just a Programmer
Tuesday, October 15, 2002

Just a Programmer,

Most of the topics Joel writes on, are about issues that are unrelated to the act programming. In fact, his essays apply equally to any project that finds itself in the same context as he gives, whether the code is programmed in C, C++, Java, or anything else.

Any of his essays that are specifically about how to do things in C++ are valid subjects for your scrutiny. If there are any, I am neither aware of them nor interested.

Remember, preparing, or controlling, or monitoring a project does not require detailed understanding of language specifics. Designing a product does, to the extent that there is no point in designing something that can't be built.

Erik
Tuesday, October 15, 2002

Erik,

Although many of the topics Joel writes about are abstracted to the degree you claim, his writing often still involves technical details. He makes various very absolute claims, for instance that having automatic memory management is the only feature a language can offer that will significantly improve programmer productivity. I would suggest that if one makes claims like that, one must be a good programmer to have the experience to back it up. If one is not a good programmer, even in a language he or she has nominated as a language which they have expertise in, then I must admit to being rather dubious about many of the claims they make that involve the details of programming.

Programming skill is relevant to many of the topics Joel writes about. It is also not relevant, or at least not very relevant to many other topics he writes about. Thus far however, I have not made any implications other than that he does not appear to be a particularly experienced programmer. The rest is left to reader deduction.

Just a Programmer
Tuesday, October 15, 2002

Just a programmer,

Thanks for the info.  I didn't realise that the exceptions weren't statically tested.  PCLint looks like it will solve that one for me.

I'd still like to know how the foo function could be called with a null reference.  I know I don't want it to happen, but I want to understand how it could happen so that I can be on guard.

Ged Byrne
Tuesday, October 15, 2002

Ged: the following code is a complete program which will give you a NULL reference in a function, using most compilers:

#include <iostream>

void function(int& ref)
{
    std::cout << (int)&ref << std::endl;
}

int main()
{
    int* p = 0;
    function(*p);
    return 0;
}

Basically it involves dereferencing a NULL pointer. Something you should never do. If you want more information, see the following article by Herb Sutter:
http://www.gotw.ca/conv/002.htm

Just a Programmer
Tuesday, October 15, 2002

Thanks, I'm beginning to understand.

However, as far as I can tell Joel is still right.  In the example he gives it's still impossible (at least on my machine with my compiler) to get a null into the function he gives.

I modified you code so that it takes an object, and it is failing at compile time with this error:

----------------------------------------------------------------------
15 d:\gedbs\cpp\my_src\foobar\justa.cpp
no match for `_IO_ostream_withassign & << void'
----------------------------------------------------------------------

Sure, if I just send ref out to std output It shows its a null pointer, but as soon as I try to use ref as a reference the compiler complains.  This reassures me.  Am I missing anything?


--------------------------------------------------------------------------
class object
{
public:
  void blah()
  {
    std::cout << "I'm good." << std::endl;
  }
};

void function(object& ref)
{
    std::cout << ref.blah() << std::endl;
}

int main()
{
    object* p = 0;
    function(*p);
    return 0;
}
-------------------------------------------------------------------------

Ged Byrne
Tuesday, October 15, 2002

The Herb Strutter article is very good.  Thanks for that.

Ged Byrne
Tuesday, October 15, 2002

Ged: The reason your code isn't working is because you're trying to output the result of blah() when blah() returns void. You just want to call blah(), since it itself outputs, but doesn't return anything. This code will then compile, and on most compilers will just output "I'm good". This is because usually, calling a member function through a null pointer is ok, so long as you don't directly or indirectly access any member variables or virtual functions inside the function. (not that you should ever do this). e.g.

#include <iostream>

struct object { void f() { std::cout << "blah" << std::endl; } };

int main() { object* ptr = 0; ptr->f(); return 0; }

will run fine, outputting "blah" and not crashing on most compilers (it's not something I'd recommend doing though)

Just a Programmer
Tuesday, October 15, 2002

Of course.  Stupid me.

Now I have code that works (or rather, doesn't -  Application Error).  Nasy null Reference.  Not so assured.

However, I understand what's going on, and the exersize has taught me a fair bit about pointers and references.  I won't go running scared back to Java just yet.

It surprises me that this type of behaviour is allowed by C++.  Is it because of maintaining C compatability?

---------------------------------------------------------------------
#include <iostream>

class object
{
public:
  object(int aSecret) : secret(aSecret) {}
  int blah()
  {
    std::cout << "I'm good." << std::endl;
    return secret;
  }
private:
  int secret;
};


void function(object& ref)
{
    std::cout << ref.blah() << std::endl;
}

int main()
{
    object* p = 0;
    function(*p);
    return 0;
}
--------------------------------------------------------------------

Ged Byrne
Tuesday, October 15, 2002

Ged: This sort of thing is allowed in C++ largely because C++ has this concept of "undefined behavior". That is, once the programmer does something not allowed, the language will no longer make any guarantees at all. This is in the interests of speed, but can be very frustrating and make debugging difficult. It is probably the biggest single factor in making C++ more difficult than Java. (But I still prefer C++ as a language; I think it has enough advantages to compensate).

Just a Programmer
Tuesday, October 15, 2002


Hm. I believe what Joel tried to say was among the lines of "See, you have this condition covered somewhere else, and there is no way this is gonna fault. Yet, it does, and it will."

Morale of the story: cover your ass, use a bug database, and test, test, test. I still can't see the value of this C++/Joel can('t) program thread (besides some interesting quirks about C++.)

Regards,

Leonardo Herrera
Tuesday, October 15, 2002

Just a Programmer,

Well, that was an interesting conversation in a place which has seemed to have lost much of its interest in recent weeks. 

Nat

(fromerly contractasarous, and other split personalities...)

Nat Ersoz
Tuesday, October 15, 2002

Oh, I meant to say also:

Agreed that what make Java exceptions so much more powerful is that they are part of the class definition, and statically bound.

Nat Ersoz
Tuesday, October 15, 2002

>>>>>>>>>>
The only place I can find a use for C++ exceptions is when calling a constructor - because its the only way to find out if the constructor succeeded.  All others should be return values with effective int of errno.h (Unix) or HRESULT (Win32) style success/error codes.
>>>>>>>>>>

I'm not a C++ expert by any means.  But, I did learn this from a C++ expert and i'll pass it along (maybe he was wrong):  You should never call any functions in a constructor (or was it any functions that could fail/return an error code).

I limit the constructor to initializing variables and that's it.  That way, I never *have* to check for an error code in the constructor.

If you need to call functions that return an error code, create an Init function for that class.

William C
Tuesday, October 15, 2002

Calling functions within your constructor is OK. If there is an error, you can use exceptions to throw the error out. However, you should never throw any exceptions from your destructor.

Zwarm Monkey
Tuesday, October 15, 2002

The problem is calling _virtual_ functions within a constructor.  That is probably something you want to avoid.  What you will get is a call to your class's function, not a call to what you probably want, which is the call to the inherited virtual function. 

Nat Ersoz
Tuesday, October 15, 2002

Re: "Never call functions in a constructor"

That used to be the rule. And it opened up a huge set of potential bugs:

1) Forgetting to call the Init function
2) Calling the Init function twice
3) Knowing when you have to Init and when you don't.

Also, it makes it much harder to use "Resource Acquisition is Initialization", the C++ idiom that prevents resource leaks.

Exceptions were added precisely to get around these problems. Now that exceptions are in the language, you should throw them, and do your init work in the constructor where it should have been in the first place.

Calling VIRTUAL functions from a constructor is still a bad idea, but that's a whole different issue.

Chris Tavares
Tuesday, October 15, 2002

I usually won't check for NULL function arguments in my C++ code, for a few reasons:

- NULL is easy to test for, but someone could pass in a pointer/reference to any random non-zero memory address just as easily.  This is common with thrashed memory.  Can't really catch this easily in C++ (without an ImOK() member function).

- It's difficult to recover from.  Someone passed me a NULL.  What do I do?  Throw an exception?  Maybe.  If I'm getting a NULL and the caller isn't an idiot, then there's possible thrashed memory and the exception may not propogate anyhow.  There's potential for errors in error handling code that "percolates up" a chain of return values.

- Dereferencing a NULL pointer is an automatic GP fault.  This makes it one of the kinder C++ errors.  You're never sick without knowing you're sick.

Bottom line:  If I'm writing void LaunchTheMissiles(target *t), I'll check t for NULL, otherwise, generally, I'll assume that this fatal error is in fact - fatal.

Bill Carlson
Tuesday, October 15, 2002

Geez, programmers are lame.

pb
Tuesday, October 15, 2002

Leonardo: I'm sorry, no, Joel was claiming that a "NULL reference" can *never* happen, and if it does it can't possibly be the programmer's fault, and must be a problem with the hardware the program is running on. He was saying that if you run into a situation where you have a NULL reference, then don't bother trying to fix it, because it's not a bug in your code and it's not worth the time or effort to do it. He even (half-jokingly) mentioned a hardware vendor accused of causing this behavior.

Bill: Yeah, usually if you get a bad or NULL pointer when you're not expecting it, your program is in big trouble anyway. The function silently returning (which is what most people do in this kind of situation) is not a good idea, as it hides the problem and could result in incorrect data, which is generally worse than no data (i.e. the program crashing).

However, it really does depend on the situation. I will generally check for NULL or bad pointers (using IsBadReadPtr, and IsBadWritePtr on win32 - in fact I have the whole thing wrapped using a function template I wrote called IsBad which will automagically work out if the pointer is a pointer-to-const and if it's a smart pointer and so forth and do appropriate checking).

Also, where I use pointers, NULL is usually a valid value - indicating non-existence of the object. If NULL is not a valid value, then I will use a reference where possible.

Classes should never have a non-private init() function. This is plain evil. Throwing something from the constructor is *the* way to report an error. Anything else is evil. Further, I would suggest that in many or even most instances, using exception handling is a more convenient way to handle errors than using error codes.

Programming with exceptions does require a disciplined programming style, but it's a programming discipline that's good anyway, even if you don't use exceptions.

Writing a robust application - one that will elegantly handle, or even attempt to recover from situations like memory exhaustion - with error codes alone is tedious and difficult. Using exceptions, it's much easier.

Just a Programmer
Tuesday, October 15, 2002

Has anybody ever heard of ' a storm in a teacup'?

Alberto
Tuesday, October 15, 2002

all you C++ programmers need to wake up and realize DELPHI is superior, and your C++ arguement is pointless.  No one would ever have these problems if everyone used delphi!

--delphi for life!!!
Tuesday, October 15, 2002

delphi for life: In my experience, one of the most useful and important features of a language is the support of typesafe generic programming. I'm afraid that Delphi doesn't support this...

Just a Programmer
Tuesday, October 15, 2002

Exceptions are fine when you have a single language runtime and a single platform.  If you have mixed development and/or multiple platforms then exceptions become impossible.

Which is why .NET scores in this regard, but then of course its really a single language runtime and currently a single platform.

Simon P. Lucy
Wednesday, October 16, 2002

I am sure most of the conversation has been fruitful for many, and I think many don't even recall why this thread was started in the first place.

Just a Programmer, you started this by questioning someones programming ability based on an article he wrote. I am no C++ plus expert and believe whatever you say about the example Joel gave.

But, I think Alberto was right when he mentioned the storm. Joel's article was not about his programming abilities, nor about the specific construct he used to make his point.
And his point was, don't always fix every bug you find, but make sure it is economically sound to fix the bug.

And that is always sound advise. And not so because Joel said it, but because many have already found and said it to be true in many other professions.

And from the programming example Joel gave and the arguments in each of your replies, I tend to think it is not such a bad example after all.
Not because it could never happen, because some of you have argued convincingly that it can. But precisely because of what some of you argued, it can only happen under very peculiar circumstances, and there is no clear path to correcting the situation.
In other words, even if it goes wrong, and you can detect it, what can you do to fix it.

Before this thread takes of again explaining the countless steps you can take to fix it, and that I am not aware of, not being a programmer, ask yourself this. How probable is it that you attract this disease, and how expensive is the cure?

Now ask yourself that every time you run into a bug, and you will have taken Joel's advise after all. Because in the real world (the world in which your code is being used), there is a clear difference between probability and possibility.

Erik
Wednesday, October 16, 2002

What an interesting thread!

First off, my (limited) experience of C++ is limited to modifying & maintaining somebody else's code.

I dislike C++ for a variety of reasons, most of which boil down to "it's too complicated". I came from a C background, but despite this I much prefer Delphi's Object Pascal language - I make far fewer mistakes. In OP, all objects are references: in C++, I'm always using . instead of -> or vice-versa. C++ seems to have all these strange rules - about what you can and can't do in a constructor, for instance - that I can see no rationale for and have difficulty remembering. So I always end up sticking to a very limited subset that I (think) I know works, missing much of the power of the language.

Now what does that remind me of? Ah yes, a badly-designed user interface! If we look at a programming language/environment as a user interface (for programmers) to the underlying machine and OS/libraries, many of the techniques and rules learned in that field can be carried over to language design and use. Discuss!

BTW, I agree that one of Delphi OP's more significant failings is the lack of a type-safe pattern/template/generic system. But C++ templates!! Look at ADA95 generics for how it should be done.

Max Hadley
Wednesday, October 16, 2002

Erik: I am sorry, but Joel's example had no validity at all. It was a typical C++ crash caused by the program itself. I don't think *anyone* debates whether or not a bug like this should be fixed. Of course it should.

If it was a weird crash, caused not by the program, but by dodgy hardware, like Joel suggested, then absolutely, it shouldn't be fixed. If he had showed that it was caused by hardware, I would have agreed with him wholeheartedly.

Although the principal of Joel's article was still correct, he miscommunicates some important things. He makes it seem like it's easy to blame a software problem on the hardware, environment, or compiler. This is not so: it is very difficult to determine that a crash of a program is due to a bad environment; one needs a far more rigorous test then what he has given.

Further, it does call Joel's credibility as a software engineer into question a little: He has admitted that he worked on a project that received reports of crashes while the product was in beta testing, misdiagnosed the cause of those crashes to be 'bad hardware' when in fact it was just sloppy programming, ending in the bugs never being fixed. And now, years later, he is writing essays on how he was right not to fix the bugs. Don't you think that calls his credibility into question just a little bit?

Max: C++ isn't my "dream language". It has many problems, not the least of which is the fragmentation and variance of implementations. However, I do understand it, and so it is productive for me. There are nicer languages, but they are simply not used. My personal favorite is Haskell.

Delphi may be simpler than C++, however its simplicity is of little advantage to me when I already know C++, and am familiar with its idioms, and can now take advantage of generic type-safe programming, which Delphi does not support.

Just a Programmer
Wednesday, October 16, 2002

"He makes it seem like it's easy to blame a software problem on the hardware, environment, or compiler."

I am sure that was not his intention. And it does not bother me as much as you apparently. His main point though, as you agree, remains valid.

"... misdiagnosed the cause of those crashes to be 'bad hardware' when in fact it was just sloppy programming, ending in the bugs never being fixed. And now, years later, he is writing essays on how he was right not to fix the bugs.  Don't you think that calls his credibility into question just a little bit?"

Misdiagnosing in itself is not that bad, it happens to the best of us. However, not learning is worse. I am just not that convinced by this very simple example in an article about something else, that he is defending he was right not to fix this particular bug.

Besides, do you think people would believe anything Joel says without at least some thought? I read his articles with interest and in the context of my experience, and I am sure others do. Most of what he says is interesting and entertaining. He never not automatically right, but he usually gives good arguments to support his opinions. Still everyone is free to disagree, and I am sure he is wrong often enough to be human. I expect he will be the first to admit when he's wrong and change his ways accordingly.
I am also sure you are intelligent enough to spot the inaccuracies of Joel's arguments and only take what you need. You are free to point out any suspect information, as you did, but like Joel you might misinterpreted on occasion too, and if you think you haven't on this occasion, I am sure you have though about it long enough to satisfy your own sense of justice.

For me, even when you are right about this, I have no reason to become more suspicous of his musings than I am by nature, unless the topic is C++. But I would not be very interested in the topic in the first place :-)

Erik
Wednesday, October 16, 2002

"Exceptions are fine when you have a single language runtime and a single platform.  If you have mixed development and/or multiple platforms then exceptions become impossible."

Beg to disagree, but I'm currently working on a project which is mixed C++/Perl and multiple platform (Win,Linux,various Unix). Apart from having to ensure that we don't propagate exceptions into the Perl parts (there are few enough of them that this is not a problem) exceptions are working well for us.

David Clayworth
Wednesday, October 16, 2002

Erik: Misdiagnosing a bug happens to the best of us. Usually these misdiagnoses consist of us thinking it is in one segment of code, when it is in another. We stick to it, and eventually find and correct the bug.

In this case however, a team Joel was working on failed to fix the bug at all, leaving it in the release version of the program. This was due largely to a huge misdiagnosis of the problem.

I don't know about you, but it makes me a little dubious about his abilities when one can deduce that he worked as an engineer on projects where he, and the entire team, flat-out missed the problems completely.

As I said earlier, being quick to blame problems on the tools used is generally a sign of a novice. It is disturbing to hear it from one who is so experienced.

Just a Programmer
Wednesday, October 16, 2002

"In this case however, a team Joel was working on failed to fix the bug at all, leaving it in the release version of the program."

If you read the article carefully, you will note that Joel says that in the end he went ahead fixed all the known bugs anyway.

Seriously, although I happen to know this wee bit of trivia about how to create a NULL reference because I  find obscure things interesting, it is really uncommon knowledge about C++ and many experts do not know about it. I seem to recall that a couple months ago when Katie (was it she?) first brought up this bit of trivia, a lot of people were really surprised to hear about it.

And now here you Big Men on Campus are all swaying back and forth and waving your jawbones and grunting and declaring what marvelous programmers you are and how ignorant Joel is that he does not have the Supreme Knowlege of C++ Trivia that you all do.

Feh I say! Show us *your* successful software companies selling usable reliable software! Show it to us that we may see what Heartbreaking Works of Staggering Genius thou hast created so that we may bow down and worship it!

Ed the Millwright
Wednesday, October 16, 2002

Ed: At the end of the article, Joel says they fixed "every known" bug in FogBugz, the software his company currently produces.

Firstly, he didn't consider the earlier crash a bug. He attributed it to "cosmic rays" (his words). Secondly, that was referring to a product he had worked on at an earlier company: Juno.

I am fairly new here, and if this issue has been brought up before, I am sorry for the redundancy; I wasn't aware of it. Indeed, if it has been brought up before, one would think that Joel would at least publish an addendum to his essay acknowledging the error.

Just a Programmer
Wednesday, October 16, 2002

I think one can be of two minds here.  On one hand, C++ is known as an inelegant monster of a language where bad trivia abounds.  And Joel's articles are about software management.  Presumably this is a bug that should not arise given reasonable coding?

OTOH, if there's an error it should be mentioned.  C++'s complexity has to be understood if you're going to program for years on it. 

I do notice though that in business there's a balance between being technically proficient and other things.  Otherwise we'd be on really incredible machines by now.

Tj
Wednesday, October 16, 2002

David Clayworth:

If you can't propagate the exceptions into Perl, for very good reasons, then surely my point that exceptions are impossible in multiple language runtimes is valid?

The number of exceptions that happen isn't actually relevant :-)

I suppose you're using the same C++ compiler and libraries across all the platforms, that enables exception handling for that runtime.

Notice I'm not getting into the religious war of whether exceptions are a Good or Bad thing.

Simon Lucy
Thursday, October 17, 2002

Ed,

The internet, as a medium, requires people to question what they read, and let others know of those questions.

Joel speaks out on a number of subjects with great authority, and it is very easy to take it all as gospel truth because of the way it's presented.

JustA is doing an important service by scrutinising what Joel has said, and bringing up points he thinks are relevant.  Personally, I'm grateful.  I've learnt a lot.

I think theres a big difference between JustA's well supported criticism and the usual 'Joel smells' type of trolling.

Ged Byrne
Thursday, October 17, 2002

Ed, the issue Just brings up is not some sort of trivia only a handful of c++ trivia hounds know about.  This is pointer basics.  If somebody doesn't understand how these things work, they're probably getting into trouble in places they don't even realize. 

qwik
Thursday, October 17, 2002

I won't weigh in on the C++ issue because while I'm comfortable with C++, I am no expert in it.

JustAProgrammer, I've read your posts but I still don't see that your point is much bigger than "Look at me. I'm a better C++ programmer than Joel because I know <insert tidbit here."

This site isn't about how to be a better C++ programmer. Joel isn't claiming to be the authority on C++. If that were true, then your point might be better taken.  I'm sure Joel writes his fair share of bugs; I'm sure he has made lots of coding and design mistakes. So what? Who hasn't?

That doesn't change the fact that he is a great writer who brings up a lot of valid points in his articles.

Mark Hoffman
Thursday, October 17, 2002

WTF?  God forbid you should point out an error in one of Joel's articles - be prepared to suffer the wrath of the Joel apologists!

qwik
Thursday, October 17, 2002

Why is it that one takes sample code that includes C++ null pointer as the word of God, and then completly ignores statements like on the FogCreek home page link:

"Tips, opinions, and highly questionable rants on the software development process from Joel on Software."

And before I get accused too, I'd like to apologise for Joel -- and myself while I'm at it, for thinking I could actually get something out of reading articles on software design by a person who write's sample code that technically could be construed to be a bad example by those with high blood pressure. I must have slipped into a coma, sorry.

Robin Debreuil
Thursday, October 17, 2002

Robin, I don't even understand what you are trying to say, but you're excused anyway.

qwik
Thursday, October 17, 2002

There's two issues here:

1. Joel is absolutely correct when he says that there is no such thing as a NULL reference. He is right. That's one of the great things about references -- you can use it without testing for NULL, rest assured it will not be. One of the criteria for using references insead of pointers is that the value you are using can not possible be NULL -- doesn't use NULL as a 'special' value meaning 'memory not allocated' or such. *

2. You guys that think you are hot shots are not all that. You would make poor employees. But you can improve. Why do I say this? Because you have poor social skills.

This is what you do:

"Joel says NULL references are impossible but I have code that makes NULl references so Joel is wrong therefore he does not know how to program because he is wrong and this is a simple basic issue of pointers that every C++ programmer learns on the first day of school. I hardly think he is qualified to be writing articles on software development with such a poor level of skills because he is wrong. Hire me instead of Joel, I am *that* good because I am not wrong like Joel because I found one thing that he is wrong at."

And you know what, it's lame. It's a dead giveaway that you are a poor developer. You might have the ARM memorized (and you don't or you wouldn't be making these claims about NULL references) but if you bring this attitude that you are better than everybody into a team, that team will never jell. Good thing you are using anonymous aliases, so there is still a chance for a recovery.

Let me teach you a better way. Why not try this approach instead:

"I noticed that Joel says NULL references are impossible. That's a very common perception and I am not surprised he was bitten by this since there are several well-regarded C++ books that state that NULL references are impossible. In fact, NULL references are indeed possible and here is some example code that shows how it is done. Remember to always check your refrences if they are null before dereferencing them with a dot - Mature Programmer"

And then Mature Programmer will find himself further educated by one who knows more than he does,

"Dear Mature, Thanks for the informative post bringing up this interesting issue. Many programmers wonder about when to use references as opposed to pointers. One useful criteria is when the value can not possibly be NULL. In point of fact, there is no such thing as a NULL reference in C++. Dereferencing a NULL pointer to create a reference is not permitted in C++ and once that happens the behavior of C++ becomes undefined, that is to say outside the standard. This is not desireable. It is true that most compilers now do not check for this and will happily create a 'NULL reference' for you, but that behavior is not defined under the C++ standard. The pattern to use here is that anytime there is the possibilitya pointer could be NULL you should not make a reference from it -- thus check the pointer for NULLity before creating that reference and if it is NULL, don't make the reference, whcih would then bring you into the realm of undefined behavior."

--

I have had this NULL reference debate with lots of competant C++ programmers. I never call insult their abilities if they don't know that NULL references are possible. Instead I use it as an opportunity to have a nice talk about C++ design methods -- such as criteria for using references instead of pointers, wihch is a very interesting subject. At the end of the day, they respect me even more and we both know more than we did before.

If someone barges into my office or starts yammering at a meeting with a bunch of nonsense about how I am an incompetant developer because I don't check for NULL references or any other bit of trivia, I wait for the tirade to end, find out what their real issues are and address them if valid or explain to them their own error if invalid. If I like them, I might talk to them as I am to you now about being professional. If I don't like them, I just regard them as unprofessional twits and let them dig holes for themselves without interference from me.

Ed the Millwright
Thursday, October 17, 2002

Ed, if your people don't understand how pointers work, then you should work on your hiring skills.  This is basic stuff - DON'T dereference an invalid pointer.  Also, here's another bit of 'trivia' for you:  DON'T divide by 0!  As for social skills, you really did provide a good example by your first post.  Quite professional indeed.  Lastly, the issue isn't about whether or not the C++ standard allows for NULL pointers.  No one claimed that it does.  The OP said quite clearly that once the invalid pointer was dereferenced that the program's behavior from that point on is undefined.  You need to brush up on your reading skills too.

qwik
Thursday, October 17, 2002

Hey quick,

Maybe I missed the point too... What I'm hearing is "Joel's articles are full of crap, and here's proof". And then the proof is a debateable snippet of code (irrelevant to the point of the article anyway), from a year and a half ago. Then we can work backwards - so he isn't a good programmer - so he's a liar about his abilities - so he isn't qualified to write about software - so his articles are full of crap. Hmmm. If that is the ultimate point, why not just say that? Or challenge the actual premise of the article? Or other ones? But with logic like that, who needs null references for bugs anyway.

I suspect though, that the real motivation is ego - the implication that 'knowing' this means greater skill, which leads to better opinions, which even implies that the said person could write better if they cared to. Well bravo. My applause would be loudest if I felt like clapping.

If someone wants to disagree with an article certainly its all open to debate, that is why there is a forum. Or talk about null refs, sure, it is interesting. Talking about how Joel "really reaks of an inexperienced C++ programmer", my spelling, or 'gif' vs 'jif' doesn't really lead anywhere useful though does it? It right up there with name calling.

Robin Debreuil
Thursday, October 17, 2002

qwik,

Pointers and references are not the same thing.

Ed
Thursday, October 17, 2002

Thanks for pointing that out Ed.  So much clearer now.

qwik
Thursday, October 17, 2002

Let me brush up my writing skills:

"Lastly, the issue isn't about whether or not the C++ standard allows for NULL _references_.  "

;)

qwik
Thursday, October 17, 2002

Robin, you may be right.  I didn't take the post that way though. 

qwik
Thursday, October 17, 2002

Robin: I'm sorry, I never said "Joel's articles are full of crap and here's proof".

I simply pointed out that something in one of Joel's articles was clearly and unambiguously incorrect. I then left conclusions thereafter to be largely left to the reader.

Just a Programmer
Thursday, October 17, 2002

Hm, no one has picked up on my comment about 'testing for a NULL reference'.

So I'll just sit here and talk to myself. All you genius programmers that are better than Joel know this stuff already so you can just skip this post.

The code joel gave:

int foo( object& r )
{
    r.Blah();
    return 1;
}

is perfectly fine. There is NOTHING in it to be fixed.

And yet there was the crash... and the comment about how the bug reporting mechanism showed this failing on two or more Packard Bell computers in 'low-memory situations' (he implies this is what is going on in this particular case.)

So what we see when we look back in time to Joel's monitor when he was working for Juno parsing these bug reports from the field. We see him opening his edinor to the line number and file name of the line r.Blah() where the bug report says that an address error occurred. We see him looking in puzzlement through this code that maybe he himself wrote or maybe it was someone else who designed and wrote it. We see him noting that there are two bug reports on which this line is implicated and that they both happened on a Packard Bell computer that had pretty very little memory left -- the stack and the heap pointers were about to collide, so says the comprehensive bug report. Joel's been a C++ programmer for years. He's read all the books. He can't see how this could be -- there is no such thing as NULL references in C++ -- that's one of the things that's cool about references as opposed to pointers -- you don't have to check them.

In summary, the following is something you should never see in anyone's code:

int foo( object& r )
{
  if (NULL != &r)
    r.Blah();
  return 1;
}

So how did it happen anyway and what is the solution?

Well, somewhere there is code that looks like this:

Gizmo myGizmo = new Gizmo(a,b,c);
...
foo(*myGizmo);

Gizmo's constructor doesn't throw an exception if allocation failed and the code ... does not check if myGizmo is a NULL pointer after the constructor is called.

None of this is the fault of function foo.
And the compiler technically IS broken since it should not allow NULL references to be created by dereferencing a NULL pointer.

But regardless of all this, one should deal with memory allocation failure in some way. Who knows though, Gizmo is probably a function in a $400 grid library they got off the internet and fails to throw an exception when allocation fails, choosing to return silently instead.


 

Ed
Thursday, October 17, 2002

60 replies on this topic.  Someone is hyperventilating.

d00d
Thursday, October 17, 2002

Ed, you should read that link way up there that Just already posted.  Herb Sutter writes way better than you (no offense, he writes better than most of us).

Here it is again in case you're lazy:

http://www.gotw.ca/conv/002.htm

(Note that you didn't add anything to this discussion that we haven't gone over)

qwik
Thursday, October 17, 2002

Hello again.

>>>>>>>>>>
Exceptions were added precisely to get around these problems. Now that exceptions are in the language, you should throw them, and do your init work in the constructor where it should have been in the first place.
>>>>>>>>>>

Hmm.  Couple of problems.  Or maybe not.  I've been programming C++ (since graduating) for about 2 years...so, I'm still "new"....so I definitely could be wrong.

Everybody treats Exceptions like they come for free.  And what I mean is, they don't think about the fact that too many exceptions might slow down the code (yes/no? am I wrong here? -- I'm thinking all the exceptions that you must catch is part of the reason that Java can be slow).  Also, I develop for PDA's.  Now, if you have ever developed for the Palm (pre-OS5) with C++...I think a lot is done just in C but we used C++...you would realize that there isn't a whole bunch of stack space available.  Right? Isn't catching exceptions applying that much more "pressure" to your stacks?  (I really need to sit down and read the Arm (annotated ref. manual) -- I've been trying to get around to doing it).

William C
Thursday, October 17, 2002

Oh. One other thing.

>>>>>>>>>>
Also, it makes it much harder to use "Resource Acquisition is Initialization", the C++ idiom that prevents resource leaks.
>>>>>>>>>>

Can you get in depth on this?

Because I don't understand how having an Init function takes away from preventing resource leaks.

In other words, I still use the destructor.  And in my constructor, I'm saying that I don't even "new" anything.  I just initialize variables (like ints, etc. -- primitave data types).

So, I will new a variable in the "Init" and if it failed, then I will call delte on the object that I instantiated.  So, the destructor will then take care of things.

Also, I'm in Palm/Win32/PocketPC land.  So, these are GUI type apps. (Dialog apps, Doc/Veiw, etc).  Maybe the fact that I'm stuck in the MFC layer of things....I don't see the need for using exceptions as opposed to another kind of C++ development?

I dunno.  I'm babbling...but interested in advice! :)

William C
Thursday, October 17, 2002

Let me be more clear on one thing I said here:

>>>>>>>>>>
So, I will new a variable in the "Init" and if it failed, then I will call delte on the object that I instantiated
>>>>>>>>>>

I don't call delte on the instantiated object inside the Init function! :)  That would be when Init returns with an error.  I'd delte the object then (after checking the return code from Init).

William C
Thursday, October 17, 2002

Ed: You are mostly right, except the compiler is *not* technically broken. If a programmer dereferences a NULL pointer, that is undefined behavior. "undefined" means precisely that. The compiler may do what it damn well wants the moment you dereference a NULL pointer, including create a "NULL reference".

And yes, Herb Sutter can articulate all this far better than most of us :)

William: If you have some code that does use exceptions extensively, and it is running too slowly for your purposes, start worrying about it at that point.

radix omnia malorum prematurae optimisatia est.

Just a Programmer
Thursday, October 17, 2002

Esto es alguna mierda loca!

Jack lives over there ->
Friday, October 18, 2002

Gizmo myGizmo = new Gizmo(a,b,c);
...
foo(*myGizmo);

Should be:

Gizmo myGizmo = new(nothrow) Gizmo(a,b,c);
...
foo(*myGizmo);

If we are trying to demonstrate undefined behavior in a conforming implementation.

Also, it's worth mentioning that checking for a null reference is a rather hopeless enterprise - not only because you can't get a null reference, but also because if you have a null reference, there are no guarantees that the test will work.  Example [warning - uncompiled code ahead]:

int * p = 0 ;
int & r = *p ; // Undefined behavior

if ( 0 == &r )
{ cout << "true" ; }
else
{ cout << "false" ; }

What does this fragment do - well, if you are lucky, it will output true.  If you are unlucky, it will output true only when you are looking at it.  A conforming implementation might also output "false".  Or it could launch NetHack - why not?  When true == false, recovery is impossible anyway.

Danil
Friday, October 18, 2002

>>>>>>>>>>
William: If you have some code that does use exceptions extensively, and it is running too slowly for your purposes, start worrying about it at that point
>>>>>>>>>>

Well, of course.  I'm not so "new" that I don't understand that!

Obviously, I gave just one example of a drawback of using exceptions (actually two -- if you include my "stack" spiel).  By me giving one example, it was supposed to "springboard" discussion about exceptions.  Shooting down my one thought as unimportant and skipping the other thought (stack)...I don't think I or anyone reading gained anything! :)  There's probably some drawbacks I'm not aware of...and when you discuss using exceptions...I think you have to discuss the drawbacks. No?

Also, I brought up the point of the environment you are working in.  Like, developing for PDA's.

Start using a bunch of exceptions during embedded development and tell me that it is a good idea (and I bet it probably sloooows down the app considerably -- could be wrong -- like I said, I've rarely used exceptions so far).  We couldn't even use objects the way we wanted to (it's not a good idea, in Palm, to have a bunch of objects instantiated and hanging around in memory).

William C
Friday, October 18, 2002

William,

There is nothing wrong, either tehcnically or style-wise with calling "Init()" from your constructor.  This is a good practice to chose when you have multiple constructors and you want to insure consistency.  Init() should be private within the class, and obviously non-virtual.  Other than that, you're in good stead.

Nat Ersoz
Friday, October 18, 2002

>>>>>>>>>>>
Also, it makes it much harder to use "Resource Acquisition  is Initialization", the C++ idiom that prevents resource leaks.
>>>>>>>>>>

Can you get in depth on this?

Because I don't understand how having an Init function takes away from preventing resource leaks.
------------------------------------------------------

The reason I say this is because this code:

try
{
      Resource1Wrapper rc1;
      Resource2Wrapper rc2;

      do_stuff();
}
catch( ... ) {
  ... recovery code here ...
}

becomes:

    Resource1Wrapper rc1;
    if { rc1.Init() != S_OK } {
        return --- what do I return here? ---
    }

    Resource2Wrapper rc2;
    if { rc2.Init() != S_OK } {
        return whatever;
    }

  actual code

You've got to remember to call init for EVERY SINGLE OBJECT you create. RAII requires that you create a lot of objects on the stack. If every one of those carries this extra overhead, you're going to be less inclined to do it, and try manual resource management instead.

Chris Tavares
Friday, October 18, 2002

Hey, thanks for the reply!

First, just to nitpick, not ALL classes have an Init.  Just classes that might need to do more than variable initialization.

Maybe it's because I'm in Windows world...and I'm programming a lot of dialogs...so I'm used to doing stuff in OnInitDialog (and sometimes not!). :)

Second, your code example,

I don't see a problem with:

Resource1Wrapper rc1;
if { rc1.Init() != S_OK }
{
    return --- whatever this func wants you to return! :) ---
}

Resource2Wrapper rc2;
if { rc2.Init() != S_OK }
{
    return whatever;
}

actual code

The destructor will get called for Resource1Wrapper or Resource2Wrapper because the function will return and the class/object will go out of scope (and if I'm handling resource leaks in destructor, I'm ok).

Third,
>>>>>>>>>>
RAII requires that you create a lot of objects on the stack. If every one of those carries this extra overhead, you're going to be less inclined to do it, and try manual resource management instead
>>>>>>>>>>

I'm sorry...but I got lost here. :)  I don't understand this.

Doing this:
CFoo foo;
is creating an object on the stack.

Doing this:
CFoo m_foo (in my .h)
is creating an object on the stack.

To not create object on the stack I would do something like this:
CFoo * pFoo = new CFoo();

Whether I did it on the stack or not...
I'd still have to do:

foo.Init()
or
m_foo.Init()
or
pFoo->Init()

William C
Friday, October 18, 2002

By overhead, I mean intellectual and effort overhead.

Yes, this is creating an object on the stack:

CFoo foo;

However, if you then have to call an init function, then you haven't REALLY created the object yet, because you can't do anything with it. Therefore, creation becomes a two step process:

CFoo foo;
Foo.Init();

As soon as you add that second step, you add the possibility of forgetting to do it.

Also, since the whole point of having the init method is to return an error code, you should also check the return value, so creation becomes:

CFoo foo;
if { foo.Init() != S_OK ) {
    return xxx;
}

So, to create one object you need at least three statements, any one of which can be messed up or forgotten.

*That's* what I mean by overhead.

Hopefully I've expressed this a little better this time. It takes me a while sometimes. ;-)

Chris Tavares
Friday, October 18, 2002

'Gizmo's constructor doesn't throw an exception if allocation failed and the code ... does not check if myGizmo is a NULL pointer after the constructor is called.'

If that's the case, it's the fault of the compiler for not throwing an exception when allocation fails, which is standard-required.

Jason McCullough
Friday, October 18, 2002

Jason,

Thanks.

So... how did Joel get that NULL reference? Was the exception caught and discarded? Or did the pointer get set to NULL in some other way -- seems allocation would be the way it would happen since it was only in low-memory situations. Maybe the code calling foo did the allocation with malloc() or such?

Or perhaps (most likely?) the work he did at Juno was with a C++ compiler that did not support exceptions or had them disabled?

Ed
Friday, October 18, 2002

Danil: When Joel wrote this code, there were no standards-conforming implementations. It's likely he wrote it on VC++6 or earlier, which by default, returns NULL if allocation fails. (you can also use _set_new_handler to set a function to handle free store exhaustion).

However, I'm not sure why everyone thinks that the problem 'must' have been caused by allocation failing. There are many many times you get a NULL pointer that have nothing to do with resource exhaustion.

And no, checking a reference for NULL is pointless: the horse has already bolted, your program has already exhibited undefined behavior. You're up the creek without a paddle anyhow.

William: My point about exceptions is, it's one of those things where it's difficult to tell how much impact it will have on performance. So, avoiding the root of all evil, you should use exceptions until you know it's affecting the speed of your code. That's the way I do it.

Having an "Init" function is fine, but it should always be private, and called from constructors.

Just a Programmer
Friday, October 18, 2002

"And no, checking a reference for NULL is pointless: the horse has already bolted, your program has already exhibited undefined behavior. You're up the creek without a paddle anyhow."

Excuse me, but wasn't that the point of Joel's article. The one to which you took exception?

Erik
Saturday, October 19, 2002

Erik: No, the point of my argument is that if a reference is NULL it is almost certainly because the program has a typical C++-type bug in it. Not because of dodgy hardware, operating system software, or "cosmic rays man".

Just a Programmer
Saturday, October 19, 2002

>> "cosmic rays man".

Look, I'm tellin' ya...  every writer deserves some poetic liberties in their lifetime.  Just write this one off as such.

No, its not acceptable to write off software bugs as "the hardware made me do it".  But I think the real point of the article was bug fixes versus risk assesment.

Hopefully, I'm not judged too harshly by everything I've ever said...  still in rehab,

Nat Ersoz
Sunday, October 20, 2002

Nat Ersoz: "Cosmic Rays man" is a common colloquialism for it being the hardware/environment's fault. If it really were the environment's fault, I would have no problem with this colloquialism.

On the premise of the article itself, I think this misdiagnosis highlights a problem: Often it is hard to gauge how damaging a bug is. It's not a simple weighing up of the bug being "worth $5000 to fix and costing $20,000" to do so. The cost of the bug and the cost of the fix is always very cloudy, when you misdiagnose it as badly as Joel and his team did, it's cloudy indeed. He even said something at the end of his article about them always fixing all bugs in FogCreek software.

Just a Programmer
Sunday, October 20, 2002

*  Recent Topics

*  Fog Creek Home