How useful closures are!

As some of you may be aware, I'm working on a pure-perl Z80 emulator. Why? <shrug> Why not! And we can't go letting the 6502 boys have all the fun!

It also makes a very good example of how useful closures can be. Here's just one example.

The Z80 is an 8 bit processor, with several 8 bit registers. But it also has some 16 bit "reigster pairs", which are made up of two 8 bit registers that can be treated as a single larger register. For example, the 8 bit register B and C can be combined to make a 16 bit register BC. Any operation that changes B or C
also changes BC, and vice versa. Now, to implement them, I could have lots of hairy logic so that any instruction that operates on BC actually operates on both
B and C. But that would lead to lots of duplication of code, for all the register pairs, and for all the instructions that operate on 'em.

I already have a::Register8 class for an 8 bit register, and a Register16 class
for real 16 bit registers such as the Program Counter (a register that points at the next instruction to execute) which store a value and have get() and set()
methods. So, I thought, instead of putting lots of hairy logic in the instructions themselves, I could move it into the registers so I'd only have to write it
once. The Register* classes already have a 'value' field for storing the register's current value. So I changed Register16 to have either a value field or a pair of 'get' and 'set' fields, depending on how the register was initialised in
perl. If it has a value field, then get() and set() simply operate on that. But if instead it has get/set fields, then get() and set() call those code-refs instead.

and then as far as implementing the actual Z80 instructions goes, I can just get() and set() sixteen bit registers with a single method call, instead of doing all the multiplication, shifting, bitmasking and so on every time. Note that I use a variable $self inside the two anonymous subroutines without declaring it with my. This isn't a bug. That is the $self in the code that creates the anonysubs. It has nothing to do with whatever
$self might be inside a Register16 class's get() or set() method.

But there are actually several register-pairs, so I went one step further. Instead of repeating that chunk of code several times, once for each pair, I did this:

In this case, I pass $self and the names of two 8 bit registers to
the _derive_register16 function. That function then creates and returns a Register16 now "closing over" 3 variables.

Closures rock. By combining objects and closures I have ended up writing a lot less code. And by reducing the amount of duplication in my code, when
I inevitably find a bug, I'll have just one place to fix it, instead of having to remember all the hundred places where I twiddle register pairs. If you ever find yourself writing the same code over and over again just with minimally different data, this is a useful technique.

You can see what I'm up to on this project by looking at the CVS repository.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
Without JavaScript enabled, you might want to
use the classic discussion system instead. If you login, you can remember this preference.