From oleg Thu Sep 7 10:27:59 CDT 1995
Newsgroups: comp.sys.mac.programmer.tools,comp.sys.mac.programmer.misc
Subject: local procedures and natural iterators in C++ [absurd example]
Summary: Snippet from grayimage_classlib showing off "nested" C++ functions
Organization: University of North Texas, Denton
Keywords: nested functions, iterators, closures, C++, Offscreen image
Status: OR
In my previous post on this newsgroup I yelled a whole paragraph about
the virtues of natural iterators in grayimage_classlib and "nested"
functions in C++, but failed to show a single bit of code to back
those claims up. That was clearly an oversight, and I'd like to fix it
now. Unfortunately, the bits of the code example patch seem to
outnumber those of the original message :-(. Sorry about the long
post.
By "nested" functions I mean local procedures, " small, special
purpose procedures that can be embedded inside another
procedure. They're neat, clean, and don't clutter your interface". The
quote I lifted from MacTech was from a guy who claims that the local
functions are the only thing he misses about ObjectPascal. Well, a
similar nesting is possible in C++, as it turns out.
"Natural" iterators are those that iterate upon you, rather than you
upon them. Kind of like a function one passes to qsort(): you only
need to deal with the _current_ elements you're _given_, and leave the
rest (iteration/shuffling/termination conditions, etc) to qsort(). The
same thing with PixelActions. Only you can keep some local environment
while being iterated upon, without (ab)use of static variables. Of
course, these iteratees are not yet full-fledged local
procedures/closures as in Scheme or Dylan; nevertheless, they're
_pretty_ close.
The code snippet below is taken from the working code, a Mac release
of grayimage_classlib. It's the implementation of an IMAGE method that
displays a grayscale image in a window (using an offscreen buffer for
drawing). As hard as it is to take my word for it, it was _not_ my
intention to make the code that weird: well, some stuff just
happens. But it works, and in a sense, _really_ shows off "nesting" of
C++ methods, to the point of absurdity, as some would probably
say. Anyway, one can start counting nesting levels and matching
braces...
void IMAGE::display(const char * title) const
{
struct ImageWindow : public OffScreenWindow
{
ImageWindow(IMAGE& image, const char * title)
: OffScreenWindow((ScreenRect)image,title,40) // 40 is Gray CLUT id
{
// Move pixels from IMAGE to a off-screen pixmap
// Note that the rows of pixmap may be padded, by
// as much as off_to_next_row bytes. So we need
// to skip over the padding as we move pixels row
// by row
class ImageToPixMap : public PixelPrimAction
{
PixMapHandle pixmap;
char * pixp;
const card height, width, off_to_next_row;
card curr_row, curr_col;
void operation(GRAY& pixel) // put a pixel to pixmap[row,col]
{
*pixp++ = pixel;
if( ++curr_col >= width )
curr_col = 0, curr_row++, pixp += off_to_next_row;
}
public:
ImageToPixMap(OffScreenWindow& window)
: pixmap(window.get_pixmap()),
height(window.height()),
width(window.width()),
off_to_next_row(window.bytes_per_row()-window.width()),
curr_row(0), curr_col(0)
{
assert( LockPixels(pixmap) );
pixp = GetPixBaseAddr(pixmap);
}
~ImageToPixMap(void)
{
assert( curr_row == height && curr_col == 0 );
UnlockPixels(pixmap); pixmap = 0;
}
};
image.apply(ImageToPixMap(*this));
}
};
ImageWindow image_window(*this,title);
image_window.handle();
}
This was only a single function, btw. The full code the snippet was
taken from was submitted to info-mac