arganx wrote:
Before I had a good idea how to use pointers, I was wondering - first,
how to use them. And second, of what value would they be.
Now that I have at least a pretty good idea of how to use them, I am
still wondering of what real value are they?
Pointers are unnecessary to express computation. Everything can be
expressed in a functional programming language which banishes
assignment.
If you never assign to a variable or any part of an object, you don't
care whether you are dealing with reference or value passing semantics.
If a function does something with an object, it simply takes that
object as an argument. You don't care whether it's a reference or a
copy is made or what.
Pointers come into play when you allow assignment. Suddenly, the
identity of an object matters, because when you change an object, every
place in the program that has a pointer to that same object will see a
changed object. Whereas copies of the object are immune to that change.
You can now tell the difference between a function which did something
to a copy of an object, and one which received a reference to the
caller's object.
I'll admit - its pretty sexy to be able to assign values indirectly,
but what I'm trying to figue out is why it is any better than assigning
the values directly.
Because when you assign values directly, you fail to separate the
algorithm from the data that it operates on. The code knows where to
find an instance of the data to work on. If you want it to do something
with a different instance of the data, you have to instantiate a new
version of that code, in which the direct reference is patched to refer
to the new instance.
A pointer just lets you pass in the identity/location of the data to be
worked on, so the same instance of the code can do the job.
If you think that's ridiculous, I can cite a recent example where this
has been done in production code (not counting the millions of bloated
C++ templates out there which instantiate nearly identical versions of
the same code). Not long ago, the Linux kernel had a driver for ATAPI
CDROM devices which was compiled multiple times if you had more than
one of these drives attached to your machine and wanted to drive each
one. The driver was compiled as many times as the number of instances
you wanted. Nearly the same C translation unit was passed through the
compiler multiple times, only with some preprocessor symbols being
altered to avoid conflicts among the instances.
This allowed the driver to have only direct references to static
variables, rather than pass around some numeric index or pointer
representing which instance of the CD-ROM drive it was working with.
I will tell you another funny story. Years ago as a little boy, I was
learning to hack in 6502 machine language. I was so eager to get coding
(as I still am today) that I put down the book and decided to write a
fast routine to flip the pixels on the high resolution screen from
black to white and vice versa.
I considered the simple instructions I knew so far and then hit a
stumbling block. How to make the program iterate over the video buffer?
I knew how to load from a fixed address to a register, compare, and
branch and that sort of thing.
So I wrote a self-modifying program. The program contained an
instruction to fetch data from a fixed address, invert the bits, and
then store back to that address. The looping step would then patch
those instructions to the next address, compare and loop back. Worked
like a charm, but I didn't like how the program ended up being a
different program at the end of the loop, and how it had to know its
own location in memory.
I then went back to the book. The next chapters covered the use of
pointers. Or rather, various addressing modes, allowing a combination
of data in memory and registers to achieve indirect references. I was
relieved: I knew there had to be a better way! Soon, I rewrote that
routine with one that wasn't self-modifying.
But you know, the original code didn't really avoid the use of
pointers. It just abused storage locations within the program's
instructions itself into behaving like pointers.
To actually avoid pointers for real (or almost!), you'd have to write a
huge, long program, in which each word of the screen buffer is
manipulated by a dedicated sequence of instructions, which is hard
coded with a direct reference to that word's address. If the buffer has
some 8000 words you string together a 24,000 instruction program. load,
invert, store, load, invert, store.
LDA $2000 ; load first 8 bit word of frame buffer into accumulator
EOR #$FF ; flip the accumulator's bits
STA $2000 ; store back.
LDA $2001 ; do the next 8 bit word
EOR #$FF
STA $2001
On that machine, there wouldn't have been enough space to store that
program. :)
I say this almost eliminates pointers, because there is one pointer
left: the instruction pointer by means of which the CPU advances
forward through these instructions!!!
You can't do anything on a Von Neumann box without pointers, because
you can't even step from one instruction to the next. To make a machine
without pointers, you need a different architecture. Like maybe
something that feeds a tape over a read/write head. But then the
position of the tape is a pointer. :)