More Comments on Comments

I was reviewing the blog yesterday and looked at my Comments on Comments article. As often happens when you revisit code after a while, I think I can do better. So let’s give it a try. Here I am standing in Kuula with my trusty rotating cube.

 

Scripting in Kuula
Scripting in Kuula

Here’s our program as we left it last time:

// This script toggles a the rotation of an object

startRotation() {
    vector zAxis = <0,0,1>;
    llTargetOmega(zAxis, 4, 1);
    g_is_rotating = TRUE;
}

stopRotation() {
    llTargetOmega(<0,0,1>, 0, 0);
    g_is_rotating = FALSE;
}

toggleRotation() {
    if(g_is_rotating) {
        stopRotation();
    } else {
        startRotation();
    }
}

integer g_is_rotating = FALSE;

default {
    touch_start(integer num) {
        toggleRotation();
    }
}

I think it’s about time to take the typo out of that initial comment, don’t you? My point about comments lying must be made by now. I’ll do that before we’re done.

But that’s not my real purpose today. Notice that integer variable g_is_rotating. It is TRUE when the object is rotating and FALSE when it isn’t. This variable is just used to keep track of, well, whether we are rotating. On touch, we check the variable and decide whether to start or stop rotating. We call the appropriate function, and in the function we change the flag. This is not very attractive in my opinion. 

One way of looking at it is that the variable g_is_rotating is used a lot. It’s a kind of duplication. 

Another thing I notice is that the start_rotation function uses a variable, zAxis, to express its rotation but the stop_rotation does not. I must have been half-way through using that variable when I stopped. This is not good: code that is similar should look similar. (And when it is similar enough, the similarity should be removed altogether.)

But one thing at a time. Let’s begin where I plan to begin:

State

The g_is_rotating variable is called a “state variable”. It keeps track of the “rotation state” of the object, namely whether or not it it rotating. LSL has a feature which is useful for just this sort of thing, called “state”.

LSL programs can have multiple “states”. Every program has at least one state, “default”, and they can have more than one. I’m going to change this program to use states. The idea will be this. There will be two states, rotating, and not rotating. When the object it touched, it’ll go into the other state. This should simplify the code a lot. Let’s try it. All the new and changed code is bold:

default {
    state_entry() {
        stopRotation();
    }

    touch_start(integer num) {
        state rotating;
    }
}

state rotating {
    state_entry() {
        startRotation();
    }

    touch_start(integer num) {
        state default;
    }
}

So this seems simpler. In the default state, where we start, we stop rotation. When we are touched, we go to the rotating state. When we enter that state, we start rotation. When we are touched, we go back to default, stopping rotation. Neat.

This means that now I can remove the g_is_rotating variable, and all the references to it. I have a trick for that. I just remove the variable definition, “integer g_is_rotating = FALSE”. Then I save the script. The LSL compiler gives me an error, referring to a line using that variable. I fix the line, save again. It gives me another error. And so on.

Naturally, I’m smart enough to find and fix all the occurrences, at least in this simple program. But I find it kind of amusing to make the compiler help me. Try it, you might like it too. Here we are without the variable:

// This script toggles a the rotation of an object

startRotation() {
    vector zAxis = <0,0,1>;
    llTargetOmega(zAxis, 4, 1);
}

stopRotation() {
    llTargetOmega(<0,0,1>, 0, 0);
}

default {
    state_entry() {
        stopRotation();
    }

    touch_start(integer num) {
        state rotating;
    }
}

state rotating {
    state_entry() {
        startRotation();
    }

    touch_start(integer num) {
        state default;
    }
}

When the compiler got me to the toggleRotation function, shown below, I realized that it wasn’t used at all, so I deleted the whole thing.

toggleRotation() {
    if(g_is_rotating) {
        stopRotation();
    } else {
        startRotation();
    }
}

OK. Now let me get the z-axis thing under control, and fix the comment. Then we’ll be done for now:

// Make an object start and stop rotating on touch.

vector zAxis = <0,0,1>;

startRotation() {
    llTargetOmega(zAxis, 4, 1);
}

stopRotation() {
    llTargetOmega(zAxis, 0, 0);
}

default {
    state_entry() {
        stopRotation();
    }

    touch_start(integer num) {
        state rotating;
    }
}

state rotating {
    state_entry() {
        startRotation();
    }

    touch_start(integer num) {
        state default;
    }
}

Summing Up

The script above looks a lot better to me, and I hope it does to you. One thing you may wonder about (well, two things) is the tiny functions startRotation() and stopRotation(). They each only have one line in them, so you may wonder about whether we should just take their contents and put them where the functions are called.

I would not do that. The coding pattern here might be called Explaining Function Name. The function name explains what the code inside does. Otherwise, to know what the code does, we would have to look at the function itself. Then we would have to look up llTargetOmega’s details, and we’d probably be tempted to add a comment to each one saying what it does. This way we need not do that.

And that’s the point. Clear code reduces the need for comments. Thanks for reading!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: