Live data from Hacker News

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

kotaku.com

201–210 of 210 posts

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

#201
post #189
post #118

Earlier quoted context omitted.

Do you have a link to the source for that? I'm curious to read. If your description is accurate, Rust[1] is exactly what he wants. I've been learning Rust recently (with a little help from [2]) and it does a ton of static code analysis, is safe by default (no dangling or null pointers, no shared mutable state), uses Hindley-Milner type interface just like Haskell, and generally is what you would expect if Haskell and…

He sort of alluded to it, but there's the usual perceived tooling/ retraining/hiring / performance ceiling issues for shops with > N devs, N somewhere between 5 and 25 (I don't agree with his arguments, just repeating them) http://gamasutra.com/view/news/169296/Indepth_Functional_pro... http://www.reddit.com/r/haskell/comments/jap3x/im_very_tempt... http://blogs.uw.edu/ajko/2012/08/22/john-carmack-discusses-t...

Oh of course, it's far from trivial to switch to a new language. But if you're writing code you'll still be using in 10 years, the maintainability benefits of a safer language like Rust could be pretty huge. Also, Carmack switched from C to C++ not too long ago.

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

#202
post #131

Earlier quoted context omitted.

Some arguments in favour of getters and setters are; that using a function allows for the addition of caching, addition of thread safety checks, changing to compute the variable rather than store it, addition of logging, mapping it to be generated from another variable, etc.

I understand all of those justifications. When I mentioned changing implementation in my post, I was thinking of exactly those sorts of things. But none of them seem to be applied in the general case of "make a pass-through getter and setter for every member variable". My biggest question to the answer of universal getter/setters is "what is being abstracted?" Classes (and objects) are meant to abstract things like a…

I tend to not mind using getters and setters, but I don't create one for every internal variable in a class. I consider "universal" getters and setters (which I take to mean one getter and setter for every variable in every class) to be an absurd idea, like something taken to the logical extreme just to piss someone off.

Perhaps a lot of people don't like using or writing getters and setters because it's cumbersome if the only code in them is an assignment/return statement. Maybe something like providing Ruby's attr_reader/attr_writer/attr_accessor to create these boilerplate getters and setters is what is required. Also in Ruby all member variables are private, so methods are always needed to access them.

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

#203
post #193

Earlier quoted context omitted.

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.

Have you ever seen a bug caused by this? I haven't. At least anecdotally, this is purely stylistic, and has no impact outside of personal preference.

With one caveat: Heavy constructor/destructor use requires it.

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

#204
post #119

Earlier quoted context omitted.

Any style of programming can look like a mistake if you take it to crazy extremes. I find header/template C++ programming works very well provided you do it in moderation and keep things simple. Remember the STL is complicated because it tries to be super generic, and it tries to be super generic because it's a library so it tries to cater for all possible uses. If you're writing a program instead of a library, you c…

For other examples of crazy extremes, see : Java Swing using anonymous classes to 10 or more depths to represent callbacks because OOP and inheritance > all. Haskell having one file IO operation a thousand feet below the surface of a program "un-purifying" the entire call stack with side effects because pure functional is king. Trying to implement any generic anything in C, because in procedural having template or in…

> Haskell having one file IO operation a thousand feet below the surface of a program "un-purifying" the entire call stack with side effects because pure functional is king.

And that's the way it should be. (Refator your programme, if you want to keep the other functions pure. But it is a Good Thing (TM), that you can not hide your IO if you pile on enough layers.) Haskell has other problems, though.

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

#205
post #78

Earlier quoted context omitted.

Haskell is a special beast, in the sense that it uses single letters a lot for generic types in signatures. Eg: doFoo :: a -> a where doFoo will take any type a and return something of the same type. Due to the density of the language, you'll often find plenty of small, commented functions.

Compare doubleCompose binary_func transformation first_arg second_arg = binary_func (transformation first_arg) (transformation second_arg) vs doubleCompose (b -> b -> c) -> (a -> b) -> a -> a -> c doubleCompose (+) f x y = (f x) + (f y) (also known as the `on` function). There's hardly any good names for x and y, since they can be anything at all.

Our guidelines at work are: The more polymorphic a variables type, the shorter its name can be.

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

#206

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.

A only slightly more complicated regex can look for Foo on the left-hand side.

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

#207
post #203
post #193

Earlier quoted context omitted.

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.

Have you ever seen a bug caused by this? I haven't. At least anecdotally, this is purely stylistic, and has no impact outside of personal preference. With one caveat: Heavy constructor/destructor use requires it.

Yes. I have absolutely seen bugs caused by the wrong variables being assigned to. I've seen it especially with loop variables. jaegerpicker indicates that he's also caused bugs by assigning to the wrong variables.

Not sure what you mean about "heavy constructor/destructor use" requiring this style.

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

#208
post #116
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…

I would argue that if declaring up-front versus declaring as-needed makes a significant difference in readability, then your functions are too long.

Except for loop counters. Being able to do:

  for (int i = 0; i 
vs.

  int i;
  // Half a dozen lines
  for (i = 0; i 
makes a big difference to me.

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

#209
post #113

Earlier quoted context omitted.

"a function can still be pure even if it calls impure functions, as long as the side effects don’t escape the outer function" This is a very good point that probably could be systematically exploited. Does anyone know examples of this?

In Haskell there is the ST monad can be used to write stateful implementations for pure functions. The type system guarantees that side effects can't escape their scope. http://www.haskell.org/haskellwiki/Monad/ST

Although this is great information I primarily had 'less pure' languages' in mind when I asked.

Come to think of it, restricting mutable access to only the relevant objects as per function call using const seems to allow just this!

A function having only const input and output "should be" free of side effects (if no global mutables); while still being allowed to run all manner of unpure processes local to its own calling context.

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

#210
post #200

Earlier quoted context omitted.

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"

VS2010 and C::B both don't seem to allow that ordering. So not a solution for me, but certainly could be other IDE's support that.
Post reply on HN