Project Good Robot 23: Programming Paradigms

By Shamus Posted Friday Oct 11, 2013

Filed under: Good Robot 149 comments

I didn’t add much in the way of new stuff this week. I spent a lot of time refining and polishing and bug-fixing, hoping to get a new build out to my testers* before the weekend. I’m spending a lot of time fussing with stuff I’ve already written about.

* For the record: I’m SLOWLY adding to my list of testers. I know people will get sick of playing the same broken game week after week, so I’m trying to add new people as the old ones lose interest.

So! Let’s talk about something controversial. Even better: Let’s talk about something incredibly controversial to programmers, and completely tedious, esoteric, and impenetrable to non-coders! Let’s talk about programming paradigms. Some people have asked about how my program is structured, and since I know the answer will leave some people deeply offended, I might as well discuss the “why” before I get to the “what”.

Just to bring normal people up to speed:

At first, basically all programming was imperative. Programs would be structured in the form of do thing1, do thing2, do thing3, etc.

UseCover (space_marine);
DoShooting (space_marine, machine_gun);
DoYelling (space_marine, gravel_voice);
DoGrumpyFace (space_marine);

Or whatever.

The idea being that in the above code, space_marine is probably a structure of properties. Like:

space_marine.name = "Mister Chief";
space_marine.bullets = 999;
space_marine.hitpoints = 100;
space_marine.run_speed = 1;
space_marine.height = 1.8;
space_marine.dead = false;

By calling this code, you’re doing things TO the space marine. Also that code might also make changes to other things that are NOT space marines. Basically, you can’t look at this code and know what parts of the game state might change. Maybe nothing. Maybe many things. The space_marine might die. It might win the game. It might trigger a change to the next level. It might destroy a dozen other in-game things. As a programmer, you just don’t know how the state of the game might be changed or what sort of things might happen. You have to read the source. This is technically true of all languages except for a few built around the functional programming paradigm, but its particularly true of imperative languages.

The problem we have is that in a big project, our marine will end up having a LOT of properties. In Good Robot, each robot has over 50 properties like this that keep track of what the AI is thinking, when the weapons are ready to fire, how it’s moving, etc. And this is a simple little 2D game. In a 3D game with more complex geometry, multiplayer, tons of weapons, vehicles, and multiple game modes, we’re likely to have a lot more.

In imperative programming, we’re likely passing around this space_marine variable to every system that needs it, and any system can make changes to any part of it. So maybe some other programmer comes along and writes the grenade code. Not understanding this structure I made, he just subtracts damage from hitpoints and calls it a day. The problem is that he doesn’t update the “space_marine.dead” variable. So now we have a bug where grenades can damage you but they can’t kill you.

Maybe he wants the grenade to blast you up in the air, so he just adds a bit to the “space_marine.height” variable. Except, that’s not how that variable is used. It’s not your height off the ground, it’s how tall you are. So now we have a bug where getting blasted with a grenade makes you incrementally taller.

The problem here is that ANYONE (any programmer working on any section of the code) can make changes to a space_marine. And thus everyone needs to have complete knowledge of how a space marine works, what all the variables mean, and how they inter-operate. You end up needing every programmer to understand every system in perfect detail, and that’s just not reasonable. It’s not even possible in most cases.

Worse, you’ve got a lot of side-effects going on. When someone notices that one character is slightly taller than another, they do some testing and find their space marine is 30cm taller than he should be. How did that happen? Anything that interacts with a space marine would have access to those variables. Which system is fiddling with the height? Saving the game? Starting a new match? Entering or exiting vehicles? Something with networking? Running, jumping, using cover, picking up weapons, dying, using guns, melee attacks, taunts, dying, leveling up, rendering, being healed, being damaged, chatting, or performing emotes? It could be ANYWHERE in the game. Have fun finding it.

So then we have Object-Oriented programming. The idea is that we lock away all those marine properties and other programmers can only interact with the marine through the interface:

space_marine.Damage (grenade_damage);

So other programmers can’t modify hit points directly. They don’t need to know that the variable “hitpoints” exists, how it’s used, or about the “dead” flag. They just send damage values to the marine and the marine object takes care of the fussy details. It knows to kill itself if its hitpoints drop below 1, and it knows what animations to kick off, scores to change, weapons to drop, etc. Other programmers don’t need to know any of it. If another programmer wants to blow the space marine up in the air with an explosion, they won’t have access to the “height” variable but they will see something like…

space_marine.Shove (direction);

…and realize THAT’S what they should be using to shove the marine around the environment. The object’s interface will guide this other programmer and stop them from doing something destructive.

This process of hiding the inner workings of an object is called encapsulation. This is a good solution to the above problems. It is not, however, a good solution to every problem.

Java adheres to the Object-Oriented paradigm with unwavering strictness. Everything is an object, owned by an object, owned by an object, yea, even unto the nth generation shalt thy objects be owned.

So you end up with this thing where you’ve got a “game” object. Just one. And it owns a “game session” object, which owns a “level” object, which owns a list of “space marine” objects.

Okay, fine. Now we’ve sealed everything off so there aren’t any side-effects, every object is owned by another, and objects can’t change each other. The problem is that there aren’t any side-effects, every object is owned by another, and objects can’t change each other.

Like, if I want my space marine to create a little cloud of dust when he stomps on the ground, who owns that? If the marine owns it, then killing the marine will make all of his dust particles instantly vanish, which would look odd. If he kicks off a sound effect, I might not want that sound effect to die with the marine. If he’s supposed to drop his weapon on death, then marines need to be able to give the object to some other system.

Obviously we can’t have marines owning their own visual effects, sound effects, and particle effects. So we have to… what? Make a “sound effect” object and have it owned by… who? The game? The level? Should we create some master sound-owning object to act as an MC for all the sounds the game is making? Should we make a particle wrangler that keeps track of all the particles?

If we make one particle wrangler object that’s in charge of all particles, then we’ve basically re-created all the old C-style imperative design but now it’s just WAY less convenient to use. We can’t just call PaticleCreate (stuff), we have to get the game object, which will give us the session object, which will give us the level object, which will give us the particle wrangler.

Also, my space marines need to collide with each other. Collision is incredibly complex. To collide A with B I need access to the polygonal structure of both, the skeleton of both, the current state of both, what each one is doing (I shouldn’t be able to shove someone if they’re attached to a mounted turret or behind the wheel of a car) and how they’re currently moving. Do I have the level object (which owns all space marines) run the tests and make the marines bounce off each other? But then we would need to expose all of the inner workings and logic of the space marine, which is exactly the thing we were trying to hide. Or do we have marines themselves try to bump into each other, in which case each marine needs to be able to find all others, meaning marines need access to the data structures of their owner. We also need a way to avoid duplicate tests so that once we test for A colliding with B we don’t waste CPU testing if B has hit A.

No matter which way you go, you have to poke some major holes in your encapsulation to do this efficiently, and we’ve just scratched the surface.

Weapons need pointers to the marines carrying them, vehicles need two-way access to marines so they can both be driven by and run over them. Marines need access to each other and all the other objects in the game. They all need pointers to the game object so they can access game rules, but they also need a pointer to the current level so they can do collision with the level geometry. And even though the game owns the level, you probably want direct pointers to both since drilling down through levels of pointers owned by pointers can cost you performance if you do it enough times (many objects) or if the layers of objects-owning-object-owning object is annoyingly deep.

In the end, we’ve imposed this rigorous top-down structure and then we spent days or weeks writing code to get around or through it. In a world of pure theory, an object hierarchy makes perfect sense and there’s always a “right” way to do things. Objects can hide behind their interfaces and we never need to worry about their innards. In practice, the right way is not always clear and even if you’re lucky enough to nail it, you may find it requires many transgressions against object-oriented design. You can end up with something that’s just as unsafe and exposed as imperative programming, while also being more cumbersome, convoluted, and perhaps even slower.

In a lot of cases, those “protective layers” of OO design don’t actually protect you from anything, because you have to poke so many holes in it that the thing no longer serves the intended purpose.

All of this is to say: I am not a purist when it comes to OO design.

For years I thought I was bad at OO programming. But then I realized that some problems just don’t lend themselves to an OO solution. In my own code, I manage to infuriate all parties by mixing C++ style object-oriented design with C style imperative. If I’m going to make many of something (robots, sprites, lasers, explosions) then those things are a class. If I’m making ONE of something (like the game, or the gameworld) then it doesn’t use any kind of class interface at all.

This makes it easy to manage large groups of things, but also prevents me from accidentally making more than one of something when more than one would violate the design and common sense.

A good example is the player. Right now you call PlayerUpdate () to process player input. This performs non-repeatable actions and creates state changes in the I/O. Sure, I could make a class Player p; and call p->Update (); but that would make no sense. Like, if you had more than one player object, the first one would eat all of the mouse and keyboard input, leaving no clicks, mouse movement, or key presses for the other. Having more than one player is an impossible and nonsense state, so why make it possible? The presence of PlayerUpdate () makes it really clear how this should be used.

Q: But Shamus, what if you wanted to make the game multiplayer?

A: Then I’d have to re-write the player code. That would be true regardless of whether or not I was using a class interface. Since multiplayer isn’t even being considered, I don’t see any percentage in spending time making it easier to add features that I’m not going to add. That’s like spending money to put a boat hitch on every car you own, just in case you end up buying a boat someday.

Boom! Crappy car analogy. It’s been too long since the last one.

Getting back to classes. Even when we DO want more than one of something, that doesn’t mean I’m going to make it a full-fledged class.

If something is a container for variables (like XYZ vector data or RGBA color data) then I make it a struct with public members. Making wrappers for individual entries in this case makes no sense to me. When I was using Qt, I didn’t bother with their built-in vector types because some silly OO zealot thought that this code…

pos.x = pos.x - (pos.y * pos.z);

Would be SO much better as:

pos.SetX ( pos.GetX ( ) - (pos.GetY ( ) * pos.GetZ ( ) );

Oh man. That still drives me crazy just looking at it. What’s the purpose of that stupid interface, anyway? If that’s a good idea, then why not:

int a.Set (b.Get () + c.Get ());

…instead of a = b + c? So much safer! Screw convenience and compact clarity, we must mindlessly adhere to class-based orthodoxy!

My rule of thumb is that if variables change each other (say, setting “m_age” will impact the value of bool m_is_senior_citizen) then it needs wrappers and the members should be encapsulated. But if the members are independent then it’s just a container for values and the other programmer should be trusted to know what they’re doing. A class interface is there to hide complexity. But if there is no complexity then the class interface might hide the fact that there is no complexity!

So to answer the question:

Robots are a single class. The only “fancy” object inheritance stuff I’m doing is I’ve got a base class from which bullets, missiles, explosions, and powerups, are derived. Objects in the program can create these entities and then hand them off to the world management code in world.cpp.

So that’s it. Mostly C-style structure with a few dozen C++ classes being thrown around. In places where I do use classes, the interfaces are very tight.

 


From The Archives:
 

149 thoughts on “Project Good Robot 23: Programming Paradigms

  1. Kyte says:

    Hey, don’t fault OO when the languages are too crappy to not implement properties like they should. :V

    More seriously now, the thing is that in most projects what starts simple might not always end up simple, so having everything in props means you can add whatever logic you need (notifications, events, validation, synthetic properties, data binding, logging, whatever) afterwards without breaking compatibility.

    It also allows different accessibility levels for getter and setter, allowing things like immutable structures by making all setters private. (Personally I hide all the setters that I don’t expect others to be changing. In your collision example, for instance, details such as polygons and skeleton ought to be purely read-only from the outside.)

    In general the benefits don’t really show in 1-man projects where you control the entirety of the source, but then again, Java was made for enterprises.

    The sane languages will make sure to write the boilerplate for you.
    Sadly, C++ and Java don’t fall into that category. (I kid, I kid. But seriously, Java’s got to shape up.)
    (One could argue C++ is a very bad OO language, at that, but I’ll leave that for others who know in more detail)

    Personally, I disagree with your idea of ownership. Particle effects shouldn’t belong to anybody but the particle system. Same with sound effects and so on. This is not just because of OO thinking, but it’s simple logic. Somebody is gonna have to coordinate everything, and that somebody will be the owner.

    1. Atle says:

      Interestingly Python goes the opposite way, where you cannot make a property private, even if you want to (a truth with some modifications). So what is the right way? (Rhetorical question not ment to be answered, merely reflected upon.)

      1. Ingvar M says:

        The Right Way is to have a naming convention saying “Think X is not exposed surface, so if you use it you are SO on your own” (like, say, the “_foo” thing in Python or simply not exporting a symbol in Common Lisp).

        That way, people can peek under the hood if they need to, but are well aware of the fact that they’re inherently relying on unstable things.

        1. Atle says:

          I’ve not uses Python very much, just barely touched it, but I like the “it’s your responsibility” approach. But I also know that I’ve more than once wished for public read only attributes in C++ to have full control while avoiding getters and setters.

          But maybe this is not important to good object orientation designs anyway.

      2. Shivoa says:

        (None of the following is prescriptive commentary. Use whatever languages however you and any co-workers agree on a system, and write a style and conventions guide so if someone inherits it they can understand why you did it that way. There is no one true way; unfortunately there are many wrong ways: untangling this is far harder than coding working systems.)

        Python is an interesting language (eg mandatory stage when a function is called in Python: look at what calling means in the current context and what is available to tie to that call – so this can be defined by your program and you can write custom scope rules for your code; it isn’t like Python hard-codes calls/jumps destinations to be fast if you don’t subvert the default handling because the current context is always run-time defined) but the fact that the underscore convention exists indicates a very widespread desire for having a system of property privacy levels.

        In large projects (if I’m using an OO supporting language) I’m quite happy to abstract the data in the RAM from all my interfaces. And then you have to look at where full OO gets you. Take the pos example above. Say I find out my physics system needs twice the resolution my current position data can provide, I need to halve the max distance to double the density of ints in the space I care about. Only the Physics system cares but as the pos data lives with the owner objects then I need to change them.

        The Shamus code requires every point where the pos data points are interacted with the be changed to deal with this difference in what 1 meter in the game means in underlying RAM terms.

        Getters and Setters mean that I don’t need to go around changing scales of everything, I just change my methods in the objects that own pos data. This is why people pay the price (and some languages have very good semantics for making this normal and free for default getters/setters).

        If the pos data was abstracted to a class so everything talked about it in terms of a meter in the game engine then you’d only have on place where the underlying RAM information was being poked at and one change to the code would allow your physics system to get more fidelity of recording all game element positions.

        As to how to do an OO look at particles and sounds: who owns them does answer itself from the use case. The marine doesn’t kill his smoke and sound but the level (thinking traditional game levels, not streaming game level blocks – but even then I think it still mostly applies) sure does. There have been more than 0 games released where changing level did not kill all the particle and sound elements that it should have owned, with amusing results. But in the more general case strict OO hierarchies may not always work and also may not be optimal for thrashing similar data in RAM when that is needed. I just think it needs a better example than that to make the case.

    2. Simon Buchan says:

      While I would like proper properties in C++ you get the 90% case since you can make something not writable by making it const….

      void can_modify_bob(bob_t* bob);
      void can_not_modify_bob(const bob_t* bob);

      Which is something I miss in literally *every other language ever*. The only way this could be a better setup is that it’s constant by default. (Similarly, “by value” for everything by default with the *option* of referencing is incredibly useful too, and something I miss all the time)

      I’m not claiming to know why C++ hasn’t added properties, but I would guess from my experience that they wouldn’t be a very good fit given C++’s features, for example you can’t make a pointer or reference to a property, and compound operators (+= and friends) would be very hard to specify correctly and without being bad for performance (consider changing the transform of a few 100,000 particles). The C++ equivalent seems to be a method returning a proxy type (iterators are a particularly common proxy for weird pointer-like behavior) or just a reference to a backing variable if that’s enough (like container back() functions). In short, not having properties isn’t a big deal. In fact, I would rather have C++ style types in C# (or whatever) than properties in C++: I’ve defined property change notification setters *far* too many times, being able to simply have observable<int> or whatever that is otherwise indistinguishable from int would be soooo much nicer.

      1. Nathon says:

        Lots of other languages have const. There’s C, Ada, Go, D (which also has immutable), not to mention all the functional languages where all variables are immutable. It would be cool if you couldn’t just cast it away in C++ though. I’m not saying it’s worthless because it’s an incredibly useful tool, but this code:

        int foo(const int *bar) { return baz((int *)bar); }

        should be a shooting offense. It should also raise a compiler warning.

        1. Atle says:

          Not to mention PHP where const is implicit, and you have to pass by reference if the function should be able to modify an object.

          Different solutions solves the same issue.

          1. Alan says:

            Passing by reference versus value is a different issue than the ability to mark a variable as being const. C++ is identical to PHP in this area: pass by value by default, optionally pass by reference. As far as I know, PHP lacks the ability to pass by reference for speed (to avoid copying a large data structure), but mark it as const so you know the receiving function don’t mess with it. Or to simply mark a variable as const so you know that no one accidentally changes the value of PI.

            1. Atle Pedersen says:

              Actually, it’s a little bit different. Pass by reference in PHP is equeal to pass by reference in C++. But default in PHP is a little bit different.

              Superficially it’s like const. You cannot change the variable that is passed. If you want to, you must pass by reference.

              But you can change the variable for the local scope. When you do, PHP wil create a copy on demand. But this is lost at the end of the scope. This is true for any variable, array and object.

              But when it comes to an object you can modify its attributes. You cannot set the variable to another object though.

              1. Alan says:

                Am I understanding this correctly?

                – If I explicitly pass by reference, the function can manipulate the variable/array/object (VAO). When the function exits, the caller will see the changes to the VAO.

                – If I pass normally, the function can manipulate the VAO, doing so will cause at that point a copy to be made. When the function exits, the caller’s VAO is guaranteed unchanged.

                Assuming that’s correct, to my mind the distinction from pass-by-copy is academic, it’s a sort of optimization to avoid unnecessary copies. (And depending on the code in question, possibly a very good optimization! Of course, I love fork()+copy-on-write shared memory, so I may be biased) As far as the code I write cares, I can treat it exactly identical to pass-by-copy.

        2. Kian says:

          const_cast is evil, but it’s a necessary evil to get around bad programmers’ code you can’t modify for whatever reason. Say you are using a vector library that didn’t care about const correctness, and the vector has a Magnitude() method that doesn’t modify the state, but wasn’t declared const. So you have a function that takes a const reference to this vector, and you need to know it’s magnitude. Without const_cast, you’d have to remove all const correctness from your own code (insane), or create a copy (ugly, a possible performance hit for large classes, a possible source of errors if your class is particularly complex or is part of a virtual inheritance chain, and impossible if the copy constructor is defined private or protected). With const_cast, you avoid this problem.

          The point being, while you can use it in evil ways, you should only ever use it to call methods you KNOW won’t modify the internal state of the object.

          I only wish c++ defaulted to const and const& for methods and parameters.

          1. Nathon says:

            Sure, it’s necessary in C++ because C++ lets bad (and sloppy) programmers get away with things that it shouldn’t. Pointers should be restrict by default and formal arguments should be const by default. Ada, for example, doesn’t have this problem because function formal parameters are in, inout, or out. If someone says that their library function accepts an inout parameter X, but doesn’t modify X, they’re still telling you not to pass in something that you want to be const because some future version of that library call is allowed to modify that piece of memory.

            1. Kian says:

              Well, it’s necessary in C++ because that was the way C treated const, and C++ was supposed to be a superset of C.

          2. Zukhramm says:

            This is why I don’t do C++. I can’t understand a word, but I’m pretty sure I don’t want to know.

    3. Bryan says:

      > having everything in props means you can add whatever logic you need (notifications, events, validation, synthetic properties, data binding, logging, whatever) afterwards without breaking compatibility.

      But, uh, you *will* break compatibility if you do this. It’s just like Shamus’s example of multiplayer. :-)

      Even something as simple as adding logging is changing the interface: you now have to point the class at something to accept the log messages (that is, a file descriptor somewhere, probably wrapped in a bunch more OO), and you’re changing the time required to get or set a given property, because (a) disk is slow, (b) you can’t just buffer the log messages in memory because of crashing bugs, and (c) even if you do buffer them in memory you have to eventually flush that out before the machine runs out of RAM.

      So now instead of taking an immeasurably small amount of time to change a robot’s X position, it takes an immeasurably small amount of time most of the time, and 100ms to flush all the logs out every so often. This is a problem. :-)

      Basically: *All* abstractions are leaky. Better to have fewer of them, all else being equal. For some things it makes sense to abstract away most of the interaction in a class, and for some things it doesn’t.

      (However, yes, you’re right — it does depend on how many people you’re working with, as well as how good they are…)

      1. Kyte says:

        Some functions are more transparent than others, yes. Logging will take time, but that’s because of the existence of the system itself.

        What I meant is that if your component is a DLL or such, you can change the underlying logic without forcing the consumer to recompile. It’s binary compatible in addition to source compatible.

  2. Jed says:

    I found that to overcome the limitations of OO for games, many studios use some sort of Entity System (ES) with OO programming.

    In an ES, an entity is a sum of component, each component being a data structure representing an aspect (like “is able to move” or “has hitpoints and can die”), while systems perform the logic on all entities (like “update the hitpoints of all entities with hitpoints”). This requires a different design approach and can still produce some convoluted code (usually around the retrieval of a particular system/entity) but gives easy to write, modular and very reusable code.

    For those interested, more info on ES here: http://entity-systems.wikidot.com/

    Some examples of game engines using ES: Unity and Merkurius (my java open-source engine based on the Artemis ES.

    1. Ed Lu says:

      Yup, pretty much this.

      I’m one of those guys who obsesses over getting the perfect design when programming – so much so that I often can’t move on with a project because I can’t decide on what direction to take. It’s a terrible thing. When I discovered ES, it was like a light shining through the clouds. Just about every design decision I made to do with my game was made easy.

      There are still gotchas with the architecture, but I’d say it’s a hell of a lot better than trying to do OOP.

  3. Atle says:

    Good object oriented programming is hard. For someone self thought it takes years.

    Just today I read something by Linus Torvals (the creator of Linux) on git and using C (not object oriented) instead of C++ (object oriented):

    C++ is a horrible language. It’s made more horrible by the fact that a lot
    of substandard programmers use it, to the point where it’s much much
    easier to generate total and utter crap with it. Quite frankly, even if
    the choice of C were to do *nothing* but keep the C++ programmers out,
    that in itself would be a huge reason to use C.

    So I’m sorry, but for something like git, where efficiency was a primary
    objective, the “advantages” of C++ is just a huge mistake. The fact that
    we also piss off people who cannot see that is just a big additional
    advantage.


    http://harmful.cat-v.org/software/c++/linus

    There is a lot of truth to this. While good object oriented design is fun to code, it is also very easy to produce horribly messy applications.

    My advice to anyone wanting to program object oriented is to use test driven development. When your objects has to fit and work both in your program, and the test environment, you are forced to avoid some of the pitfalls and bad design traps of OO.

    1. Mephane says:

      The funny thing is, the “bad C++ programmers” are most of the time those that unknowingly attempt to write C code in C++ without knowing how to do neither good C++ nor C. Who hand around raw pointers yet have no idea when they are deleted. Who write the same 5 lines for the same low level string operation hundreds of times, instead of either putting them in a function or using a function already provided by the standard library or some other library that you are using anyway. Who write classes with members that are dangerous to naively modify from the outside yet don’t declare them private nor provide member or free functions to modify them properly, but litter their code with a dozen variants of the same sequence of operation.*

      If C++ did not exist, the same people who keep bashing C++ as a whole would merely have a harder time bashing bad C programmers as an abstract, inconsistent fuzzy group of people that is much more difficult to point your finger.

      Well, it were funny if not for all the hostility involved, which I never understood and probably never will. Why can’t we just have favourite languages and accept that other people prefer different languages for many different reasons?

      —–
      *Imagine in Shamus example, whenever the space_marine receives damage, there is always is the code
      space_marine.hitpoints -= damage;
      if (space_marine.hitpoints <= 0)
      {
        space_marine.hitpoints = 0;
        space_marine.dead = true;
      }

      repeated dozens of times, sometimes with minor or major bugs; like checking for < 0, leading to sometimes characters ending up with 0 hitpoints yet still alive. Another place will omit space_marine.dead = true altogether, but then another place does not check that variable, but space_marine.hitpoints < 0, and suddenly you have characters in a zombie state where they are technically dead to some parts of the game, yet alive to others. Great fun.

      1. Nathon says:

        I think Linus’s problem is the impression that most programmers are not very good (something to which I can attest; past-me was a terrible programmer) and most programmers write C++ code. These two assumptions lead to the conclusion that most people who write C++ code are not very good. If you have a language (like C) that’s fallen out of the first-language-learned category, the idea is that you won’t get as many people who don’t know what they’re doing. There’s also the fact that Linus thinks that C++ is a horrible mess of a language. Note that I’m not endorsing any of these opinions (except that most software is crap) as my own, just trying to explain the reasoning Linus uses. I think irritating a goodly chunk of the programming population is just a bonus for him.

        1. Atle says:

          Linus “problem” is that he is not a nice guy, and doesn’t want to be either.

          But he is right. Most programmers aren’t very good, because being a good programmer[*] is very difficult.

          I have many years experience, and just now I start to produce code that I can look at and feel happy about. It both does what it’s supposed to do, and it is readable, structured, maintainable and extendable. This takes experience, and I still only produce good code when I’m not working under “should be done yesterday” conditions.

          [*] There are more than one way to be a good programmer. Sometimes you need to make something done quickly for a stand alone application that will not be maintained further after release. A very different condition is creating maintainable code that will live for a long time and be modified and extended many times. Very different requirements.

        2. Kingmob says:

          I’ve noticed there is this tendency to overestimate what it takes to be a ‘good’ programmer, where it really is just a mindset connected to knowledge. I don’t think there’s that many bad programmers, there’s just too much archaic knowledge required and usually no good ways to tell a programmer that he’s doing it wrong.
          That may sound like a redefinition, but it puts the blame more on the tools and less on the people.

          I’m still amazed by the fact where most of programming happens in a text editor, even though every programmer I know is mostly thinking of the problem in a visual way.

          To put it another way, programming is still largely conforming to the will of the language, instead of the language conforming to your will. In a perfect world you should only really have to think about the code that actually does useful stuff.

      2. James Schend says:

        > Well, it were funny if not for all the hostility involved, which I never
        > understood and probably never will. Why can't we just have favourite
        > languages and accept that other people prefer different languages for
        > many different reasons?

        It annoys me to see other people waste their time and potential working with bad tools. Whether or not they like it.

        Obligatory analogy: if you saw a carpenter building a bench, hammering in nails with an old Budweiser bottle when there was a hammer sitting not 3 feet away, wouldn’t that annoy you? Wouldn’t you say, “hey spend 30 seconds grabbing that hammer, and you could finish your nailing in a third the time and use the extra time to really make the veneer excellent!”

        Maybe not. Maybe I’m unique in this. Oh well.

        1. Volfram says:

          If I saw a carpenter who I knew was reasonably competent(at least as much so as I am) pounding away with a beer bottle when he’s got a hammer at hand, I’d assume he has reasons for what he’s doing.

          I make way too many of my own bizarre choices to begrudge anybody theirs.

          1. Paul Spooner says:

            Agreed. There’s a very strong temptation to assume that, just because there appears to be an obvious solution, everyone who doesn’t use it is an idiot. Probably part of the reason that political discussions get so heated.

            Personally, I’d be quite curious about the carpenter hammering with a bottle. I mean, this is an entire possibility space of tool design and use that may be unexplored! Has he patented the bottle-shaped-hammer? What qualities about the bottle does he like? Could I, perhaps, design a new kind of hand tool that incorporated those qualities along with the durability of forged steel? You’ll never find the answers to these kinds of questions by getting annoyed at professionals for ignorant assumptions.

          2. Retsam says:

            Well… if I saw a carpenter pounding away with an empty beer bottle, I think there’s a fairly obvious explanation for that. I might intervene, but I certainly wouldn’t hand him a hammer.

            1. Pylo says:

              Best. Response. Ever.
              (Sorry for a useless comment but this just made my day)

        2. Mephane says:

          There is a difference between being merely annoyed and outright hostility.

        3. Al says:

          Although Volfram, Paul, and Retsam have all adequately addressed reasons why one should not make an assumption about the suitability of a particular tool for a particular task, none of them made any mention of the reason that Shamus has mentioned in the past for his choice of tool.

          To continue with the analogy, you hand the carpenter the hammer. He examines it and asks, “What do I do with this?” You explain it to him. He asks, “How is this better than the bottle?” Another explanation follows. When you are done explaining it, he starts tapping the nail gently (as he would have done with the bottle so that it doesn’t break). Exasperated, you exclaim, “No! No! No! Swing it like this.” You demonstrate how it’s used. The nail is now half way in, which is much better progress than he was making.

          You have now convinced the carpenter that your tool is much better than his. He winds up and swings, but because he has never used a hammer, he is unfamiliar with the weight, the grip, safety, etc. He misses, hits his hand and breaks every bone in his hand. For the next six months, he’s unable to use any tools that require two hands. His productivity is diminished. Sure, in six months when he finally recovers, he’ll be twice as productive as he was before, but in the mean time, he better have good health insurance and lots of cash on hand to pay the bills.

          Analogies aside, the most difficult part about learning a new language is not the syntax. Once you’ve learned a couple of languages, the syntax isn’t a big deal. The most difficult part about learning a new language is becoming productive. Becoming productive requires familiarity with the libraries. Familiarity with the libraries requires time. For most people, time is a luxury they do not have.

          Would you really want Shamus to put Good Robot on hold while he learns your favorite language?


          Then again, I would like to play Good Robot on my Android phone…

          But I digress. First Shamus must produce the PC version before we can talk about an Android port ;)

    2. Simon Buchan says:

      *sigh* The old “I used C++ in 1992 and it sucked then!” and “You can do OO in C!” arguments. Even a disguised “C++ is slower!” argument. I would have hoped Linus could at least give *interesting* reasons to prefer C over C++, but it seems he’s just parroting the standard C party line on C++. Don’t get me wrong, C++ *does* have problems! But they sure as heck are not that it’s slower (to run, at least!) or C++ has a worse programmer pool (which is a stupid argument even if it were true, just don’t use the bad programmers!). And, of course, the usual missing the point of C++ again, and thinking it’s still only “C with Classes”, circa 1988.

      1. Nathon says:

        I think you misread or didn’t read what Linus said. Boost and STL didn’t exist in 1988. I just wrote a huge rant about the abuses of C++, but we really don’t need more of that. Linus is blunt and rude about his opinions, but he does know what he’s talking about. Sometimes it’s even worth wading through the profanity to extract the meaning.

        Also: don’t oppress his Finnish culture. (that was a joke)

      2. Kyte says:

        I liked the FQA, it puts a very in-depth explanation of the failures of C++.

        1. Alan says:

          Only if “failure” is defined as “ways in which it isn’t my favorite language.”

          I don’t know if he’s genuinely clueless about why C++ is what it is, why it was incredibly successful despite its legion “failures,” and why new projects are developed in it, or if he’s just pretending to make his arguments seem better. No one is going to read that essay and change their mind about C++. If you already dislike C++, the author is happy to reinforce your beliefs. If you appreciate C++, it’s a transparent attack with a poor grounding in reality and completely missing the poitn. One might as well identify the “failures” of the M1 Abrams: doesn’t fit in standard parking spots, tears up my driveway (and the lawn around it, since it doesn’t fit in my driveway), fuel inefficient, poor driver visibility, replacement parts are expensive, and the seats are uncomfortable.

          C++ is not the right answer for every project. It’s not the right answer for most projects. But it is a good solution for a non-trivial number of projects. While the author of that rant is busy ranting, people are getting work done in C++, choosing to use it despite knowing languages lacking these “failures,” and happy to have it as an option.

    3. Canthros says:

      I work in C#. I learned Java and C++, but have done basically zero real work with either. I still kind of miss C++, though C# is a better compromise than Java was. I do not consider myself an expert programmer of any stripe. (How much of that is truth, how much is Dunning-Kruger in action, and how much is false modesty I leave to the judgment of others.)

      I would still like to be able to declare things other than types at the namespace level, because a static class seems like a cumbersome solution to that problem. I would like the option of truly multiple inheritance, even if it seems like 90% of my peers don’t grok inheritance and polymorphism at all. I’d like to have private and protected inheritance, even if it’s only syntactic sugar for aggregation. I don’t want to go back to C++ libraries and platform, but, as a novice, I was always less familiar with the standard libraries than with the language. (And I sure as hell don’t miss manual memory management, though ISTR that more recent C++ standards include a garbage collector.)

      It’s kind of weird. One the one hand, I think that making programming more difficult actually does produce better programmers, and I think this is true even aside from the effect of filtering out programmers who just can’t hack the more difficult tools to start with. But. The other effect of making programming more difficult is making programming more difficult, and it still means making the process more error-prone and time-consuming. Most of the time, this trade-off just plain does not pay off.

      In that regard, Torvalds is in a weird, rarefied sort of environment. Given his reputation, he could probably find enough people of an arbitrary level of skill to work on a project of arbitrary size, even if he chose to use, say, BF (apologies; language name contains an F-bomb) as the language. I don’t think that decision works that way for most people in most environments, even if it does for Linus.

    4. James Schend says:

      Considering how crappy Git turned out, I wouldn’t put much weight in Linus’s words there.

      1. Ian says:

        Git is as crappy as the people using it really.

        Git is very complicated, and it can be hard to understand how decentralized SCM systems are supposed to work. But it has some very nice benefits over traditional systems, as it allows for very agile development.

        No other SCM system I have worked with allowed me to abandon a feature, only to pick it right back up 50 commits down the line.

      2. Retsam says:

        Git? Crappy? Pistols at dawn, sir!

        But seriously, as Ian says, it’s as bad as the person using it. It’s a powerful tool that gives you more than enough rope to shoot yourself in the foot. It does help if you embrace a pattern like “git flow” or “github flow” to manage the complexity and put some guidelines on how it should be used.

      3. lethal_guitar says:

        I disagree, I think git is great. But learning to use it right takes a long time. The steep learning curve sure does suck, and if you’re coming from a more traditional VCS like SVN, you’ll have a very frustrating time at first. I was first introduced to git roughly 5 years ago. I didn’t really become proficient until maybe a year ago, and having a day job that uses it helped a great deal with that.

        Once you obtain the power to rewrite history though (interactive rebasing), you never want to go back :D

    5. Felblood says:

      The fact is, C++ would get a lot less crap if it hadn’t been the language of choice for crappy community colleges to teach worthless AS-CS degrees in, for over a decade.

      We have theoretical C programmers teaching most of our practical C++ programmers, from a curriculum that never even mentions how to import a library, let alone integrate it properly.

      The hardest part of learning C++ was learning to forget all the BS I learned studying for my AS.

  4. Dr_Fred says:

    After reading this, I feel absolutely obligated to link to Steve Yegge’s rant about Java’s full-OO design. Shamus probably knows it already (in fact, I’m surprised there was no link to it :p), but if you like poking fun at Java’s everything-is-an-object doctrine, this one is hilarious.

    http://steve-yegge.blogspot.fr/2006/03/execution-in-kingdom-of-nouns.html

    Aside from that, I feel compelled to add that this does not constitute, from me, an attack against Java of any sort (don’t want to start a holy war, Emacs-vs-Vi style). I just link it for the laughs.

    1. Stuart Hacking says:

      I love this article. The parable of the horseshoe nail gets me every time!

      Ok, let’s get serious now though. Emacs or Vi? :P

      1. Nick says:

        Hey now, no religious commentary

      2. swenson says:

        I have never used Emacs, so clearly the only right answer is and forever will be vi.

        Except I’ve never technically used vi, just vim, so let’s go with that being the One True Editor, and if you disagree, you are clearly insane and I have the right to break into your house and steal all your stuff. Why is it better, you ask? Oh you. What a silly question to ask. Isn’t it obvious?

        1. ET says:

          The best editor is Notepad++ on Windows, and Kate on *nix.
          Except if you’re on the command line, then it’s Vim.

          1. Horfan says:

            “Except if you're on the command line, then it's Vim.”
            Yeah, about that… time and place motherf*****
            I kid, i feel like Vim actually is better but it’s so damn hard to use compared to Emacs. Is Vim usable for C++ in a command-line environment?

            1. Nathon says:

              A) Religion is supposed to be verboten here.

              B) Having used both (comparing vim to Emacs here; nobody uses vi any more), they both have roughly the same capabilities. The vim people where I work can do almost anything I can do with Emacs (no gdb mode for them!) and I can do everything they’ve done with vim. There’s no basis for arguing that one is objectively a better editor.

              C) Both can be used from command line or in fancy windowing systems.

              D) That said, Emacs is clearly better.

              1. Ingvar M says:

                Hey, now! I actively prefer nvi to vim, because when I learned vi in 1989, the I I had was nothing like vimand much like nvi. And, thus, vim breaks my hand-eye coordination. And that, when using vi, is stressful.

          2. James Schend says:

            Notepad++ can’t even draw menus right. I’m always amazed at developers who are still having trouble with things that were perfected in 1984– how is it even possible to have a program in 2013 that can’t draw menus right!?

            SublimeText is much better.

            1. Kian says:

              Is that a joke? What do you mean “can’t draw menus right”? Honestly curious, I see no difference with N++’s menus. They look the same as every other menu in Win7.

          3. Retsam says:

            Honestly, I’ve been using Notepad++ for years now, but just recently I’ve switched over to using SublimeText 2 (because my new work computer is a Mac), and ST is pretty wonderful. It’s very like Npp; no strange key commands to get used to (that’s not meant as a bash against things like vim; I like vim, too), but with some nice features.

            Things I like:
            1) Much better plugin/package system. (And from what I can tell, many more plugins to choose from) It probably helps that it’s built on python, so plugins are just python code.

            2) Python console. Even if you don’t technically know python, you could probably make use of a python shell. (Though I haven’t looked much into this; but I love the idea of it)

            3) Directory tree for opening files, creating files, renaming files, etc.

            4) Single click a file to ‘preview’ a file, which is identical to editing it except that the previewed file doesn’t have a tab, and disappears when you change tabs. (It prevents unnecessary tab explosion that I find when I try to work on projects with a lot of files and I just want to reference single files)

        2. Ingvar M says:

          The best editor for you is whatever damned editor you want to use. It shouldn’t matter to anyone if it is spelled with two, five or any other number of letters.

          Me, I use emacs for large edits, vi for small-to-=medium edits and ed for tiny-to-small. I mostly do large edits, though.

      3. Zukhramm says:

        Though by no means do you have to write your Java to look that way.

      4. Paul Spooner says:

        I was really hoping “horseshoe nail” referred to a nail bent into the shape of a horseshoe. It looks broken and useless, but you can actually use it to nail together complex geometries, since the nail will “curve” through the material. You have to do it on purpose though, and finding horseshoe shaped nails among your normal ones is bound to be a bit upsetting.

        Also, the whole parable is a bit misleading. If you’re going to loose the battle for want of a nail, there’s not nearly enough redundancy and robustness in your supply chain, command chain, or any other kind of chain. I read it not as a parable about how the little things are super important, as much as a parable about the importance of safety factors and well engineered infrastructures.

  5. Robert Conley says:

    The power and ease of use of Object Oriented Programming is not in an object heirarchy. But rather in the implementation of interface. An object can only have one parent but can have multiple interface. This is was the key concept that allowed to make effective use of OOP.

    Learning this was not easy because
    a) every damn book on OOP starts with inheritance and the Animal->Mammal->Dog examples
    b) C++ doesn’t make interfaces (virtual functions) stand out. They look almost like the regular inheritance setup.
    http://stackoverflow.com/questions/318064/how-do-you-declare-an-interface-in-c

    Last run not walk (or type very fast on Amazon.com) and get Design Patterns from Amazon.com.
    http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612/ref=sr_1_1?ie=UTF8&qid=1381489890&sr=8-1&keywords=Design+Patterns

    Design Patterns are to OOP what algorithms are to imperative programming. IT is a book about how to create and use a combination of objects to accomplish something.

    And get Refactoring, Improving Design of Existing Code.
    http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672/ref=sr_1_1?ie=UTF8&qid=1381489927&sr=8-1&keywords=Refactoring

    These two books are outstanding and more important they are not holistic “You got to change your programming” type of books. They are like a really good set of cookbooks that explain very well how to do certain things.

    The two in combination will help you with your code. Design Patterns how to get the most out of OOP, and refactoring tells how to get from where you are now to a different point without breaking shit along the way.

    I been using these on a complex CAD/CAM machine control program using VB6 for 10 years with great success. I been working as a programmer in Northwest PA for nearly 30 years and these two books are some of the most outstanding books on programming I ever owned and I still use today.

    1. somebodys_kid says:

      Thanks for the recommendations. I may pick some of them up over Christmas break.

    2. Zukhramm says:

      I would have thought algorithms were to OOP what algorithms are to imperative programming.

      1. Where’s that like button again? ;-)

        I think the earlier discussion about intelligence of programmers was actually pretty close to the mark. OO allows for much better software but it also requires more intelligent developers to do it well (cf imperative programming). There seems to be an emerging consensus that Functional Programming is the next step up, FP can be used to make even better software than OO but with the bar for developer intelligence set even higher.

        Conversely if your developers aren’t smart enough you better just hope your projects are simple enough that it doesn’t matter what paradigm you use!

  6. Ingvar M says:

    I would add “stick-in-a-class and wrap accessors around anything that requires access from multiple threads”, that way you can stick suitable locking around the modification, so you don’t end up with things affecting the wrong variable.

    But, then, I don’t normally write code for games and when I do, the game engine is single-threaded and I tend to use Common Lisp instead of C++. Mostly, I write assorted scaffolding around server code in C++.

  7. Stuart Hacking says:

    Java’s main problem in this sense is that it overloads the word ‘class’ to mean ‘A set of possible values’, and ‘a namespace’, and ‘a compound data type’.

    In Java, not everything is an object, but there isn’t enough vocabulary to say ‘this thing is semantically a namespace, and this thing is semantically a representation of data’.

    A few more keywords would probably solve it(!) ;-)

    1. Kyte says:

      Technically the ‘set of possible values’ is the Enum.

  8. Kian says:

    At work we use the “Spaghetti-Oriented” design Shamus described (I imagine OO looked like meatballs to the original coders). For my hobby projects, though, I’ve taken a rather esoteric approach. Instead of trying to model the real world as objects, I design the program’s systems (collision, movement, graphics, etc) as objects, and the world ‘objects’ as data structures that these system hold and share with whatever other systems need it.

    So, for example, instead of a SpaceMarine object with a position member and an Alien object that also has a position (possibly inherited from an Entity base class), I have a MovementComponent class with a list of positions and associated entity ids. The CollisionComponent class has the collision data for each of them, also associated to the corresponding id. And the graphics component has the model information for each, associated with the proper entity id.

    So instead of calling “spaceMarine.Update(); alien.Update();”, I’d call “movementComponent.Update();collisionComponent.Update();graphicsComponent.Update();”. The movement component has the information it needs to move things around. The collisionComponent has a reference to the movement data, so it can check for collisions and update the movement data if necessary (tight coupling between these two systems). The graphics component has a constant reference to the movement data so it can update the model matrices each frame, but it doesn’t modify the movement data (loose coupling), and knows nothing about the collision data (no coupling).

    So a component is defined by what information is needed to perform a certain operation, and is linked to whatever components hold associated information. The world the system models is just a collection of dumb data, and it’s the systems that operate on this data that are the programs’ objects. I’ve found this approach called “data-oriented”, though I might have taken liberties in my application. It seems more natural for me to think about things like this though.

    1. Volfram says:

      That’s a lot like what I ended up doing, except I still have the “SpaceMarine” and “Alien” classes. They contain components(Drawable, Audio, Collider, probably an Input component that will handle player input, AI, and netcode somewhere in the future) which they handle off to the various component managers(Draw manager, Audio manager, Collision manager), which are responsible for making sure all the Drawables get drawn, Audibles get audio’d and Colliders get checked for colliding.

      It’s probably a good thing that nobody else needs to look at my code…

  9. Robert Conley says:

    I maintained a CAD/CAM program for nearly 30 years and pulled it through a variety of languages and different OSes. When OOP first burst on the scene I looked into along with everybody else. Dutifully following along with the Animal->Mammal->Dog examples the books give.

    And while interesting it only seem to help with a small amount of problems.

    Then I found Design Patterns by the Gang of Four.

    http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612/ref=sr_1_1?ie=UTF8&qid=1381496169&sr=8-1&keywords=Design+Patterns

    Design Patterns are like algorithms for imperative language. The teach how to construct objects to accomplish a variety of useful general task. Similar to sorting algorithms or dealing with hash tables.

    For example one pattern they talk about is a command object. Another was a state object. Both of which was very useful for my CAD/CAM programming. With it I was able to change the design of my software to allow for a full undo/redo system. Using the command pattern to organize the overall design and the state pattern to save and restore what the command did in a compact form.

    One thing the Design Pattern enlightened about was that power of OOP is not in inheritance of behavior but rather in the implementation of interfaces. As I was using VB6 when I first read all this this was very helpful because OOP programming in VB6 only support interfaces.

    In contrast the use of inheritance in Design Patterns was very limited. Which mirrored my own experience in trying to use OOP. In my opinion the key to OOP is learning how to use interfaces. The nice thing is that a object can only have effectively have one parent, but it can implement any number of interfaces.

    Later when I did a simulation of the Mercury Space Casule in C++ as a hobby project. I found that C++ obscured interfaces in a major way. However it does support them.

    http://stackoverflow.com/questions/318064/how-do-you-declare-an-interface-in-c

    By now I bet you are thinking that it is too late for all this given the amount of time you put in. Well there is something to help with that.

    And that is the book Refactoring: Improving the design of existing code. The book is a cookbook of different procedures to use when you want to alter the design of your code in a safe and predictable. The author explains why each procedure works the way it does. The best part it works with any type of code in any langauge.

    For example if a subroutines gets too large and you want to pull a section out and make it a subroutine of its own. The book explains how to do it step by step so you don’t trash your code. And it has dozens of procedures addressing all type of design changes.

    http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672/ref=sr_1_1?ie=UTF8&qid=1381496902&sr=8-1&keywords=Refactoring

    I am experienced at converting a code base to a different language and OS. In my time I shifted it from a 1980s HP Workstation to a DOS PC, from DOS PC to Windows 3.1, from Windows 3.1 to Windows 32 bit (98/XP).

    At first I didn’t believe refactoring works as well as the author claimed. But then I tried because we had to radically alter some of our design to handle new types of machines and it does work. Way better than I thought it would. And when the IDE support refactor it like the closest thing to heaven in programming I can think of.

    1. Volfram says:

      I learned to write Object-Oriented code in Hardware Description Language.

      We have a Module here! The Module has input wires and output wires(typically including a clock signal and a reset signal). We feed inputs into the module, and get outputs from it.

      How do the outputs happen? I DON’T CARE, IT’S A BLACK BOX! I just care that it gives me the right outputs!

      So yeah… Interfaces. Something I understood, but now that you’ve mentioned it, I understand WHY I understood.

  10. Matt Downie says:

    I used to hate
    pos.SetX ( pos.GetX ( ) – (pos.GetY ( ) * pos.GetZ ( ) );
    but I’m starting to come around to it now. The sort of situation I get is that something is occasionally setting X to -1000000 and I have no idea what’s doing it.
    If SetX is a function, I can at any time add some kind of sanity check with an assert or breakpoint to tell me exactly when the value is going out of sensible bounds and what triggered it.
    It’s must easier to do this if it’s a function right from the start.
    Or I might discover I need to set a ‘this object has moved so trigger collision detection’ marker for it, or some other thing I can’t easily anticipate…

    1. Yes but a decent language allows you to make a property exposing X and then implement it with either do direct variable access or a get method without the calling code needing to know anything about how the property is implemented.

      Gives you the best of both worlds and the flexibility to start with direct variable access and then add getters/setters as complexity grows. Delphi did this back in the 90s and there are plenty of other good examples.

      1. jlejeune says:

        A decent language may expose properties properly, but you can still replicate it in C++ well enough when all you have is C++ and without the clunky “Get” and “Set” in names. You really are just stuck with ().

  11. That makes me think – how would one create a tool to create a c++ class much quicker?
    C++ has the problem of taking far too long for annoying admin tasks every time you want to make a new object.
    Maybe there’s already a tool out there…

    1. Nathon says:

      There are several. Generating boilerplate is a thoroughly solved problem. My editor does it for me.

    2. Kian says:

      Most IDEs I’ve worked with will do the standard work for you. You tell them “Add Class to Project”, and they’ll open a window asking you the name of the class, locations for header and implementation files, and create the files with header guards, declarations for constructors and destructors (helpfully defined as virtual) and whatever inheritance you defined.

      That’s most of the boilerplate you’re likely to define as common to all classes. There isn’t much more that a program can do without knowing what you intend to do with the class.

    3. Simon Buchan says:

      Use what you need: start with a stupid struct with public fields, add stuff as you need it, because you probably won’t. In particular, don’t bother with a whole new header and implementation file for each class, write the code where you need it to make it work first, then dump it all in the header when that becomes ugly, then move out method bodies when that becomes ugly. Don’t take pain you don’t need to.

      Class generators exist, but they can’t do terribly much for you, since there’s not that much actual boilerplate for a new class. Now, generating the comparison operators or the << formatting operator on existing types, *that* would be useful.

    4. ET says:

      The real question is, “Is there a way to program this without so much boilerplate?”
      The answer is usually, “Yes”, with the implied action “Move on to a higher-level language.”

      Can’t remember where I read it, but the number of errors produced is proportional to the number of characters/lines/things typed. *
      So, usually, you’ll want to use whichever language/library/foo lets you express yourself as concisely as possible.

      * Even when you’re using a tool to auto-generate your boilerplate, the size of your code will affect how quickly you can read through it, analyze it, debug it, etc.
      So even with tools, you want your code to be concise.

      1. Alan says:

        Has “stop using programming language Y” or “use programming language Z” ever changed anyone’s mind ever in response to “how do I do X in programming language Y?”

        1. Zukhramm says:

          Even it is has, it’s still not an answer to the question.

      2. Kian says:

        The boilerplate for creating a class is really very little. It’s just the header guard. It’s just boring to write
        #ifndef BLAH
        #define BLAH
        #endif //BLAH

        Then it’s just “class $ClassName {};” and optionally declaring the constructors, which you might not want.

  12. Nathon says:

    A couple thoughts on how other languages do it (because I like other languages):

    First, Python. In Python, you can make a class that looks like a struct:

    class Foo(object): # This is Python <3.0; Py3k doesn't need object there
    ….member # I can’t convince this blag software to properly format things.

    People can instantiate a Foo (as foo, for example) and get and set member with foo.member. But then, when member needs to update some other funky things (log messages, event notifications, etc.) you can do that without changing the interface to the class. (This isn’t a Python tutorial, so I’m not going into details, but it’s pretty easy.) It’s great. You don’t need to write getters and setters just because you might want them at some point in the nebulous future. Python’s philosophy on private members is a bit less restrictive than most languages: _member can be accessed directly, but probably shouldn’t and _function won’t be imported with “from module import *” and __member can be accessed directly but its name has been mangled so you have to know what it’s called if you want to be able to break things.

    Second: Erlang.

    Erlang uses processes to encapsulate state. If you want a space marine, you can spawn a space marine process that accepts and generates messages. OTP wraps this up in a nice interface, but the essence is just a process per object. The best thing about Erlang (with OTP) is that if you make a new version of your code, you can upgrade the running processes with zero downtime. This isn’t particularly useful in game clients, but it’s awesome for servers.

    Anyway, C++ does OOP brokenly. You can tell because it promises that your private members will never be modified by anything else, but doesn’t actually do anything to prevent some unrelated function from stomping all over your memory. Const too. You can say things are const, and sometimes they’ll be put in .text and actually be const, but usually you can just cast it away and modify the const stuff and nothing will crash.

    I don’t know much about Java, having never used it, but Steve Yegge wrote a hilarious post about the kingdom of nouns a while ago.

    1. ET says:

      I particularly like Python, because it let’s you use many different paradigms.
      OO? Check.
      Functional? Check.
      Etc? 99% of the time, check!

      1. Shivoa says:

        Name a programming language. Statistically speaking, chances are you just named a multi-paradigm language (Wikipedia may contain language that sounds far more authorative than it is, but the broad strokes can also be found in a decent textbook that touches this topic). Because they kinda grew that way once there was a decent example of something that could do any single paradigm. If the language was developed in the late ’80s forward then you should really expect it to cover quite a broad range of paradigms (and the ‘fun’ is looking at how badly or well each language managed to get them all working together and avoiding duplicating functionality for each way of accessing it – or just straight up duplicating functionality if you franken-language your way there with actual duplication throughout your broad, fragmented std lib and base features).

        Python is an interesting example of a dynamic and dynamically typed language that takes hold of the scripting needs in a lot of places, while still being a programming language suitable for writing most programs you could want to (if performance wasn’t an issue, not a unique issue of Python) and you could actually build a consistent specification for it without dealing with a significant suicide issue for the documenters. I generally don’t like dynamically typed languages (not knowing what type something is at compile time means I cannot know what something is at time of writing and this unravels into a sea of concerns that making compile time guarantees on types fixes for me and allows me to get down there and reason on the type specifications for optimisation) but have been doing quite a lot of Python stuff in the last few years at work (because sometimes you follow the library rather than write a massive interface layer to translate data structures being passed back and forward to your lib in a different language, and because Python is a great choice for rapid prototyping new algorithm designs).

        1. Kevin says:

          Just add some is_instance guards.

          def foo(a_str, b_int):
          …if not is_instance(a_str, str) or not is_instance(b_int, int):
          …….raise TypeError(“You gave me the wrong type”)

          At least Python is strongly dynamically typed, so:

          “2” + “2” => “22” (and not 22, or 4, or ???)
          2 + 2 => 4
          “2” + 2 => Error

          and that’s guaranteed to happen. Unlike the weakly-typed languages.

          1. Alan says:

            Coming from compile time typed languages, run time checks are frustrating. I prefer to turn as many bugs into compiler errors as possible. I gather it’s possible with dynamically typed languages. I’ve been told of there is at least one language (sadly blanking on which) whose compiler is smart enough to deduce things like “In this function, the parameters a and b are added together. Therefore, if someone passes values that can’t be added, or can’t be added together, the compiler will complain without ever running the code.

            (Don’t take the above as “never use Python.” Python is a rock solid language. I recommend everyone who programs consider it for new projects.)

            1. WillRiker says:

              I think you’re describing type inference; this is a feature of a few functional languages, including Haskell and the ML family. Technically, though, compile-time type inference is considered static typing, though I actually really like it because I think, when done right, it combines the safety and performance benefits of static typing with the flexibility of dynamic typing.

              1. Shivoa says:

                Type inference (of the form I think you’re describing, using var/val rather than a type in your source at places where what you want will become obvious – basically removing duplication of the type token when it isn’t needed) is something you should expect, going forward, at the IDE level even if programming languages don’t adopt it. Things like C# (in 2007) and C++11 have added it and Scala (and yep, a lot of functional first languages) always had it. There’s no real need for a lot of the type tokens in most languages and if you’re going to be strong then you definitely don’t need it and if you’re weak then you’re not really saving people without it (one is busy work that does some validation of the programmers understanding, the other is hidden by implicit type conversion so it isn’t even throwing up errors). But it takes more than no work and most languages were devised when the idea of parsers running on each token add to run grammar checks and even do advanced static code analysis as we write code was well into the magical future of Moore’s law.

                Alan’s post seems to be considering some static code analysis being run on a dynamically typed language to point out places where a clear contradiction can arise, rather than waiting for it to fall apart at run-time. If you’re running something like PyLint, Pyflakes, or PyChecker (I think all 3 do type inference passes; other DCA or SCA tools exist for other dynamically typed languages) then the analysis they do will give you some indication of clearly bad code. But the compiler isn’t required to have types and so some code will resist analysis. This is the freedom of dynamically typed, which I prefer to give up for guaranteed compile time type errors, and a limitation of code analysis tools. In my view statically typed languages used generic programming to get past the really nasty limitations that originally made dynamically typed languages so seductive.

          2. Shivoa says:

            Yep, I’m aware of how to turn Python into an approximation of any other language I desire but using manually inserted run-time type checking into every bit of your code is a sure sign you’re using the wrong language for the job. I want compile time type checking to do as much as possible basically in every language I use. Even jumping around implicit casts in weakly typed C (once described to me as the minimum required type system to have a working pointer system and not a jot more) seems preferable to having to deal with all type concerns at run-time.

            It’s a bit like the original C++ compilers being C compilers with a C++ to C transformer step at the front (with some rejection logic for things that are not C++ – a critical point as these later become compiler errors that pure C compiled with a C compiler cannot reproduce). Technically it means that the first C++ users (before the C++ specs moved to the point where this is no longer possible) are just enjoying some syntactic sugar on C so you should just use C. Only that’s missing the point. A bit like the Turing complete bar: everyone jumps it so they’re all the same. Only they’re not and picking the right tool is important.

            I will occasionally check types when I feel I really need to in my Python code but generally try to follow Python guidelines to use duck typing at all points. I just feel like I’m working without a safety net and would be happier with static typing. It doesn’t help that most people think of dynamic typing as type inference and Scala and C# (to randomly pick two quite nice staticly typed languages) both show this can work just fine without giving up on knowing your types at compile time. But this is an “I like X” thing where I happen to sit in the static typing camp and I’m not sure another couple of decades of coding, even if I continue to work in a mix, is going to change that.

            Now mutable objects as default arguments being created at code load time rather than creating at each instantiation. That seems like Wat language design in Python. After a few months you get to accept why you end up there but if that isn’t a slightly weird exposure to the mutable/immutable split in the type system hitting the first class function, I don’t know what is. Maybe it is there as an important lesson everyone has to hit as they learn the language but sometimes you do wonder why it isn’t sugar for making a clean mutable each call and so acts like everyone else who isn’t a Python user expects.

      2. Ian says:

        Contrary to popular belief, python does not actually support a functional paradigm very well. Actually I would say that it does not support it at all.

        First of all, it does not optimize tail recursion. Making it near useless for implementing any algorithm in a purely functional way.

        Secondly it has not have shorthand way for defining functions. The lambda keyword is a remnant of one of the first patches to the python source code. Guido looked into removing it, but there was not direct replacement for what little purpose it did serve.

        Thirdly, it does not support any pattern matching, meaning it is useless as a functional language compared to more modern and mature counterparts.

        At best the syntax is functionally inspired, with functions being first class citizens, and various comprehensions being the only noticeable functional features.

        That being said, I love python personally, I use it every day, at work, for my personal projects. It simplifies my work a great deal.

        But, knowing many languages, and having written a few compilers on my own.

        The language and the API is a real mess. The only feature that really deserves praise is how easy it is to use.

  13. Retsam says:

    C# has a really interesting solution to the getter setter problem. (Obligatory: I’m not trying to be an evangelist just discussing an interesting approach to the problem discussed) Basically C# has two different types of object variables, fields and properties. Fields, with a lower-case variable name, are basically standard object properties. So “private int health;” is pretty much what you’d expect.

    However, you can also declare properties, with capital letter variable names. These are accessed just like fields, i.e. “player.Health”, however, under the hood that’s actually a function call; as well as “player.Health = 10” is also a function call. C# will automatically implement a standard getter and setter for you (or just one, or neither if you so choose), or you can implement custom logic. So you might see:


    string Name {get; set;} //Automatically implement getter/setter

    private int health;
    int Health {
      get {
        return health;
      };
      set {
        if(value < 0) die()
        health = value; //Value is a special variable for the value being assigned
      }
    }

    Anyways, my syntax is bad, but it's close enough to see the idea.

    I've only used C# for a few months, but I do find that I really like it. It takes the basic idea of Java but with much more flexibility and just better design over all.

    1. Volfram says:

      D does this as well(though not transparently. That may have more to do with Code::Blocks than D, thought), and in fact dynamic arrays have a built-in Property, “length,” which can be called as a right-hand value if you want to check the array’s length, or can be called as a left-hand value if you want to set the array length. Small side-effect is that you can’t do array.length++(which is how I figured out that it does this)

      One of the reasons I compare D to C# so often.

    2. Canthros says:

      I feel like it’s worth noting that the naming convention described above is just a convention. But, yes, properties and nifty, and auto-implemented properties are extra-nifty.

      There are some quirks, though, that prevent a property from behaving like a field of the same type. For instance, you cannot pass a property in place of an out or ref parameter of a given type. This will make sense, if you think about it: an int property is not a variable of type int, it is a pair of methods (one that takes an int and returns void, and one that takes nothing and returns an int) which are swapped between at compile-time.

      On the upside, declaring public fields as properties by convention helps a bit with future proofing, and solves some questions about behavior of fields that are const vs. static readonly (i. e. const fields may be inlined to dependent DLLs during compilation, but a static readonly won’t; this makes consts exposed outside your library relatively dangerous).

      Still, it’s a very handy bit of syntactic sugar to have in the language. One of C#’s language features that I really, really like.

    3. Mephane says:

      Yeah, I wish I had that feature in C++, le sigh.

  14. MelTorefas says:

    I know enough of programming to understand everything you wrote, but not enough to care about which way is “right” or how one “should” do something. So, in other words, I guess I am in the perfect state to enjoy this post. ^.^

    1. Nathon says:

      The goal of good programming is to communicate to humans what the computer is doing. Computers don’t care if you write all your code in binary or Haskell. Programming languages are for the benefit of humans. So when evaluating software for goodness, you can use the “how long does it take me to understand this?” metric. If it’s a long time compared to other software that does similarly complex things, it’s not good.

      Of course, that’s not very useful advice for a newbie.

      1. Alan says:

        To call out the point I believe Nathon implicitly stated: the “right” answer varies based on the problem you’re trying to solve at the moment. This is part of why multi-paradigm languages exist (see Shivoa’s comment). Different parts of a large project might use different paradigms. It’s also part of why there are so many programming languages, different problems map better to different languages, and why many projects include multiple languages. (If you’re running a Java program, I pretty much guarantee there is C++ helping. If you’re doing massive numerical crunching in Python (NumPy), Fortran is probably hiding under the hood.

      2. Mephane says:

        There is a saying. Always write your code as if the one to later maintain it is a manic psychopath who knows where you live. The extended version also says – that guy might be you.

  15. Nick says:

    Whilst I agree it is sometimes annoying to have to use a lot of getX style methods (though in that case, why not make a function called doAlgorithm to do that from inside the object and use the result there?), I’ve had some bad, bad experiences at hunting through code to find where the object.x was reset, by another programmer in a different thread, and there are lots of other .x calls throughout the code…

    The ability to add a debug line to getX/setX and work out where in the code that call is actually located is a Godsend

    1. Paul Spooner says:

      True. I really enjoy Python’s property implementation, where you can add getter-setter functions after the fact. Super handy, but of course it’s an interpreted language.

  16. WillRiker says:

    OOP got sold back in the 90’s as a magic silver bullet that would solve software complexity forever. Shockingly, it didn’t turn out that way (presumably these people never read Fred Brooks)

    OOP is a *tool*, and like all tools it has strengths and weaknesses, problems it’s well-suited towards and problems where all it does is add needless complexity. Trying to impose it on every problem, large and small, causes as many problems as it solves.

    This is why Java drives me nuts. Its slavish devotion to Object Oriented purity has the effect of driving out other, equally useful tools. It’s like a toolbox full of hammers. What if I need to turn a screw?

    1. Stuart Hacking says:

      Java only requires that everything be declared inside a class, but it doesn’t enforce Object-orientation. You can, for example, have a program comprising a single mega-class. A C program disguised in Java.

      You can think of Java’s ‘class’ keyword as declaring either a data type or a namespace. It might help if these notions were separated, but maybe the language is too long in the tooth now and Java programmers don’t seem to mind the conflation.

      1. WillRiker says:

        My primary gripe is the lack of functional programming facilities. Functions in Java are not first-class objects, which means no higher-order functions; Java has no anonymous functions, and to my knowledge doesn’t have full support for closures.

        This is with the caveat that the last version I used was Java 5; if any of these have been added to the language since, that’s great. The important thing is, none of these things are possible without abandoning Java’s “everything is an Object” orthodoxy.

        1. Stuart Hacking says:

          Well, Java 8 will add support for a lambda expression, but as far as I know this will just be syntactic sugar for anonymous inner classes.

          I actually don’t see the lack of functional constructs in Java as a disadvantage, or rather.. I wouldn’t see the addition of them as an advantage for Java. Java currently enshrines the theory of Object/Component Oriented programming and the only first class citizen are classes. I think this is very clean, personally.

          It’s true that Anonymous Functions, are not possible and that’s good for the same reason. However, you can achieve this behaviour by having an anonymous inner class which implements an interface (e.g. Callable, if you just want a functor). A limitation is that you may only close over final variables in an inner class.

          I think if you really want to mix Java with functional elements, a much better route is to pick a functional jvm language like Scala or Clojure. These languages give you the first class functional constructs, with the advantage of fantastic interop with the Java Class Library.

          My personal feeling is that Java should maintain it’s current position as a ‘class oriented’ language and not muddy the water by introducing things which are not a good fit.

          but maybe I’m just an old curmudgeon. :-)

    2. Groo_The_Wanderer says:

      Well if you are using Java then the answer is obviously “Swing Harder”.

      ROFL.

  17. kdansky says:

    I want to throw in that many issues of OO that Shamus mentions are somewhat specific to the late 90’s style of OO languages such as C++ and Java. In actually modern languages (Scala, Eiffel), many of these problems are far easier. Nobody writes a vector.GetX() function in Scala. It’s just vector.x, as expected. It’s a bit more complex than that, but suffice to say, this issue is solved by now.

    The problem is that these newer languages are not that widely used yet, to put it mildly. That said, it’s not a secret that most games have very shallow inheritance structures, and not a strong object model. Not because the programmers suck at OO, but because games don’t translate well into OO. Everything interacts with everything, performance is super-important, but there are relatively few use cases compared to business software (how many tools does Photoshop have? How many types of guns are in Quake?).

    I also want to point to anther issue with OO, namely trying to map objects and relational databases. This (long) article explains it all, and is worth the read for any programmer. http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Computer+Science.aspx

    The short version: It’s absolutely impossible to perfectly map objects and relations, because they are not the same thing. Any attempt to do so will work nicely for 90% of the time, and then proceed to completely screw you over with a dirty, lightning powered flaming chainsaw in the rectum.

  18. Svick says:

    A good example is the player. Right now you call PlayerUpdate () to process player input. This performs non-repeatable actions and creates state changes in the I/O. Sure, I could make a class Player p; and call p->Update (); but that would make no sense.

    That sounds like what you want is a static class*. With that, you would write something like Player::Upadate ();. This basically combines advantages of both approaches: the player data is nicely encapsulated (you can have private static fields), but you can’t have more than one player and you can also access the player from anywhere.

    * C++ doesn’t have any specific support for static classes, you just make your constructor private and don’t declare any instance members.

    1. Paul Spooner says:

      I think the point was more along the lines of “I don’t need any of the features of a class, so why spend internal overhead on a class when a few arrays and some functions will do just as well?”
      Even in your example, you’re going out of your way to make the class harder to use in order to make it not behave like a class at all. Why use a class interface at all?

      1. Svick says:

        I don’t think the features of a class are not needed here.

        What can still be useful:

        * Grouping all the related code in one place, with enforced consistent naming.
        * Having the ability to hide implementation details into private fields and accessing them only from a limited and knowns set of functions.

        And I’m not sure what kind of overhead are you talking about, but classes have pretty much no overhead in C++, and especially classes that you never instantiate.

  19. newplan says:

    But then I realized that some problems just don't lend themselves to an OO solution. In my own code, I manage to infuriate all parties by mixing C++ style object-oriented design with C style imperative. If I'm going to make many of something (robots, sprites, lasers, explosions) then those things are a class. If I'm making ONE of something (like the game, or the gameworld) then it doesn't use any kind of class interface at all.

    Someone above talked about design patterns being the algorithms of OO programming and this is a perfect example.

    The pattern you’re looking for here is “Singelton”. Singleton allows you ensure that there is only one instance of a particular class running around.

    How does it work? You make the constructor private / inaccessible then create a static method that returns an instance of the object. The first time the static method is called you create a new object, return it, and create a static reference to that object. The second time and every time after you simply return a reference to the static reference you stored the first time.

    1. Canthros says:

      Singletons are great when you really need one, but they’re overused and a source of potential pitfalls. And a singleton object is probably still more awkward to deal with than the situation Shamus is describing with a mix of procedural/imperative and object-oriented coding.

      1. Zukhramm says:

        When do you actually need one instead of a static class though? I guess if you need some polymorphism for some reason? Other than that, I can’t think of anything.

        1. Canthros says:

          I think you may have misunderstood me: Singleton is a pattern, and I see no reason you couldn’t implement it as a static class. (My major concern re: pitfalls has to do with multithreading.) There are situations where it might be convenient to serialize singleton data to or from a shared source, such as a file or database. That sort of thing may not require or be compatible with wrapping in a static class.

          Most instances of “I know: I’ll solve it with a singleton!” I’ve seen either involved tracking a bunch of global state in C#, which doesn’t have global variables; or creating a singleton of a thing that doesn’t need to be a singleton (usually with a factory type). The former was the wrong solution to a non-problem, and the latter is a design error that is probably propagated by every almost example I’ve ever seen of a Factory implementation also being a Singleton.

    2. Svick says:

      Singleton is a pattern that you use when you want static class, but you don’t want to use static class, because that’s not “object-oriented”.

      So, it doesn’t actually solve anything, it just makes your code more verbose.

      1. Paul Spooner says:

        Yeah, I’ve read and heard about the Singleton “pattern” several times now, and every time it’s sounded like either nonsense or circumlocution. Every time it comes down to “We don’t like to call them “global variables” so we call them “Singletons” instead! Now it’s a design pattern instead of poor practice! The magic of terminology and obfuscation solves everything!”
        Just use global variables properly and call them global variables.

        1. Svick says:

          Actually, static classes (and singletons) have one significant advantage over global variables: you can control access.

          With static class, you can have a private static field and allow access to it only indirectly, though some set of static methods.

          With normal global variables (or public static fields), you never know who is accessing it and whether they are doing it correctly.

        2. Alan says:

          If someone is using a singleton just a simple global, they’re probably using it wrong. A singleton isn’t about “toss all your globals here.” The original Design Patterns specifies that it’s for when one has an object for which logically there should only ever be one instance of, and one wants to ensure no one erroneously instantiates a second one.” It accomplishes that job pretty well.

          Given that use case, it’s widely overused. Almost any circumstance in which I might want 1 of something, I can reasonably imagine wanting 2 or more. “There is only one player” stops being true as soon as you go multiplayer. “There is only one display” stops being true as soon as you go multi-screen. Even “there is only one event loop” becomes dubious assumption on a multi-core machine.

          On the (marginal) up side, there is a small advantage if someone is just using the singleton as a dumping group for globals. Globals suggest side-effecting code, and probably non-thread-safe code. If you need to add threading to such code, if all of the globals are in a singleton, it’s a lot easier to remove the singleton, take the object itself, and instantiate it once for each thread. Arguably not a big deal if one “Just use[s] global variables properly,” but if I’m handed someone else’s improper code, I’d rather the global variables were grouped into a singleton than scattered across the code like buckshot in a deer.

    3. Aerik says:

      +1

      (I was thinking “Just use a singleton, just use a singleton…” all through that part, and as soon as I finished the post, I searched through the comments for “singleton” to make sure it was represented. :P)

  20. Chris says:

    I think all programming should be approached that you may need to support it two years down the road so you better be able to understand it 2 years later when you are no longer in that headspace anymore. If you do that then the code will be able to stand up to other programmers. Also agree with the above that standardization amongst team is a must, but real world rarely happens. More like rough guidelines…oh well a rant for another time.

  21. Niriel says:

    I slowly gave up OO when working in python. I’m coding in go now, and I’m experimenting with immutable and pointerless structures, in a data-driven way. So far, I love it. Immutable means that I can parallelize everything without ever having to worry about synchronization. It means that I can also keep past versions of the world in memory so that I can replay it if something goes wrong. Not using pointers means that saving/loading the game state on disk is a one-liner. That comfort has a performance price, but I will value correctness above speed any day. The data-driven approach gives me some speed back anyway.

  22. krellen says:

    I was thinking this article would end with “so I’ve done this whole project in imperative style, because all the downsides of imperative are alleviated when you’re the only person working on a project.”

    1. Knut says:

      Don’t know about you, but I am perfectly capable of confusing myself when my projects starts to get large. Especially the parts I haven’t worked on for a bit tends to be forgotten.

      (and this is also the reason I try to be very generous with comments)

      1. I try to comment shit myself, but a lot of the time I just end up rewriting the code instead, which has the side effect of making it moire solid, lean and mean too; which I don’t mind :)

  23. guy says:

    There’s totally a good reason for the a.setX thing, although it’s not always necessary. Using getters and setters means it’s impossible to bypass the sanity checking code that stops things like having a negative age. This is, of course, only a problem if there are potential nonsense values and the program is structured so that might possibly happen, and the setter actually screens for such things. It’s much more important when you have multiple programmers.

    1. If you do not want the risk of a negative age then using unsigned is the solution as it can’t go negative. Signed and Unsigned exist for a reason.

      1. Shivoa says:

        And that reason is people used to have total RAM measured in bytes, so you didn’t have space to ask for an int that could do both negatives and count all the way to 255 without taking up significant space.

        Sanity checking age makes a lot of sense when subtracting 1 from the age of 0 gives you the oldest age possible (UINT_MAX) and no errors in some languages (which cunningly defined away overflow errors with unsigned ints by saying they just wrap and this is the spec behaviour, nothing to see here) if you didn’t use signed ints.

        As an aside (as we’ve mentioned unsigned ints in C), signed ints have undefined behaviour if you ever fail to check for an overflow before executing that computation. This is potentially a rather exciting difference in the C spec for those two type groups, depending how much you believe your old professor and how graphic his embellishment of what the worst that undefined behaviour could mean.

        1. Now if there is undefined behavior related to this in the C spec then that is worrying indeed.

          But regardless, overflow is nasty, and if it happens it is the programmers fault, not the underlying language or storage method.

          Why is it the programmers fault? Because nothing should ever overflow or underflow in the first place.

          The way I code (and ensure) that my code behaves like is that if you have $FFFFFFFF and then add to that then the result should still $FFFFFFFF if that suddenly wraps around it’s a major bug/issue.
          Now if you do not use the whole range it’s easier as you can control things if the underlaying language wraps around or not. If signed and you use from 0 to 1000 then you could easily do a upper and lower check like (pseudocode) If (x>1000 then x=1000) or (x<0 then x=0) now if values never go negative naturally the second part could be (x999

          oldtime=timeGetTime()
          endif

          This will do the code inside the if block once per second, and you have to use (time-oldtime) as that is the only safe way (you end up with the difference so when it wraps (which it might every 49 something days on systems that is always on) your code will handle that fine..

          You mention values up to 255 and memory in the past, but there are actually unsigned 32bit and unsigned 64bit CPU support as well?

          Now, I have heard statements that unsigned math can be slower than signed math, I’m yet to do a test myself or read up on any tests for that.

          Most of the time I never need to worry about signed vs unsigned.
          But when dealing with memory addresses or filepositions or handling of checksums (like CRC32) then I prefer to use unsigned.

          If I where to do a game and a monetary value where to be stored then I might use unsigned 32bit integer or 64bit integer, with or without a fixed point. (many games do this).
          If I where to do a financial program then signed would actually be a benefit as a negative is actually a valid result.
          If I where to do a game with damage calculation then I might use 32bit float.
          For a audio program I might use 32bit float (which can easily hold a 24bit integer value) or 64bit float is a lot of processing is to be done and highest precision is needed, float does have some minor rounding issues due to the way floats work. (and I know, there are 128bit+ features in newer CPUs but the gain is diminishing rapidly at a certain point)

          1. Shivoa says:

            I advise reading the C specification, or more accurately I advise reading the K&R 2nd book and then maybe dropping in to the actual specification document (getting up to date with C99 or C11) from there as you need it. C is well specified as a language but there are quite a lot of things that are grammatical C and result in either compiler dependent execution or undefined behaviour (as defined by the spec, which should be considered the gold standard to hold compilers to). This is not a problem with the spec (or even that worrying – the range of non-compliant code that is similar to C, ie outside of the C standard, that a compiler will generate an executable for is far more concerning) but you do need to be aware of it before you consider yourself a competent coder in the language. There are also great resources like the CERT C secure coding standard that help explain how to code to avoid shooting yourself in the foot in C.

            1. In other words, one need to choose which version of C to code for.

      2. kdansky says:

        Using unsigned for such a thing only means that you now have another class of errors: Instead of the somewhat annoying “why do I have negative HP?” you now have the much more problematic underflow. As soon as subtraction is a thing you are likely to do, unsigned is wrong.

        Few people understand how to work with unsigneds (namely only use them when you are so close to the hardware that you care about individual bits), and that is why we have such horrible constructs as arrays that take DWORDs for indices and return them on GetCount(), only to die a horrible seg-fault death at the earliest chance.

        1. Actually, you are wrong, if all you care about is the individual bits (AND OR XOR NOT and similar) then it does not matter if it’s signed or unsigned as long as it’s consistent all the time, as soon as you move a value to from signed or unsigned storage the issue isn’t the language or the signed vs unsigned, the issue is the programmer being a moron.

          Programmers these days are so used to just casting something from one thing to another, and if something blows up they have no idea why.

          I searched up GetCount and segfault and the results I see are C++ specific, could this be because programmers just assumes that C++ waves a magic wand for them?

          The correct behavior (at least to me) is that the calculation: 0-1=0
          The same way that the calculation 4294967295+1=4294967295
          In the same way 2147483647+1=2147483647 and -2147483648-1=-2147483648

          If the underlying language does not do that, then it is the responsibility of you as the programmer do be aware of this and code accordingly.
          If the language is speced properly and not undefined then unsigned or signed is not an issue.

          With the exception of things like timeGetTime(), things should not normally overflow/underflow/wrap around.

          Imagine if a gas pump at a gas station was allowed to wrap around or overflow. The result would be that the gas would overflow (pun intended) from the gas tank, and the gas station would owe YOU money instead (as the gas amount would be negative).

          “why do I have negative HP?” my answer is, because either the programmer of the game, or the programmer of the underlying language or the game engine screwed up.
          And as for GetCount and DWORD, luckily I’ve never had to deal with code that used that (I rarely use code by others without reviewing it anyway if it fits my needs).

          But if you have an array (I assume that is what you are talking about as you mention indices). Myself I use whatever number storage is big enough to hold the numbers I need to hold, combined that with always having control over what gets added/subtracted/multiplied/divided.
          I may be anal about coding like this, but to put it another way, I can’t recall the last time I had a division by zero, it’s really that long ago.

          I do recall the last time I had a wraparound bug though, and that was because I forgot to initialize the comparison value for a timeGetTime() check that was to be done later and occurred in the middle of some larger code rewrite/moving.

          My statement above of “If you do not want the risk of a negative age then using unsigned is the solution as it can't go negative. Signed and Unsigned exist for a reason.” still holds true.
          Now if programmers fail to maintain control over what is happening with their code and values (bounds checking and sanitizing user or 2nd or 3rd party interacting software/code, or loading stored/transmitted data), that is not the fault of unsigned or signed.
          Or if the underlying language does not handle unsigned and signed consistently or how people expect them to then that is a issue the programmer of the language or for the programmer that uses the language.

          Now, I code in a procedural language, and if I do C then I prefer to stick to C whenever possible if I do C based stuff. When it comes to #NET and java and managed stuff like that I have no idea how messed up/un-messed signed vs unsigned actually is as I never use those languages.

          When it comes to OOP then classing everything and mixing signed and unsigned and not documenting it is a huge blunder by whomever did that.
          I avoid New and (the implied) Destroy like the plague anyway.
          I prefer to allocate all memory/buffers I’ll for the duration of the program that I need at startup, and if temporary memory is needed (for processing a loaded image for example) then I allocate that memory and then free it when I no longer need it, but if possible I recycle that memory thus avoiding further allocation and de-allocation needs.

          And I never free any memory when I quit the program unless the Win32 API documentation states that this or that must be freed or unlocked first. All memory that “you” allocated is automatically freed. Instead of taking seconds or longer to quit the program can quit within a second and the system has the memory available ASAP.

          I’ve actually seen code/software that step through a list of heap allocated memory and free each entry. Stuff like that happens because the programmer do not understand the underlying code of the language or library or classes they use.

          So I’ll re-iterate, unsigned vs signed is not the issue, not any more than signed vs unsigned vs 32bit float vs 64bit float and so on is.

          1. Alan says:

            If the language is speced properly and not undefined then unsigned or signed is not an issue.

            The more things you define, the more things the compiler need to check. Checking for overflow to ensure consistent behavior on every operation has a price. Neither C nor C++ is going to accept that price. Thus, it’s undefined.

            I prefer to allocate all memory/buffers I'll for the duration of the program that I need at startup….

            So, most of your memory allocation is in one place, distant from the code using it? It seems like it would be easy to remove usage of some memory, but forget to remove the associated allocation.

            and if temporary memory is needed (for processing a loaded image for example) then I allocate that memory and then free it when I no longer need it, but if possible I recycle that memory thus avoiding further allocation and de-allocation needs.

            Why would you recycle it? All I can think of is optimization, and if you’re making this your default style, it sounds like premature optimization. Allocation and de-allocation is pretty cheap. Reusing the memory makes it harder to detect accidental aliasing; it will thwart pretty much all of the techniques for automatically detecting that.

            And I never free any memory when I quit the program unless the Win32 API documentation states that this or that must be freed or unlocked first.

            While there is a big advantage in a fast shutdown, there are several dangers. First, you’re going to make it very hard to use a memory leak detector. Also, if you’re using C++ and your coworkers are relying on destructors being called to handle final cleanup, it won’t be done. Sure, memory and sockets and some other things will get cleaned up, but temporary files, SOAP sessions, and can will be leaked.

            At most places, these habits will not make you friends with your co-workers.

            1. Just letting the program exit and not free the heap is actually MicroSoft’s own recommendation.

              Also you mention coworkers, luckily I have none. But even if I did, a project would have a agreed upon practice.
              And in the case of different languages used one could always compile to DLLs, using a modular approach to building a program.

  24. Mersadeon says:

    Shamus explains a lot of stuff better than both my Informatics Prof AND my OO Java tutor. I wish I could take classes with him, to be honest. Also, that hybrid style seems wonderful (at least when you code alone, I suppose when you’re in a team you really have to adhere to strict OO rules to make it easier).

    1. I would not be surprised that when Shamus gets too old to code (feels two eyes glaring),
      that he might end up doing some for design tutorials/design classes, theory classes of some sorts.

      Nothing more difficult for a programmer or technical guy to try and dumb down stuff so others that now less or very little can understand you, after all, sometimes we can’t even understand our own code at times.

      When you yourself stare at a piece of code you have written and go “OK! I understand what it does but I have no idea how I came up with the idea to do it this way, when did I write this code? 02:00 Sunday night? I must be going senile or something here…)

      It also does not help that a lot of things that are similar but a little different but has overlapping functiona,lity can be confusing to beginners you try to explain to either.
      Like structure vs object, or object functions vs procedures with a structure pointer, and so on.

      But I’m impressed with Shamus’ ability to explain things in a generally digestible way. Maybe having kids is part of the equation. Or maybe seeing how crappy the school system was first hand is part of it, or a combo of both.

      Or maybe, Shamus is just really talented at typing shit for other folks to read. :)

  25. lazybratsche says:

    Thanks for this post. I’m not a programmer, but as a scientist I hack around a bit with R to analyze my data. My formal programming experience starts and ends with a class on C++ I took in high school. Every so often when I stumble over epic internet arguments about Object Oriented programming or whatever, I’ve been puzzled about what everyone is arguing about and why I should ever care.

    With this post and the rest of your series, I’m realizing that all y’all professional programmers are dealing with orders of magnitude more complexity and interactions and ways for things to go wrong. For me, most of my data analysis scripts are simply ImportData, CleanUpData, TransformData, AnalyzeData, GraphData, etc. Really there’s very little room for something to go wrong that’s not a straightforward mistake on my part. So I suppose plain ol’ imperative programming is exactly the right approach for me.

  26. “space_marine.Damage (grenade_damage);”

    This is no different than doing this:
    Damage(*space_marine, grenade_damage);

    Here Damage() is a procedure/function, the first parameter is a pointer to the space_marine structure (or object if you roll that way, in this case they are almost synonymous), and second parameter is the damage.
    You can easily add a sanity check to the damage and to the npc/player/rock that is taking damage.

    I used to do a lot of functions that had a lot of parameters, or globals.
    But now I’m addicted to functions that take a pointer to a structure, and then none or more paramaters that do something to that structure, or based on that structure.

    I still do have “globals”, but my “globals” are all in a structure instead, and I have one single global variable that points to that structure instead.
    I also use Init and DeInit functions to allocate or populate a structure and then free or null it. Not unlike new and destroy in many OOP languages.
    Only that I do this in a procedural language, and no garbage collection (it’s all manual baby).

    Always choose wisely, sometimes a structure you just pass a pointer to may be all you actually need.

    Also if you set or get something using a object function then you get overhead, this can obviously be avoided by simply using unsigned and signed where appropriate (I mentioned this in another comment here).

    But OOP Get or Set stuff does not guarantee things will work as expected, some idiot may just decide to improve the Set function of a object and now shit is going haywire all over (maybe they changed from signed to unsigned or vice versa?)

    Procedural is also just as weak, if the procedure (or function as some call it from time to time) in some include is messed with or somebody changes a structure value from signed to unsigned or vice versa you get the same issue there.
    OOP is just a different way to code than Procedural, you can do the exact same stuff using either of these approaches (people did code before OOP, and OOP did not revolutionize anything practically speaking).
    What can fuck you up is that some bozo, some yoyo, some shmuck changes something about some piece of code that screwes up a lot of code that relies on that,
    or they fail to follow the internal guidelines for the project.

    Important note! Each project should have a set of guidelines to ensure consistency and less chance of bugs being introduced.
    So if you are 1+ on a project, start to write a damn manual documenting the functions, source comments are fine, but nothing beats a manual documenting stuff and you can search and reference it while you are writing/editing source code. (nothing worse than scrolling/looking through source to find the comment with the info you need).

  27. Andy K says:

    Wow – that was a brilliant articulation of the different paradigms – thank you!

    Sounds like you have adopted the pragmatic paradigm; using OO where it makes sense and limiting side effects where possible – make it as simple as possible but no simpler :p

    Anyway, nice article; as always. Enjoying the series immensely and looking forward to giving real cash moneys for the game when it comes out.

    1. Paul Spooner says:

      Yeah, I’m a big fan of the pragmatic style as well. I’ve been told by professionals that my code is “messy” and “poorly structured” but then they comment on how quickly it runs, and how robust the output is. I’d guess the same is true of Shamus’ code. It’s easy to look down on informal code structure, but if it works at the end of the day as well as the beginning then I’d be more interested in learning than lambasting.

      1. Nathon says:

        I’m not prepared to comment on the clarity of the code Shamus produces, but “if it works at the end of the day as well as the beginning” is the wrong time frame. As a professional programmer, I’m much more interested in whether or not it works 6 months later, when weird features have been added by people who didn’t have time to fully understand how it worked to begin with (or wouldn’t have if it had been messy, hard to follow, and poorly documented).

        Thinking hard about structure is not always worth it. Sometimes your code gets run once and thrown away. “It runs faster” is only a good reason to have ugly things if you have profiled the equivalent but pretty code and decided that it’s too slow to do its job. That does not happen very often.

      2. Canthros says:

        The long and the short of it is that performance isn’t the whole story for most software projects. Maintenance cost far outweighs the cost of initial development for a great many ‘real’ projects. So, code structure matters, even if it’s not the first and most important thing to worry about.

        1. Paul Spooner says:

          I often wonder why, if maintenance costs so much more than development, we don’t re-write more code from scratch.
          Yes, I realize inertia and sunk costs and such, but even so…

          1. Alan says:

            Was that some very dry humor, or sincere?

            1. Paul Spooner says:

              Can’t it be both?

              As if we’re going to re-write every architecture from scratch? Nonsense!

              And yet, we do it for toilet paper, plastic forks, keyboards, and airline production lines. The rules are generally the same, and patterns emerge, and lots of stuff gets re-used, but a lot of stuff gets re-built instead of maintained. I mean, at some point it’s going to be more cost effective to write working but hard-to-maintain code and then simply re-write the whole thing before it stops working. I don’t know where that threshold is exactly, but it exists. We do it with cars (car analogy!) so why not with software?

              Not saying anyone here thinks like this, but I get the impression that software engineers have no concept of wear, and lifespan. It’s like they think software is this untouchable perfect thing that will last forever. Its not, it wears out just like a bearing or a building. Eventually you need to design a new one.

              Certainly easy-to-maintain code is preferable, but it comes at a cost, and that cost is not always worth paying.

              1. Alan says:

                Joel Spolsky explains far more eloquently than I can manage why rewriting from scratch is usually a mistake. I recommend “Things You Should Never Do, Part I” and “Netscape Goes Bonkers“.

                1. Paul Spooner says:

                  Good articles!
                  So, it doesn’t matter if the code is ugly, as long as it works? I think that was the point I was trying to make at first.

                  And yes, ideally one would write code that is easy to write, easy to maintain, works perfectly forever, and has no bugs. But, since we have to make trade-offs, I’m going to generally err on the side of “this code runs” instead of speculating on what kind of maintenance or feature creep is going to rear up in the future, distant or otherwise.

                  1. Alan says:

                    That’s not the message I took from it. I got, “the code may be ugly, but it works, and that’s strictly better than throwing it away and starting from scratch.” I don’t see it as an endorsement of writing ugly code in the first place. A lot Spolsky’s articles are about doing things in a way that helps maintence. For example, his piece on Hungarian notation convinced me that it was a really good idea, and that I’d what I hated was erroneous Hungarian notation.

                    (On that note: anyone who thinks Hungarian notation is stuff like “unsigned long ulCoordX”, read Spolsky’s article for how it was meant to be used, and why it can be useful.)

              2. Canthros says:

                Some software is like a disposable utensil, some software is a durable good. The way one addresses each is different.

                If your code is so great it never, ever needs to be touched again, great! Structure it however you want. If that’s not the case, a little care to readability, encapsulation, etc. might be worth the investment.

  28. John Lopez says:

    One way to deal with the traditional problem of object oriented design is to turn things upside down a bit. Instead of expecting classes to do everything, classes are expected to expose events that “observers” can subscribe to and then do the magical things that a given subsystem expects, leaving the object oblivious to these actions.

    This isn’t a native C++ feature, but most frameworks (Qt, SDL, Windows, etc…) do provide them.

    What observers bring to the table is the fact that your space marine can simply raise a Walking event and the sound system can update the walking sounds as needed (staring, continuing, switching between sounds based on surface, cycling sound options to avoid obvious “looping”). Meanwhile the game-play system determines the “physical” results of the attempted move and the graphics system eventually gets notified of the updated location/orientation/status of the unit.

    The observer and the observed can then cooperate, the observed maintaining the state of the object while the observers maintain the state of the *impact* of that object on the game.

    Which isn’t saying it is a silver bullet… there is overhead in such systems. However, they are immensely flexible when the workload is divided well and the state objects provide a robust set of events to observe.

  29. Neil Roy says:

    I’ll stick to pure C for now. I am currently using the C 2011 standard. I am comfortable with pointers and the like. While I have experimented with C++, I found myself taking more time to solve problems that C++ produced where as with C, I got the job done, error free, usually the first time I coded it! I find C++ bloated. All my C code is commented, if you don’t know what I am doing when you look at my code from my comments, than you’re an idiot and should stick to BASIC programming. ;)

    I use structs to make “objects” with their own functions, which reside in their own C file. I am working on a game now, 100% C (2011) and have been surprised at how few errors I have had. When I started it I tried to do it in C++ and it was an excersize in frustration, and there was no WAY I was going to go online and ask questions in some forum, my experience with forums and getting answers is similar to some of the posts Shamus talked about with his “backing up the car 2 feet” analogy. :)

    1. Svick says:

      I think it’s pretty obvious that if you’re programming in a language that you know well, you’re going to be more productive (and write code with less bugs etc.) than when you’re programming in a language that you don’t know yet.

      That’s an argument to stay with the language you know in the short term, but it doesn’t mean the new language is worse. And in the long term, I think it’s a good idea to actually learn and understand other languages, for two reasons:

      1. You might find that the new language is actually better and start using it.
      2. You might find that the new language has some interesting ideas, that might make your code in the old language better (e.g. emulating virtual functions in C after trying an object-oriented language, or using higher order functions in C++ or C# after trying a functional language).

      Specifically about C, when I programmed in it a bit recently, the thing I missed the most from C++ weren’t objects, it was generic collections.

      In the code I was writing, there were several linked lists of different types. Doing that using C++ templates (or C# generics) is trivial, even if the standard library didn’t already contain it. But I think that doing it cleanly in C is pretty much impossible.

      One more thing regarding forums: have you tried Stack Overflow? I believe it’s much better for asking about programming than forums.

Thanks for joining the discussion. Be nice, don't post angry, and enjoy yourself. This is supposed to be fun. Your email address will not be published. Required fields are marked*

You can enclose spoilers in <strike> tags like so:
<strike>Darth Vader is Luke's father!</strike>

You can make things italics like this:
Can you imagine having Darth Vader as your <i>father</i>?

You can make things bold like this:
I'm <b>very</b> glad Darth Vader isn't my father.

You can make links like this:
I'm reading about <a href="http://en.wikipedia.org/wiki/Darth_Vader">Darth Vader</a> on Wikipedia!

You can quote someone like this:
Darth Vader said <blockquote>Luke, I am your father.</blockquote>

Leave a Reply to Volfram Cancel reply

Your email address will not be published.