TweetFollow Us on Twitter

January 94 - C++ for Gurus

C++ for Gurus

Jeff Alger

Jeff Alger is a consultant and author internationally recognized as an authority in object-oriented methods and technologies. He is coauthor of "Developing Object-Oriented Software for the Macintosh." The material in this article was inspired by his experiences developing a new seminar, "Advanced C++," now taught by him at Apple Computer Developer University. The course deals with advanced architectures for C++ programs. For information contact Developer University at (408)974-4897 or (408)974-6215.

There is a growing community of disenfranchised C++ gurus out there, and you may be among them; if so, this article is for you. No, I'm not talking to you beginning and intermediate C++ programmers; you have dozens of books, loads of training classes, multimedia-based self-help courses, magazines, mentors and cocktail parties galore. Not that one more cocktail party would be a bad idea, mind you, it's just that for one of the few times in my otherwise spotless diplomatic career, I'm going to be politically incorrect and send you packing.

For just this once, I'm talking to the rest of you, and you know who you are. The sort of person to whom an "overloaded function" isn't a boring social affair, an "overloaded operator" doesn't work for the phone company and a "collection class" isn't a seminar on raising money for charity. You cite the ARM frequently in casual conversation (always pronounced "arm"), at least half the time correctly but who cares because no one else in the room knows what the acronym means and you're not about to tell them.1 You're the sort who doesn't read those "sissy" books and, as a result, haven't found any books about C++ worth reading since you browsed through the index of Lippman's book after starting your first C++ compile.2,3 You don't just program in C++, your ideas flow onto a digital canvas using brushes and a palette from Bell Labs. Well, you have rights, too, and it's about time someone did something to keep you and others like you from going stark, raving mad. To anyone I haven't thoroughly offended yet, glad to meet you, come on in. Welcome to group therapy for C++ gurus. This is the first and possibly the last article in a series on how to learn to stop worrying and love C++. It is an outgrowth of a new three-day course I developed recently and now teach at Apple Computer's Developer University, titled "Advanced C++" and targeted, not at C++ programmers, but at C++ architects.

The Zen of C++

The natural course of one's understanding of C++ is like rising on an elevator, with each floor decorated quite differently from the one below.

Ding! First floor. C++ is a more reasonable C, strongly typed as long as you don't fool around too much, and, hey, how about those nifty // comments? All the C programmers that didn't want to go into management really needed a career path, and Bjarne Stroustrup, bless his soul, dreamed up a doozy.

Ding! Second floor. C++ is a decent but not great object-oriented language that happens to run blindingly fast by comparison to others. It's politically correct and sure to get your project funded by top management. Heck, they might double your budget if you mention the language often enough in your proposal. That's just as well, because no one really knows how to estimate and manage C++ projects and as to tools… lot of weather we're having, eh?

Ding! Top floor, everybody out. Hey, where did everyone go? Sure is drafty up here. C++ is really "yacc++,"4 not so much a language as a way of creating your own languages, elegant not for its simplicity (like "jumbo shrimp," the terms "C++" and "simple" grate on the ears when used in the same sentence) but because of its potential. Lurking behind every gnarly design problem is a nifty idiom, a nice little twist to the language that makes the problem melt away like the Wicked Witch of the West without her umbrella. That idiom solves the problem as elegantly as a real language like Lisp or Smalltalk would, but without causing smoke to rise from your CPU and the stock of companies that manufacture memory chips to rise on Wall Street. C++ isn't a language, it's an experience, a mind-altering drug.

There's that word again, "elegant." There is a Zen to designing for C++: You have to stop trying so hard to be elegant in order to achieve true elegance. From its brutish ancestor C it inherits not only compilation efficiency but also a conventional block structured grammar and a terse syntax for commonly used forms. It's got nouns, verbs, adjectives and lots of slang, like

cout<<17<<endl<<flush;

