- Unix file descriptors are small-integer array indices into, normally‚ arrays in kernel space.
- Many Smalltalk implementations, especially on older machines, named objects in memory with small-integer indices into a global object table (typically shifted in some way to accommodate tagged SmallIntegers) which was implemented as an array of pointers to the real object locations.
- Functions exported from DLLs on Windows can be identified by "ordinals" that index a table of all exported functions instead of by name.
- PalmOS, Win16, and Pre-X MacOS identified allocations of memory from the operating system by "handles" which were, again, indices into a table of pointers, the master pointer block. To access the actual memory you would call HLock() (MacOS name) and index the table (yourself, on MacOS, or using the return value from the lock function on PalmOS or Win16) to get the physical address, which could change if the handle was unlocked.
- Forth maintained an in-memory buffer cache of 1024-byte disk blocks, which it identified by ordinal number rather than, say, cylinder/head/sector tuples or inode+offset tuples. To get the memory address of block 53, you would say 53 block (Forth for "block(53)") and freely index into those 1024 bytes, which were guaranteed to remain resident until the next call to block or until you yielded the CPU with another I/O operation. If you modified the data there, you would call update to tell Forth the buffer was modified. If block 53 was not currently in memory, Forth would pause your task until it had loaded it, running other tasks meanwhile. If there was no free block buffer, Forth would free one up, by writing out a modified buffer to disk if necessary. This provided a sort of virtual memory in about 100 lines of code without requiring memory-mapping hardware. (The "BLOCK I/O" part of F83's KERNEL86.FS is 8 16-line screens long, but a fair bit of that is actually dealing with MS-DOS's file I/O functions.)
- Because standard Pascal had no string type and no way to handle variable-length arrays of any kind, TeX uses indices into a string table as its string type. It inserts newly encountered strings in the string table.
How noticeable the performance impact is depends a lot on how often you have to traverse the extra level of indirection. (Doing a base+offset addition before each memory access could be a significant performance issue on things like a Commodore 64 or a TRS-80 but basically doesn't matter on 8086 or better hardware.)
Aw, thanks! I worry I'm often too disagreeable in my replies, and I usually only see people arguing with them, so it's nice to see that someone appreciates them.
- Unix file descriptors are small-integer array indices into, normally‚ arrays in kernel space.
- Many Smalltalk implementations, especially on older machines, named objects in memory with small-integer indices into a global object table (typically shifted in some way to accommodate tagged SmallIntegers) which was implemented as an array of pointers to the real object locations.
- Functions exported from DLLs on Windows can be identified by "ordinals" that index a table of all exported functions instead of by name.
- PalmOS, Win16, and Pre-X MacOS identified allocations of memory from the operating system by "handles" which were, again, indices into a table of pointers, the master pointer block. To access the actual memory you would call HLock() (MacOS name) and index the table (yourself, on MacOS, or using the return value from the lock function on PalmOS or Win16) to get the physical address, which could change if the handle was unlocked.
- Forth maintained an in-memory buffer cache of 1024-byte disk blocks, which it identified by ordinal number rather than, say, cylinder/head/sector tuples or inode+offset tuples. To get the memory address of block 53, you would say 53 block (Forth for "block(53)") and freely index into those 1024 bytes, which were guaranteed to remain resident until the next call to block or until you yielded the CPU with another I/O operation. If you modified the data there, you would call update to tell Forth the buffer was modified. If block 53 was not currently in memory, Forth would pause your task until it had loaded it, running other tasks meanwhile. If there was no free block buffer, Forth would free one up, by writing out a modified buffer to disk if necessary. This provided a sort of virtual memory in about 100 lines of code without requiring memory-mapping hardware. (The "BLOCK I/O" part of F83's KERNEL86.FS is 8 16-line screens long, but a fair bit of that is actually dealing with MS-DOS's file I/O functions.)
- Because standard Pascal had no string type and no way to handle variable-length arrays of any kind, TeX uses indices into a string table as its string type. It inserts newly encountered strings in the string table.
- Symbols in some Lisps.
- Pretty much anything in any Fortran program. See http://www.the-adam.com/adam/rantrave/st02.pdf on how to program Fortran in any language.
How noticeable the performance impact is depends a lot on how often you have to traverse the extra level of indirection. (Doing a base+offset addition before each memory access could be a significant performance issue on things like a Commodore 64 or a TRS-80 but basically doesn't matter on 8086 or better hardware.)