[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.5.2 Abusing defines

A common mistake is to put HUGE arrays and mappings in a define. It's very tempting really, assume for example that you have a mapping that contains the definitions of guild ranks, descriptions, various skill limits, benefit adjustors etc in one big mapping with the rank as index. Very often you'd then need to index that mapping to look up things. Probably it'll be done dozens of times in the central guild object. You'd have something like this:

 
// Top of file

#define GUILD_MAP ([ "new": ({ "beginner", "Utter newbie", 3, 2343, ... }), \
                     "older": ({ ....                                        \
                     ... /* Perhaps another 10-20 lines or more */        \
                   ])

// code, example of use
        write("Your rank is: " + GUILD_MAP[rank][1] + "\n");
// more code...

However... just pause for a second and consider what the #define statement really does... well, it substitutes whatever you had as a pattern for the #define body. So, in every instance where you had written GUILD_MAP the entire mapping would be copied in. And every time it was put in, the gamedriver would have to interpret, store and index the mapping again. It doesn't take a genius level of intelligence to realize that this is a horrible waste of both memory and time.

So... instead of doing it this way you store the mapping in a global variable. Then you use that variable as you use the define. I.e.

 
// Top of file

mapping GuildMap;

create_object()
{
    // code

    GuildMap =  ([ "new": ({ "beginner", "Utter newbie", 3, 2343, ... }), \
                   "older": ({ ....                                        \
                   ... /* Perhaps another 10-20 lines or more */        \
                 ]);
}

// code, example of use
        write("Your rank is: " + GuildMap[rank][1] + "\n");
// more code...

While #defines are easy to use and seemingly convenient, they can also easily break your code if you don't think twice and then yet another time before using them. Again, as the interpreter just replaces whatever you have used as a key with the aliased text, you can easily get into trouble even when you belive you're in the right.

Consider this seemingly inocuous example:

 
#define SQUARE(a)  ((a) * (a))

Now consider what happens when you try this:

 
int s, x;
s = 3;
x = SQUARE(s++);  // You might _think_ x = 9 and s = 4 when this is done.

Well, like I said, the preprocessor happily substitues the pattern you specified, and what you end up with is:

 
int s, z;
s = 3;
x = s++ * s++; // This makes x = 12 and s = 5!

Variations on this theme makes #define a truly double-edged sword. So please use them as sparingly as possible for as simple tasks as possible. The basic rule is to keep macros short and fairly simple, however even then you can't be certain you won't be bitten somehow.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

This document was generated by Hekay Permer on April, 20 2005 using texi2html