C++ programmers have been cowed into embarrassment by the language purists. The purists think that distinguishing a simple variable from a function call from a macro using nothing but parentheses is a surefire crowd-pleasing feat of prestidigitation. In real life the crowd only applauds languages in which different ideas look different. The "simple, consistent" languages have never gained much of a following outside academia, while block-structured languages have drawn all the crowds. This shouldn't be a surprise; research in linguistics predicts that learning time should be shorter and reading comprehension and retention much higher for languages that have all those supposedly "bad" properties. "i++" really is more "readable" by any verifiable measure than "i := i + 1;" and people really do have an easier time reading "x = 17 + 29;" than "(setq x (+ 17 29))". This has nothing to do with the design of the programming language and everything to do with how we are designed. C++ is ugly in large part because we are ugly. Learn to know and love the quirks and stop worrying about mathematical consistency and you are on the road to elegance in C++.

Like Lisp, Smalltalk, and other dynamic languages (and unlike C), C++ provides the hooks needed to manipulate low-level behavior of the compiler. You can make up your own data types and fool the compiler into adopting them as its own progeny. You can control how functions are called, how data members are accessed, how memory is allocated and deallocated and how and when things get initialized. And all without sacrificing efficiency or type safety (often). Unlike those other languages, a C++ program will merrily crash and burn if you use this power the wrong way. Even if it doesn't, your fellow programmers might if you don't find just the right C++ idiom for a complicated design. Deadalus and his son, Icarus, escaped imprisonment on Crete by fashioning wings out of feathers and wax. The wings helped Deadalus, the master architect, soar to distant shores. In the arms of his brash son, they led to death when he flew too close to the sun and melted the wax. Now that I think of it, there is more irony than I intended in that analogy: Deadalus was also the designer of the Labyrinth, which was so complex no one could find the way out once imprisoned. Hmm. Perhaps a more contemporary analogy is needed. Every time you use these low-level C++ features it's like the bumbling detective Sledge Hammer from the 80's TV series saying to the compiler, "Trust me, I know what I'm doing." The compiler rolls its eyes and plays along.

C++ is intriguing because of its inherent contradictions. Powerful because of tools that are easily abused. An extensible programming environment without compromising space or speed. Elegant in one set of hands while dangerous in others. Simple and complex at the same time. After years of using it, you still can't make up your mind whether to admire it or walk away in disgust. Yet, to the truly expert, there are concepts that underlie the use of the language that tip the scales in its favor. Certain architectural paradigms go best with specific features of the language; mismatch the two and the result is chaos, but get the right combination and the result is… well, elegant.

Three Great Ideas in C++

It seems to the uninitiated that mastering C++ is really about getting your own bag of tricks like the ones carried by the masters. Some of these tricks are general object-oriented design principles. The rest are specific to C++ and revolve around how to use its unique strengths and work around its unique shortcomings. To my mind, there are three basic paradigms of C++ architecture that organize these tricks into a coherent framework.
  • Indirection
  • Homomorphic type hierarchies
  • Memory spaces

Each is supported by specific syntax and features of C++ and the three principles work together to solve an amazing variety of problems. There are other C++ design principles one could add to the list, but these are the core of any advanced C++ design.

Indirection covers a wide variety of individual topics, but the concept is the same throughout: some client object makes a request of a second object, which turns right around and delegates the work to a third object. The object in the middle is where the indirection takes place. Some might argue that this is almost the dictionary definition of delegation, one of the bulwarks of general object-oriented design, but in C++ the idioms one uses with this concept and the language support for it goes beyond what is considered delegation in other languages. For example, the object-in-the-middle, which I shall call the smart pointer for the time being, may determine where in memory, on disk, or in the network the object resides; when it gets destroyed; whether it may be updated or whether it is read-only; whether it even exists or whether it is simply an abstract location in some collection or memory space waiting to be assigned to. All without the active cooperation of the target object, which may be completely oblivious to all this grubby, low-level activity.

A homomorphic type hierarchy is one in which all derived classes share the same public interface as their common abstract base class. In fact, the abstract base class is usually as pure as the driven snow: all of its methods are pure virtual placeholders. This sounds simple enough, but in C++ there are a number of powerful language and design idioms that are enabled by the paradigm.

