Monday, March 23, 2009

Pointers to Pointers

When you first learn about pointers, it takes a little while to get that aha moment. They're a bit like recursion and closures in that respect. Then, just when you think you've got it, get shown pointers to pointers. You understand the concept, but can't really figure out where they'd be useful. So you look at the examples, but you still can't see their use. The examples are just so contrived, that you're left thinking, I'm never really going to need to pointers to pointers.

Delphi does a pretty good job of hiding anything to do with pointers from you, and you can go for years without using a pointer if you really didn't want to. I resort to pointers quite often, but I can't really remember a time when I really needed a pointer to a pointer. That is until this weekend.

I was looking at the jclExprEval unit in the Jedi Code Library. Now the code as it stands make it very easy to add variables.

var
A : Double;
B : Double;
...
...
begin
ExprEval.AddVar('A', A);
ExprEval.AddVar('B', B);
CompiledExpression := ExprEval.Compile('A+B');
Result := CompiledExpression;

The variables A and B are internally stored as pointers to double. This is all well and good, and this works fine. Now what I wanted to do was to be able to compile an expression once, and repeat it multiple times over an array of values. Actually each variable in the formula is an array. I wanted to do something like


var
DataA : array of double;
DataB : array of double;
A : pDouble;
B : pDouble;
...
begin
A := @DataA;
B := @DataB;
ExprEval.AddVar('A', A);
ExprEval.AddVar('B', B);
CompiledExpression := ExprEval.Compile('A+B');
i := Length(Result);
while i>0 do
begin
Result[i] := CompiledExpression;
Inc(A);
Inc(B);
Dec(i);
end;

I thought initially I'd just override AddVar so it can take a pointer to a double, and store it directly. That was before I thought about it properly. When I did think about it, I realised it wouldn't work. Since the variable internally is stored as a pointer to a double it is basically a copy of A. at least initially it is.


Pointer to double

Incrementing the pointer A just gives you the following

Increment pointer

As soon as you see the picture the solution is obvious.

Pointer to a pointer

A pointer to a pointer! We can manipulate A anyway we like, and our internal copy still points to the right place. Whereas before to get to the value of our variable we'd de-reference the pointer once, now we have to be careful and do it twice. I had to write quite a few classes and methods (basically replicate the whole structure that handled pointers to handle pointers to pointers) to get this to work, but as I said before, the code is well written, and extending it to do what I want was really easy. So while pointers to pointers and even simple pointers are not essential (as I'm sure a load of C# developers will tell me) they do have a place in a Delphi programmers toolbox.

No comments: