Live data from Hacker News

John Carmack's comment on Doom 3's code style

kotaku.com

191–200 of 210 posts

Re: John Carmack's comment on Doom 3's code style

#191

Earlier quoted context omitted.

It strikes me that your argument taken to the extreme is that everybody should program in assembly language because you can do anything, anytime, anywhere. Well, at least as far as control flow structures are concerned. Certainly C is preferable to C++ if you want simple and malleable code. Do you also prefer if-else to switch statements? (I'm not sure.) Do you like to use goto? (I doubt it.) Do you eschew the use of…

Not to mention that it's essential for initializing some constant variables; I have yet to find a better way to do: const int count = argc > 1 ? atoi(argv[1]) : 1000000; For quick test programs where I might want to change some number of iterations without having to recompile, but I also don't want to have to provide an argument every time I run it.

You're assuming that the first argument here is an integer value. For a single, one off, testing haress application I wouldn't worry too much about applying a full-blown semantic code style.

Is there anything wrong with keeping the default value as a separate constant?

  const int kDefaultValue = 1000000;
  int value = kDefaultValue;
  if (argc > 1) {
    value = std::atoi(argv[1]);
  }
  const int count = value;
Personally I much prefer using [program options][1] from the boost project (since we are talking about C++ here). Most projects already have this as a dependency, and its quite easy to setup. It also properly handles your types.

[1]: http://www.boost.org/doc/libs/1_52_0/doc/html/program_option...

Re: John Carmack's comment on Doom 3's code style

#192
post #165
post #123

Earlier quoted context omitted.

Precisely. The real reason Python gets this right is that it the properties feature lets you write `obj.foo` but still call a `getFoo` method behind the scenes.

C++Builder and Delphi offer this too, with the '__property' declarator.

As someone who writes C++ regularly, I would love to see something like __property introduced in C++15.

Re: John Carmack's comment on Doom 3's code style

#193
post #25

Earlier quoted context omitted.

void up_front_decls() { float some_var; int another_var; some_var = get_some_var(); do_some_calculations(some_var); maybe_something_else(&some_var); some_var = get_another_var(); do_some_other_calculations(another_var); blah_blah_already_broken(); } void as_needed_decls() { float some_var = get_some_var(); do_some_calculations(some_var); maybe_something_else(&some_var); int some_var = get_another_var(); // compile-ti…

Your up fornt example isn't a result of poor style it's the result of a bad programmer. Assigning the right values to the right variables is the most basic of programming concepts. Sure typo's and bugs happen, I've done it too but it's still a programmer error not style error.

Any style that encourages errors is a bad style. Yes, it's possible to make the code correct and still use up-front declarations. It's also possible to make the code correct while using a 10k-line main() littered with gotos. It's still a very poor programming style.

People make mistakes. Practices should be built around this fact, not built assuming people could be perfect if they just tried a little harder.

Re: John Carmack's comment on Doom 3's code style

#195

Earlier quoted context omitted.

Not to mention that it's essential for initializing some constant variables; I have yet to find a better way to do: const int count = argc > 1 ? atoi(argv[1]) : 1000000; For quick test programs where I might want to change some number of iterations without having to recompile, but I also don't want to have to provide an argument every time I run it.

You're assuming that the first argument here is an integer value. For a single, one off, testing haress application I wouldn't worry too much about applying a full-blown semantic code style. Is there anything wrong with keeping the default value as a separate constant? const int kDefaultValue = 1000000; int value = kDefaultValue; if (argc > 1) { value = std::atoi(argv[1]); } const int count = value; Personally I much…

Perhaps I should have clarified: when I said quick test program, I was referring to something I would write to convince myself of some minor detail (sometimes just checking compiler warts or algorithm performance) and that piece of code would never be seen or run by anyone but me. I know that the first argument will always be an integer, because I'm the only one who will pass it arguments! I'm also (kind of unreasonably) a const nazi. So given the option, where I can take a shortcut (I know, bad, bad programmer), but still do "proper" programming (consting everything by default is my SOP), I'll do it. And I'll never release that code (I'm starting to regret posting that snippet here . . .).

I will agree, though, option parsing libraries are a definite must for released software. I like Boost, but using even small parts of it tends to pull everything in, and at least for my current project, we are trying to minimize dependencies (it's a library). I had to fight for Boost::regex, and only got it as a fallback for compiler versions that don't have regex.

Re: John Carmack's comment on Doom 3's code style

#196
post #69
post #45

Earlier quoted context omitted.

> A lot of the practices here are enshrined in the Google C++ styleguide: with the notable exception of lining up things horizontally, which tends to be frowned on.

I really do not understand why they chose to do so. In my opinion, it does not improve readability at all, even worse, when the spacing between type and name gets big , your eyes need more work to figure out the correct line relations. Furthermore, this can generate horrible commits, for example: int x; int y; becomes: int x; int y; float z; after adding ONE single variable. But your commit will contain changes for t…

You usually aren't looking for a line based on the type... you're usually looking for a specific variable... with your variables lined up, that portion becomes faster... scanning for y in your second example without the variable declarations lined up for example. This advantage outweighs the slight hinderance of the separation on a given line. That, and many editors will highlight the line with the cursor on it. Which alleviates the issue you point out a bit.

Re: John Carmack's comment on Doom 3's code style

#197
post #69

Earlier quoted context omitted.

I really do not understand why they chose to do so. In my opinion, it does not improve readability at all, even worse, when the spacing between type and name gets big , your eyes need more work to figure out the correct line relations. Furthermore, this can generate horrible commits, for example: int x; int y; becomes: int x; int y; float z; after adding ONE single variable. But your commit will contain changes for t…

I do use vertical alignment, but that's not necessarily how I'd align the above lines. Assuming y and z are related, but x is not, I'd do them like this: int x int y float z I might add a blank line between x and y, too. If you do vertical alignment such that it emphasises semantic relations, you avoid commits that change more than they should, and it also helps draw your eye to relationships between variables.

I'll make exceptions myself if there is one declaration that is just way longer...

    int   x
    int   y
    float z
    MyReallyLongTypeHere foo;
Other than that, I tend to prefer having the variable names line up. Though doing mostly JS and C#, I can use var pretty much anywhere an assignment happens, even with null initialization.

    var foo = (sometype)null;
The bigger issue to me is comma first vs comma last... I find that comma first is easier to notice a missing/extra.

Re: John Carmack's comment on Doom 3's code style

#198

Earlier quoted context omitted.

You're assuming that the first argument here is an integer value. For a single, one off, testing haress application I wouldn't worry too much about applying a full-blown semantic code style. Is there anything wrong with keeping the default value as a separate constant? const int kDefaultValue = 1000000; int value = kDefaultValue; if (argc > 1) { value = std::atoi(argv[1]); } const int count = value; Personally I much…

Perhaps I should have clarified: when I said quick test program, I was referring to something I would write to convince myself of some minor detail (sometimes just checking compiler warts or algorithm performance) and that piece of code would never be seen or run by anyone but me. I know that the first argument will always be an integer, because I'm the only one who will pass it arguments! I'm also (kind of unreasona…

I wasn't lambasting you, and I wouldn't ever regret posting a snippet. It helps drive the conversation.

I understand and agree with Boost injecting a whole lot of dependencies, and for a small testing library or executable I would probably got the same route that you did. I'm also a pedantic const nazi at times, and merely replied back as it makes me feel that, in some else's code, they may find this useful.

If you take a look at the Doom3 code there are even places where they stray from the code style guide when it makes sense. I'm more of a proponent of "in the moment" styling to make sure that it matches the rest of the project, or at the very least, component that I am working on.

Re: John Carmack's comment on Doom 3's code style

#199
post #51
post #50

Earlier quoted context omitted.

Bravo. That comparison makes worrying about vertical space seem ludicrous.

Ugh. I prefer the Carmack version. This example turns the code into something that appears more airy but in fact is much harder to understand due to extensive use of ? :. I find that one of my own major steps toward programming maturity happened when I stopped doing goofy things like this and started writing code that was as simple as possible to logically follow, and that was as un-special-cased as possible. (By thi…

If / else is a way of defining what to be executed based on some condition.

The ternary operator is used to guarantee assignment to a variable based on some condition. It's not only a way to save space, it's a way to express your intent clearer. It simply doesn't leave any undefined code path behind.

In your case of changing the code a bit, in the carmack version of the function there's a risk that you remove the assignment to sides[i] in one case and it will later be undefined.

Though i agree that the syntax is horrendous since it requires you to remember exactly what the symbols ? and : do. Compare to the much nicer and to a newbie understandable python syntax: x = y if c else z

Re: John Carmack's comment on Doom 3's code style

#200

Earlier quoted context omitted.

I'm kind of the same opinion as Carmack re: getters/setters. My feeling is, if all you're going to do is allow clients to read and write the variable, why not just expose it? Sure, you can argue encapsulation and even justify it by saying that later down the road you may want to change the implementation, but far too often I've seen C++ classes with a setter and getter for every variable, for no good reason (eg, they…

One (maybe stupid?) reason why I really like getter/setters has nothing to do with encapsulation, but that it makes it easier to search for places where a variable is changed. Often you have lots of getFoo and little setFoo functions - so just searching for "Foo" will return lots of results while "setFoo" helps me finding those faster.

Most editors with an indexer solves that automatically with "find all references". They can usually even order by "read occurrences" and "write occurrences"
Post reply on HN