The idea of a memory space is enabled by your ability to overload operators new and delete and certain other very language-specific features. The concept is that an object may be allocated, not just randomly in a compiler-assigned location in memory, but as part of an implicit collection of objects not directly visible to the application. The simplest example is preallocating an array big enough for 1000 Foo's, then overloading operator new to allocate from an unused slot and operator delete to return the Foo to a free space list. But this is the plumber's view of architecture; the concept of a memory space builds on these low-level mechanics to become itself one of the central tools of the C++ designer. It is difficult to separate these concepts, since each borrows from the other two. But together they solve some of the most daunting problems of design in just a few lines of code. In fact, maybe that should be a standard by which to judge how well you have used the concepts: more than a couple of hundred lines and a giant hook pulls you off the stage. In the "Advanced C++" course several of the labs would normally merit a few weeks each just for design in a typical project. While the labs aren't exactly obvious, the solutions involve from dozens to a couple hundred lines of code and actually flow very logically from the coding and design idioms presented. The labs include

  • An "undo" facility that is easily extended into multi-user transaction processing;
  • An high-performance, industrial-strength garbage collection scheme for use with existing classes; and
  • Distributing objects over a network.

These all build toward what is almost an anticlimax, the use of all three design concepts to facilitate reuse. In the remainder of this article I will skim the surface of one of these three concepts, indirection.

Indirection

Many of the techniques used by the C++ masters revolve around the idea of indirection. Consider the following code fragment.
class Foo {
public:
    void MemberOfFoo();
};

Foo* aFoo = new Foo;
aFoo->MemberOfFoo();

Forget you ever knew anything about C and the lowly ->, and take a fresh look at the subject. This is the built-in "operator->" being applied to a built-in pointer "class," in this case the address held in aFoo. The built-in operator-> is available for use with any address whose type is "pointer to struct or class." In effect, you are indirectly referring to one object, the Foo, using another, the pointer. This is as far as built-in indirection goes, but you can extend the idea of operator-> through the magic of operator overloading. Here is a simple example of something known as a "smart pointer" class.

class PFoo {
private:
    Foo* fFoo;
public:
    PFoo(Foo* f): fFoo(f) {}
    Foo* operator->() { return fFoo; }
};

PFoo pf(new Foo);
pf->MemberOfFoo(); // Works!

Here the class PFoo slips into your program in place of the built-in "class" Foo*. When the compiler sees operator->, it does not automatically spit out the member requested on the right-hand side; instead, it looks to see whether the left-hand side is a built-in type (an address) or a user-defined type. If user-defined, it invokes the overloaded operator->() and repeats the process with the return value as the new left-hand side. Of course, if you are silly enough to fail to overload operator-> or to return the address of something other than a struct or class, the compiler will reach out and slap your hand and refuse to budge. In this case, pf->() returns a Foo*, which is a legal left-hand side to the built-in operator->, so the compiler is happy and we're happy.

There is no space or performance overhead to this indirection. What's the size of a smart pointer? The sum of its data members (there are no virtual member functions and, therefore, no vtable pointer to clutter up the object). In this case, an instance of PFoo is the same four bytes as a Foo*; it can be passed by value in a machine register just as efficiently as an integer or anything else. What about performance? All methods are trivial inlines that any good C++ compiler should handle as efficiently as using a built-in Foo* directly. At the least we haven't done any damage. But so far, we really haven't done anything we couldn't have done with the built-in operator, either. How many times have you gnashed your teeth over the old dereferencing-nil problem? Here is a minor variation on the theme.

inline Foo* PFoo::operator->() {
#ifdef DEBUGGING
    if (!fFoo) {
        cerr<<"*** NULL PFoo ***"<<endl;
    fFoo = new Foo; // Create a dummy instance
    }
#endif
    return fFoo;
}

Now we have a smooth way to handle the problem: spit out an error message and return a surrogate object to allow the program to keep limping along, at least in debug mode. There are further variations on this, such as storing a single default surrogate as a static data member of the class PFoo just so you can return it to wayward clients, or returning a derived class of Foo all of whose member functions scream loudly every time they are accessed.

Now suppose that Foo is really an abstract base class like this.

class Foo {
protected:
    Foo() {} // Cannot be directly instantiated
public:
    virtual void MemberOfFoo()=0;
    virtual int AnotherMember()=0;
    // ...
};

The client of the pointer now need have no idea which derived class of Foo is actually contained in the smart pointer. In fact, it is simple to switch the object pointed to at run time. "That's nothing," you may say, "I can change the address contained in a pointer variable, too." True, but can you train your pointers to do this?

class PFoo {
private:
    Foo* fFoo;
public:
    PFoo(Foo* f): fFoo(f) {}
    const Foo* operator->() const { return fFoo; }
    Foo* operator->() { // Warning! Non-const access!
        if (fFoo->IsConst())
            fFoo = fFoo->UpdateCopy(); // A new one I can change
        return fFoo;
    }
};

Presumably there is some optimal representation of Foo when it is being used in a read-only (const) fashion. If someone requests a member in a non-const way, the smart pointer automatically replaces the read-only version with a writeable version. In fact, with an extra level of indirection this example can be reworked so that the object itself need not provide the method support shown here (IsConst() and UpdateCopy()); that logic can be entirely contained in read-only and read-write pointers. That extra effort is rewarded; this architecture can then be slipped into an existing program that uses smart pointers. It would be extraordinarily difficult, however, to make this sort of change late in the game in a program organized around *s. One of the first steps on the road to C++ elegance is to learn to mumble smart pointers in one's sleep, using them routinely out of the vague sense that they might come in handy someday.

I am only hinting at a general strategy here: read-only pointers as distinct from read-write pointers. These wrap the object and largely insulate it from knowledge about how it is being used. For example, in a distributed object system one may use a local copy for read-only purposes but retrieve the "master" copy in order to perform updates.

When a smart pointer is in one-to-one correspondence with the object it points to, the terms "master pointer," "envelope" and "handle" have all been used by various authors. I prefer the term "master pointer" because I have other uses for the other terms. Here is a simple example that illustrates master pointers and the recursive use of operator->.

class PFoo { // This acts as a "master pointer"
private:
    Foo* aFoo;
public:
    PFoo(): aFoo(new Foo) {}
    PFoo(args):aFoo(new Foo(args)) {}
    PFoo(const PFoo& pf):aFoo (new Foo(*pf.aFoo)) {} // Copy contents
    PFoo& operator=(const PFoo& pf); // See below
    ~PFoo() { delete aFoo; }
    Foo* operator->() const { return aFoo; }
};
inline PFoo& PFoo::operator=(const PFoo& pf) {
    if (this == &pf) return *this;
    delete aFoo;
    aFoo = new Foo (*pf.aFoo);
    return *this;
}

class HFoo {
private:
    PFoo& fMasterPtr;
public:
    HFoo(PFoo& pf):fMasterPtr(&pf) {}
    Foo* operator->() const { return fMasterPtr; }
}

PFoo pf; // Creates master pointer plus instance of Foo
HFoo hf(pf); // Handle to the Foo

hf->MemberOfFoo(); // Works! Doubly interpreted: HFoo and PFoo

Here the direct pointer class, PFoo, is in one-to-one correspondence with the object it points to. When the master pointer is deleted, its destructor also deletes the object pointed to. operator-> is recursively interpreted twice so that the user of an HFoo need not do any explicit dereferencing. HFoo is now analogous to a "handle" in the Macintosh or Windows environments; it refers to the object indirectly through a master pointer. Unlike those environments, however, the dereference is done without compromising type safety and without relying on a single model of how objects are created, stored, and destroyed. In fact, those memory managers are really just a special case, a specific implementation of this design paradigm in C++.

Master pointers can be used for a wide variety of simple memory management strategies. operator-> can, for example, create the object on the fly if it doesn't already exist, perhaps reading it from a database or obtaining a copy from another process elsewhere on the network. Handles are the key to most advanced memory management strategies, including reference counting and the many variations of mark-and-sweep and generational garbage collection. It can also be extended to elegantly handle distribution of objects over multiple processes, computers, and storage media. In the seminar, we take this one step further, designing each master pointer to automatically maintain two copies of the target object: one for current access and one for undo.

One of the more intriguing and less obvious uses of indirection arises from the design of collection classes.

Arrays and operator[]

operator[] is amazingly versatile in ways most C++ programmers never consider. Here is a simple application: an array that checks its bounds when its elements are accessed.
class ArrayOfFoo {
private:
    int fSize;
    Foo* fContents;
    static Foo* fgSurrogate; // A dummy for out-of-bounds indices
public:
    ArrayOfFoo():fSize(0),fContents(nil) {}
    ArrayOfFoo(int size):
        fSize(size),fContents((Foo*)(new void*[size]) {}
    ~ArrayOfFoo() { delete fContents; }
    Foo*& operator[] (int index) {
        return (index<0 || index>=fSize)
            ? fgSurrogate : fContents[index];
        }
};

// In a .cp file somewhere
Foo* ArrayOfFoo::fgSurrogate = nil;

The return value from operator[] is a Foo*&, that is, a reference to an address of a Foo. This allows the result of operator[] to be used as the left-hand side of an assignment, among other things.

anArray[10] = aFoo;

If efficiency is more important than robustness, simply surround the fSize data member and the range-checking logic with #ifdefs, and you have an array identical in size and performance to a standard C-style array of pointers. But this only scratches the surface of operator[]. It can be overloaded to take non-integral arguments. Here is the outline of an association class that maintains a set of pairs (String, String), where the first string acts as a key and the second, the unique value associated with that key.

class Association {
public: // Implementation details spared here
    const String& operator[] (const String& key);
};

String value = anAssociation[someString];

This is much more elegant and expressive of the designer's intent than using a purely method-based interface like

String value = anAssociation.Lookup(someString);

Operator[] can be overloaded to accept any argument type, as for String in this example, with the sole restriction that it can only accept one argument. Thus, the following is not legal.

class WontWork {
public:
    Foo& operator[] (int x, int y); // Only one argument allowed
};

This isn't as much of a problem as it would appear, since one can easily create classes or structs that simulate a point in n-dimensional array space.

struct Index {
    int fx;
    int fy;
    Index(int x, int y):fx(x), fy(y) {}
    Boolean operator== (const Index& i) 
        { return fx==i.fx && fy==i.fy; }
};

class WorksFine {
public:
    Foo& operator[] (Index i);
};

anArray[Index(17,29)]; // Uses an anonymous instance of Index

It is also possible to overload operator[] more than once in a single class. Why would you want to do that? Perhaps you have a need to index two ways.

class StringArray {
public:
    const String& operator[] (int index);
    int operator[] (const String&);
};

The first operator[] maps from an integral index to the string at that location. The second does the opposite: given a string, it returns the index of that string in the array. (Presumably some value such as -1 is set aside to return when the string does not occur in the array.) Once one gets used to overloading operator[], it becomes invaluable as a way to encapsulating collections of all sorts, not just arrays. However, collections that do not simply span indices from 0 to N require a little more attention than simply overloading operator[].

A Sparse Array Class

One of the most basic data structures is the sparse array. This is a matrix most of whose cells are empty. To represent this as an NxM (or even higher dimensions) array of cells would be a terrible waste of space, so a variety of lower-level data structures are used to simulate the array: linked lists, hash tables, binary trees, and just about any other exercise from your Introduction to Data Structures course in college. We aren't concerned here with the implementation details but rather with how to best leverage C++ language features to isolate clients from those details. To illustrate the ideas, here is a brute-force implementation using a linked list of cells.
class SparseArray {
private:
    struct Node {
        Index fIndex; // Uses Index structure above
        Foo* fContents;
        Node* fNext;
        };
    Node* fCells;
public:
    SparseArray(): fCells(nil) {}
    Foo* operator[](Index i) {
        Node* n = fCells;
        while (n)
            if (n->fIndex == i) // Why we overloaded == for Index!
                return n->fContents;
            else n = n->fNext;
        return nil; // Not found
        }
};

aFoo = anArray[Index(17,29)]; // Works

This is fine for accessing cells of the array, but how do we add new cells or reassign existing ones? The operator[] we have created won't work as the left-hand side of an assignment because it is a Foo*, not a Foo*&.

anArray[Index(17,29)] = aFoo; // Will not work

We could create some special functional interface, but that would mean breaking the illusion for the client that this is a normal array. Is there a way to use operator[] as the left-hand side of an assignment with this and other pseudo-arrays? It turns out the answer is Yes, but we have to introduce a new design paradigm for the purpose.

Cursors

Let's try again.
class ArrayCursor;
 
class SparseArray {
friend class ArrayCursor;
public: // private: ***The Semantec work-around***
   struct Node {
   Index fIndex; // Uses Index structure above
   Foo* fContents;
   Node* fNext;
   Node(Index i, Foo* content, Node* next)
   : fIndex(i), fContents(content), fNext(next) {}
   };
   Node* fCells;
public:
   SparseArray(): fCells(nil) {}
   ArrayCursor& operator[](Index i);// inline moved below ArrayCursor
};
 
class ArrayCursor {
friend class SparseArray;
private:
   SparseArray& fArray;
   Index fIndex; // Index this cursor represents
   SparseArray::Node* fNode; // Non-nil means the index exists
   // Constructors are private; only SparseArray can create these
   ArrayCursor(SparseArray& array, Index i)
   : fArray(array), fIndex(i), fNode(nil) {}
   ArrayCursor(SparseArray& array, SparseArray::Node* node)
   : fArray(array), fIndex(node->fIndex), fNode(node) {}
public:
   ArrayCursor& operator=(Foo* foo) {
   if (!fNode) {
   fNode = new SparseArray::Node
   (fIndex,foo,fArray.fCells);
   fArray.fCells = fNode;
   return *this;
   }
   fNode->fContents = foo;
   return *this;
   }
};
 
inline ArrayCursor& SparseArray::operator[](Index i) {
   SparseArray::Node* n = fCells;
   while (n)
   if (n->fIndex == i) return ArrayCursor(*this,n);
   else n = n->fNext;
   return ArrayCursor(*this,i); // Not found
   }

Whoa! What's going on here? operator[] returns an ArrayCursor for an index that does not yet exist. This becomes the left-hand side of the assignment, so the ArrayCursor::operator= is invoked. This creates a new Node and adds the right-hand side as the contents of that cell. To the client this appears to be a simple array even though the internal details are anything but simple.

There are a couple of details glossed over here. For example, the following would not work.

anArray[Index(17,29)]->MemberOfFoo();

This and similar problems are simple to handle by overloading operator-> and adding an operator Foo* in the ArrayCursor class.

The concept of a cursor is not specific to the matrix form. A cursor can be used to represent any "position" in a collection, even a collection that is unordered. Cursors can also be used to represent positions in disk files or other processes and computers. C++ operators ->, [] and =, overloaded together, largely insulate clients from where the actual objects and collections are physically stored and what index structures are used to retrieve them.

From Cursors to Iterators

I said earlier that a cursor is a new design idiom, but it is easy to connect it to one you are probably already familiar with: the iterator. The basic concept of an iterator is illustrated by the following code fragment.
class Collection {
public:
    class Iterator {
    public:
        Boolean More();
        Foo* Next();
    };
    Iterator* ProvideIterator(); // Returns an Iterator
};

Collection::Iterator* iter = aCollection->ProvideIterator();

while (iter->More())
DoSomethingToAFoo(iter->Next());

Here we have assumed that the collection contains Foo*s; more generally, one would use a template to genericize these classes, but the treatment here is otherwise general. Note that you ask the collection object to hand you the iterator, rather than directly instantiating it yourself. This allows derived classes of Collection to return derived classes of Iterator without the client having any knowledge that derived classes are involved.5 There are lots of variations on the theme, such as controlling the order or range of the iteration.

How are iterators implemented? One straightforward approach is to simply extend the collection's cursor class to add the More and Next member functions! This combination provides a bonus in the box of candy corn: assignment to the current location of the iterator/cursor is supported automatically. A closely related design strategy is to create an iterator class that contains a cursor as a data member.

Cursors and iterators aren't just oddly shaped widgets in the bag of C++ tricks. If you look carefully, you will see that they recycle the idea of indirection. A cursor with an overloaded operator-> is just a "smarter" pointer of sorts. The same technique of pointing to something that isn't there yet finds wide application in other design problems: persistent objects, distribution, and caching, to name a few. This convergence of design ideas is typical of advanced C++ architectures.

Top Floor

There is a relatively small circle of experts in C++ and object-oriented design that understand and routinely apply these principles, creating what to others often seems black magic. As with all magicians, people hold them in a combination of reverence and distrust. However, the real problem is a lack of literature, for the techniques themselves are accessible to anyone with a solid background in C++ and software design. Hopefully now that C++ is entering its teen years we will see more attention paid to members of that frustrated underclass, the C++ architect. In future articles, I'll pay some attention to homomorphic type hierarchies and memory spaces.

Copyright ©1994 by Jeff Alger. All rights reserved.

  1. That's Bjarne Stroustrup's C++ Annotated Reference Manual, and if you had to ask perhaps you should go find one of those cocktail parties. No offense intended… I'll catch up with you later.
  2. Well, maybe James Coplien's Advanced C++ Programming Styles and Idioms caught your eye for a while, but much of that book is just too weird. I mean, how many people really care about how to use C++ to emulate Lisp programming? Do you really need to change the implementation of a method on the fly without shutting down a running C++ program? I admire the book, but it doesn't fill the void on advanced C++ usage.

    You don't mind footnotes, either.

  3. Oh, you're not a Unix hacker, either? That's the Unix-based "yet another compiler compiler," (cute, huh?) a do-it-yourself kit for implementing programming languages.
  4. Note for MacApp programmers: iterators in MacApp violate these rules and as a result are not quite as flexible as the strategy presented here.
 
AAPL
$119.00
Apple Inc.
+1.40
MSFT
$47.75
Microsoft Corpora
+0.28
GOOG
$540.37
Google Inc.
-0.71

MacTech Search:
Community Search:

Software Updates via MacUpdate

Skype 7.2.0.412 - Voice-over-internet ph...
Skype allows you to talk to friends, family and co-workers across the Internet without the inconvenience of long distance telephone charges. Using peer-to-peer data transmission technology, Skype... Read more
HoudahSpot 3.9.6 - Advanced file search...
HoudahSpot is a powerful file search tool built upon MacOS X Spotlight. Spotlight unleashed Create detailed queries to locate the exact file you need Narrow down searches. Zero in on files Save... Read more
RapidWeaver 6.0.3 - Create template-base...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
iPhoto Library Manager 4.1.10 - Manage m...
iPhoto Library Manager lets you organize your photos into multiple iPhoto libraries. Separate your high school and college photos from your latest summer vacation pictures. Or keep some photo... Read more
iExplorer 3.5.1.9 - View and transfer al...
iExplorer is an iPhone browser for Mac lets you view the files on your iOS device. By using a drag and drop interface, you can quickly copy files and folders between your Mac and your iPhone or... Read more
MacUpdate Desktop 6.0.3 - Discover and i...
MacUpdate Desktop 6 brings seamless 1-click installs and version updates to your Mac. With a free MacUpdate account and MacUpdate Desktop 6, Mac users can now install almost any Mac app on macupdate.... Read more
SteerMouse 4.2.2 - Powerful third-party...
SteerMouse is an advanced driver for USB and Bluetooth mice. It also supports Apple Mighty Mouse very well. SteerMouse can assign various functions to buttons that Apple's software does not allow,... Read more
iMazing 1.1 - Complete iOS device manage...
iMazing (was DiskAid) is the ultimate iOS device manager with capabilities far beyond what iTunes offers. With iMazing and your iOS device (iPhone, iPad, or iPod), you can: Copy music to and from... Read more
PopChar X 7.0 - Floating window shows av...
PopChar X helps you get the most out of your font collection. With its crystal-clear interface, PopChar X provides a frustration-free way to access any font's special characters. Expanded... Read more
OneNote 15.4 - Free digital notebook fro...
OneNote is your very own digital notebook. With OneNote, you can capture that flash of genius, that moment of inspiration, or that list of errands that's too important to forget. Whether you're at... Read more

Latest Forum Discussions

See All

Raby (Games)
Raby 1.0.3 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.3 (iTunes) Description: ***WARNING - Raby runs on: iPhone 5, iPhone 5C, iPhone 5S, iPhone 6, iPhone 6 Plus, iPad Mini Retina, iPad Mini 3, iPad 4, iPad Air,... | Read more »
Oddworld: Stranger's Wrath (Games)
Oddworld: Stranger's Wrath 1.0 Device: iOS Universal Category: Games Price: $5.99, Version: 1.0 (iTunes) Description: ** PLEASE NOTE: Oddworld Stranger's Wrath requires at least an iPhone 4S, iPad 2, iPad Mini or iPod Touch 5th gen... | Read more »
Bounce On Back (Games)
Bounce On Back 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: | Read more »
Dwelp (Games)
Dwelp 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: === 50% off for a limited time, to celebrate release === Dwelp is an elegant little puzzler with a brand new game mechanic. To complete a... | Read more »
Make Way for Fat Chicken, from the Maker...
Make Way for Fat Chicken, from the Makers of Scrap Squad Posted by Jessica Fisher on November 26th, 2014 [ permalink ] Relevant Games has announced they will be releasing their reverse tower defense game, | Read more »
Tripnary Review
Tripnary Review By Jennifer Allen on November 26th, 2014 Our Rating: :: TRAVEL BUCKET LISTiPhone App - Designed for the iPhone, compatible with the iPad Want to create a travel bucket list? Tripnary is a fun way to do exactly that... | Read more »
Ossian Studios’ RPG, The Shadow Sun, is...
Ossian Studios’ RPG, The Shadow Sun, is Now Available for $4.99 Posted by Jessica Fisher on November 26th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Mmmm, Tasty – Having the Angry Birds for...
The very first Angry Birds debuted on iOS back in 2009. When you sit back and tally up the number of Angry Birds games out there and the impact they’ve had on pop culture as a whole, you just need to ask yourself: “How would the birds taste... | Read more »
Rescue Quest Review
Rescue Quest Review By Jennifer Allen on November 26th, 2014 Our Rating: :: PATH BASED MATCH-3Universal App - Designed for iPhone and iPad Guide a wizard to safety by matching gems. Rescue Quest might not be an entirely original... | Read more »
You Can Play the Final Chapter of Lone W...
You Can Play the Final Chapter of Lone Wolf: Dawn Over V’taag Right Now Posted by Jessica Fisher on November 26th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »

Price Scanner via MacPrices.net

Black Friday: $300 off 15-inch Retina MacBook...
 B&H Photo has the new 2014 15″ Retina MacBook Pros on sale for $300 off MSRP as part of their Black Friday sale. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.2GHz Retina... Read more
2014 1.4GHz Mac mini on sale for $449, save $...
 B&H Photo has the new 1.4GHz Mac mini on sale for $449.99 including free shipping plus NY tax only. Their price is $50 off MSRP, and it’s the lowest price available for this new model. Adorama... Read more
Early Black Friday pricing on 27-inch 5K iMac...
 B&H Photo continues to offer Black Friday sale prices on the 27″ 3.5GHz 5K iMac, in stock today and on sale for $2299 including free shipping plus NY sales tax only. Their price is $200 off MSRP... Read more
Early Black Friday sale prices on iPad Air 2,...
 MacMall is discounting iPad Air 2s by up to $75 off MSRP as part of their Black Friday sale. Shipping is free: - 16GB iPad Air WiFi: $459 $40 off - 64GB iPad Air WiFi: $559 $40 off - 128GB iPad Air... Read more
Early Black Friday MacBook Air sale prices, $...
 MacMall has posted early Black Friday MacBook Air sale prices. Save $101 on all models for a limited time: - 11″ 1.4GHz/128GB MacBook Air: $798 - 11″ 1.4GHz/256GB MacBook Air: $998 - 13″ 1.4GHz/... Read more
Why iPhone 6 Tablet/Laptop Cannibalization Is...
247wallst.com blogger Douglas A. McIntyre noted last week that according to research posted on the Applovin blog site the iPhone 6 is outselling the iPhone 6 Plus by a wide margin . Hardly a surprise... Read more
Worldwide Tablet Growth Expected to Slow to 7...
The global tablet market is expected to record massive deceleration in 2014 with year-over-year growth slowing to 7.2%, down from 52.5% in 2013, according to a new forecast from International Data... Read more
Touchscreen Glove Company Announces New Produ...
Surrey, United Kingdom based TouchAbility specializes in design and manufacture of a wide variety of products compatible with touchscreen devices including smartphones, tablets and computers. Their... Read more
OtterBox Alpha Glass Screen Protectors for iP...
To complement the bigger, sharper displays on the latest Apple devices, OtterBox has introduced Alpha Glass screen protectors to the iPhone 6 and iPhone 6 Plus. The fortified glass screen protectors... Read more
Early Black Friday Mac Pro sale, 6-Core 3.5GH...
 B&H Photo has the 6-Core 3.5GHz Mac Pro on sale today for $3499 including free shipping plus NY sales tax. Their price is $500 off MSRP, and it’s the lowest price available for this model from... Read more

Jobs Board

*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Senior Event Manager, *Apple* Retail Market...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global event strategy. Delivering an overarching brand story; in-store, Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.