What's a Configuration Object, and Why Bother Using It?

It's a pain to have to change the parameters of a function; you have to change every other call to that function in order to avoid errors. But you can get around this by using just one parameter: a configuration object.


What It Looks Like

Here's a silly example of a function for creating a robot:

Now, here's the same example, using a configuration object:

I've highlighted the lines that require changing; you can see that there's not much difference.


Why Bother?

So if there's hardly any difference, why would we bother doing it the second way? After all, it actually makes the function a little harder to use; whereas before our IDE would be able to give us this information about the parameters the function expected:

...now it can only give us this:

Suppose you want to add a couple more parameters: one specifying the material to use and another to specify what color its laser should be. That's not too hard, in either case:

So far, still not much of a difference. What if you want your robots to all have red lasers by default? Simple again. Without a configuration object, you just need to change the method signature (the function line), and then you can remove the last argument from the function call:

With a configuration object, it's a little trickier - though not much:

Okay. Now suppose you find that you're setting almost all of your robots to be evil (I mean, why not?), so it's actually kind of a pain to write "evil" as a parameter every time. Naturally, you want to set "evil" as the default - but you don't want to set a default material.

The only way you can do this, with a regular set of function parameters, is to switch the order of the personality and material parameters:

Ah, but now you have to switch the order of the arguments round on every single function call!

A configuration object doesn't give you this problem. Check it out:

Neat! All your old generateRobot() function calls will continue to work, but you can create new calls that don't bother specifying personality.

You can even decide to get rid of the personality parameter altogether:

The above version of the function doesn't refer to conf.personality at all - but you won't get an error if you still have calls like this:

Of course, you might get a few confused users if you have calls like this:

...since all robots are now evil. But at least the code will compile.

For the same reason, you can change the order of the arguments without it mattering at all, and even add in new parameters that don't do anything yet:


Making It Easier to Set Defaults

The code for setting the defaults is easy to understand so far, but is going to be very annoying to extend if we need to have lots of parameters:

Let's write some more general code to cope with it:

That for loop may be a little confusing, so I'll break it down. First, look at this:

This is a for...in loop, which will output the names of the keys inside the default object:

Next, look at this line:

This will output red - it's the same as writing trace(defaults.laserColor).

Following on from that, look at this example:

What do you think this will output?

Well, example["demo"] is the same as example.demo, which equals "test". But example.foo does not exist, so example["foo"] will return null. This means that !example["foo"] (note the exclamation mark) will be equivalent to true.

Put that all together, and you should be able to understand why this code works:

Give me a shout in the comments if you need a hand!

I Want More!

For an even quicker version, try this:

The change in Line 1 (and new Line 2) means that even the conf object itself is optional, so you can just call generateRobot(). (Of course, you'll need to change the code to deal with the values that don't currently have defaults.)


Helping the IDE Help You

As I mentioned above, the IDE can't give you any tips about what parameters a function is expecting, if that function uses a configuration object. This is a major drawback, as it can make your code really hard to use; you have to remember which parameters go in the conf object, as well as all of their names and types.

But we can still display this information to the coder when it's needed; we just have to do so manually, like so:

Now, if I start to write a call to this function in FlashDevelop (my IDE of choice), I see this:

Sure, it's a bit of a pain to keep this manually updated, but in many cases it's worth it.


Conclusion

I'm not claiming that you should use a configuration object for every single function you create from now on; just think of it as another useful tool in your arsenal.

Personally, I find it a particularly useful pattern whenever I'm building the first draft of some set of classes that all need to work together. The added flexibility of a conf gives me so much more flexibility, freeing me up to zip around all the different functions and changing how they call one another, without worrying about breaking the code by inserting or removing a parameter.

Remember the benefits:

  • It's easy to add and remove parameters (at either end).
  • It's easy to set default values.
  • You don't have to worry about the order of the parameters.

There are drawbacks to using simple objects like I have, though - especially if you do so in a project that's past the prototyping stage. Check out the great comments below for more details!

Tags:

Comments

Related Articles