Monday, July 13, 2009

the zen of curly braces

As one of the unwashed millions who hopes to make his fame and fortune as an iPhone developer, I've been learning Objective-C. My main teacher has been "Programming in Objective-C 2.0" by Stephen Kochan, a book which deserves its accolades.

At some point, Kochan says something like, "In general, you can substitute a block of code for a single statement." I thought about that for a second and realized that, simple as that sounds, I'd never really thought about it before.

Of course, I know that you can -- in all the c-family languages -- write...


if ( condition ) statement;


or


if ( condition )
{
block;
of;
statements;
}


... but I hadn't considered statement/block substitution as a general rule.

To test things out, I tried this timeline code in an AS3.0 fla:


{
var a : int = 3;
trace( a );
}

{
for ( var i : int = 0; i < 10; i++ ) trace( i );
}

{}


And it worked!

Now, it's not that I think this is useful. I don't. But I love it when I can generalize some specific behaviors into a principle. When this code worked, I felt some contents drifting together. I suddenly understood a bit of Actionscript grammar that I'd never really considered before.

Actually, I can think of a use for this: refactoring. Say that as a first draft, you write a method like this:


public function init() : void
{
drawBackground();
drawPlayer();
drawEnemies();
setPlayerLives();
setPlayerStartingPosition();
drawPlayerShip();
setEnemyStaringPositions();
setEnemyStrength();
setPlayerStrength();
startGame();
}


Your first step in refactoring could be to group statements into blocks:


public function init() : void
{
{
drawBackground();
drawPlayer();
drawEnemies();
}

{
setPlayerLives();
setPlayerStartingPosition();
}

{
drawPlayerShip();
}

{
setEnemyStaringPositions();
}

{
setEnemyStrength();
setPlayerStrength();
}

startGame();
}


I like this, because it suggests groupings without affecting functionality. init should run exactly the way it did before you added the blocks.

Having added them, you can see some better ways of organizing the statements:


public function init() : void
{
{
drawBackground();
drawPlayer();
drawEnemies();
drawPlayerShip();
}

{
setPlayerLives();
setPlayerStartingPosition();
setPlayerStrength();
}

{
setEnemyStaringPositions();
setEnemyStrength();
}

startGame();
}


This, with a little cutting and pasting, leads naturally to...


public function init() : void
{
renderGamePieces();
initPlayer();
initEnemies();
startGame();
}

private function renderGamePieces() : void
{
drawBackground();
drawPlayer();
drawEnemies();
drawPlayerShip();
}

private function initPlayer() : void
{
setPlayerLives();
setPlayerStartingPosition();
setPlayerStrength();
}

private function initEnemies() : void
{
setEnemyStaringPositions();
setEnemyStrength();
}


incidentally, going back to my original example...


{
var a : int = 3;
trace( a );
}

{
for ( var i : int = 0; i < 10; i++ ) trace( i );
}

{}


... I found that double nesting works, too:


{
{
var a : int = 3;
trace( a );
}

{
for ( var i : int = 0; i < 10; i++ ) trace( i );
}

{}
}


As does triple nesting:


{
{
{
var a : int = 3;
trace( a );
}

{
for ( var i : int = 0; i < 10; i++ ) trace( i );
}

{}
}
}


And so on.

Strangely, this doesn't work:


{
var a : int = 3;
trace( a );
}

{
for ( var i : int = 0; i < 10; i++ ) trace( i );
}

{};


The problem here is the semi-colon after the final close-brace. It throws this error:

Syntax error: extra characters found after end of program.

I got the same error when I added an empty block to the start of the frame code:


{}

{
var a : int = 3;
trace( a );
}

{
for ( var i : int = 0; i < 10; i++ ) trace( i );
}


And I also got it when I added an empty block in the middle of the code:


{
var a : int = 3;
trace( a );
}

{}

{
for ( var i : int = 0; i < 10; i++ ) trace( i );
}


For some reason (that I don't understand), the AS interpreter assumes it's reached the end of your code when it finds an empty set of braces. The empty set doesn't cause an error on its own, but you will get an error if there are any characters following the the close-brace. This isn't a problem, since I can't think of a reason to ever include an empty block. But I am curious about what's going on.

No comments:

Post a Comment