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
$423.00
Apple Inc.
+0.00
MSFT
$34.59
Microsoft Corpora
+0.00
GOOG
$900.68
Google Inc.
+0.00

MacTech Search:
Community Search:

Software Updates via MacUpdate

The Cave 1.0.1 - Adventure game featurin...
The Cave is an adventure game that offers a unique blend of fast-paced action, mind-bending puzzles, and winning humor. Assemble your team and embark on a journey into the shadowy underworld. Once... Read more
Apple Java 2013-004 - For OS X 10.7 and...
Apple Java for OS X 2013-004 supersedes all previous versions of Java for OS X. This release updates the Apple-provided system Java SE 6 to version 1.6.0_51 and is for OS X versions 10.7 or later.... Read more
Google Chrome 27.0.1453.116 - Modern and...
Google Chrome is a Web browser by Google, created to be a modern platform for Web pages and applications. It utilizes very fast loading of Web pages and has a V8 engine, which is a custom built... Read more
EarthDesk 6.2 - Striking animated image...
EarthDesk replaces your static desktop picture with a rendered image of Earth showing correct sun, moon and city illumination. With an Internet connection, EarthDesk displays near real-time global... Read more
Apple Configurator 1.3 - Configure and d...
Apple Configurator makes it easy for anyone to mass configure and deploy iPhone, iPad, and iPod touch in a school, business, or institution. Three simple workflows let you prepare new iOS devices... Read more
Apple Java for Mac OS X 10.6 Update 16 -...
Apple Java for Mac OS X 10.6 Update 16 delivers improved security, reliability, and compatibility by updating Java SE 6 to 1.6.0_51.Version Update 16: See http://support.apple.com/kb/HT5744 for more... Read more
Neat 4.0.3 - Digital filing system for r...
Neat (formerly NeatWorks) is a powerful scanning and digital filing system that enables you to scan and organize receipts, business cards, and documents. Unlike other scanning software, NeatWorks... Read more
Adobe Muse CC 5.0 - Design and publish H...
Adobe Muse enables designers to create websites as easily as creating a layout for print. Design and publish original HTML pages using the latest Web standards, and without writing code. Now in beta... Read more
Adobe Creative Cloud 1.0 - Everything ne...
Adobe Creative Cloud costs $49.99/month (or less if you're a previous Creative Suite customer). Creative Suite 6 is still available for purchase (without a monthly plan) if you prefer. Introducing... Read more
Adobe Flash Professional CC 13.0.0.759 -...
Flash Professional CC is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Flash Professional customer). Flash Professional CS6 is still... Read more

Latest Forum Discussions

See All

Calendars+ by Readdle Goes Free For A Ve...
Calendars+ by Readdle Goes Free For A Very Limited Time Posted by Andrew Stevens on June 19th, 2013 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Modern Combat 4: Zero Hour Has A Meltdow...
Modern Combat 4: Zero Hour Has A Meltdown, Gets New Maps, Multiplayer Modes, and More Posted by Andrew Stevens on June 19th, 2013 [ permalink ] | Read more »
XCOM: Enemy Unknown – Commander’s Log: H...
Part of the series 148Apps Goes Deep on XCOM: Enemy Unknown I’m still haunted by visions of a parallel world (classified as Xbox 360) as it wasn’t long ago that I was in charge of the XCOM project and led a squadron of soldiers against an alien... | Read more »
Rovio Stars: The Angry Birds’ New Publis...
Rovio Entertainment, creators of Angry Birds, has a new publishing initiative called Rovio Stars that will see its first titles Icebreaker and Tiny Thief released soon. Kalle Kaivola, Senior Vice President of Product & Publishing at Rovio... | Read more »
Favorite Four: Soccer Games
As a soccer fan, I’m getting twitchy. The Confederations Cup might be helping a little, but I miss the English Premier League week in, week out. This is where I sink time into FIFA 13 on my console in order to counteract the problem. What about... | Read more »
Knights of Pen & Paper Adds More Dun...
Knights of Pen & Paper Adds More Dungeons and Loot In Free Update Posted by Andrew Stevens on June 19th, 2013 [ permalink ] | Read more »
Froot ‘n’ Nutz Review
Froot ‘n’ Nutz Review By Blake Grundman on June 19th, 2013 Our Rating: :: VISUALLY DICEYUniversal App - Designed for iPhone and iPad While Froot ‘n’ Nutz may not look very modern, it is very likable.   | Read more »
148Apps Goes Deep on XCOM: Enemy Unknown
XCOM: Enemy Unknown will be released tonight for iPad and iPhone. And we’re very excited. While XCOM isn’t the first console game to be ported over to iOS, it is one of the most ambitious. XCOM: Enemy Unknown while first released for XBox 360 and... | Read more »
A Cautionary Tail – An Interactive Book...
A Cautionary Tail – An Interactive Book That Teaches Self-Acceptance Posted by Andrew Stevens on June 19th, 2013 [ permalink ] | Read more »
XCOM: Enemy Unknown – Cheats, Tips, and...
The X-Com series, particularly the earlier games, are notoriously unforgiving. Although while XCOM: Enemy Unknown has been modernized, and is therefore more player friendly, it’s no slouch either. In fact, even on the Normal difficulty there’s a... | Read more »

Price Scanner via MacPrices.net

Smaller Tablets Forecast To Get Even More Popular...
The DisplaySearch Blog’s Richard Shim notes that tablet PCs with screen sizes smaller than 9 inches are currently forecast to account for 66% of tablet PC shipments for the year but that share is... Read more
Updated iPad Price Trackers
We’ve updated our iPad Price Tracker and our iPad mini Price Tracker with the latest information on prices and availability from Apple and other resellers. Read more
Apple refurbished iPod nanos available for $99
The Apple Store has Apple Certified Refurbished 16GB iPod nanos available for $99 including free shipping and Apple’s standard one-year warranty. That’s $50 off the cost of new nanos. All colors are... Read more
iFixIt Tears Down mid-2013 11.6-inch MacBook Air
iFixIt Chief Information Architect Miroslav Djuric says: The epic week of disassembly continues: Today, the MacBook Air 11″ found its way onto our teardown table and was soon just another Apple in... Read more
Mature Consumers Know When They Need a PC
Tech.Pinions’ Ben Bajarin sensibly observes that one of the fundamental characteristics of a mature market is mature consumers – mature in the sense that they know what they want and more importantly... Read more
Windows 8 Continues Ascension in User Popularity R...
Softpedia’s Bogdan Popa notes that Windows 8 is now the fourth most popular operating system in the world, and according to some new statistics, it continues to gain new users every day. Popa cites... Read more
Apple iOS and OS X Updates Put Bluetooth Smart Rea...
From its Worldwide Developers Conference last week, Apple announced unprecedented integration of Bluetooth technology into its operating systems – a move that sets the bar for Bluetooth integration... Read more
Buy a 13″ MacBook Pro, get AppleCare for as little...
Adorama has 13″ MacBook Pros bundled with 3-year AppleCare Protection Plans for as little as $40 extra (AppleCare has an MSRP of $249 for 13-inch MacBook Pros). Shipping is free, and Adorama charges... Read more
Updated MacBook Price Trackers
We’ve updated our MacBook Price Trackers with the latest information on prices, bundles, and availability on MacBook Airs, MacBook Pros, and the MacBook Pros with Retina Displays from Apple’s... Read more
Save $140 on the 15″ 2.3GHz MacBook Pro
B&H Photo has the 15″ 2.3GHz MacBook Pro on sale for $1659 including free shipping. Their price is $140 off MSRP. B&H will include free copies of Parallels Desktop, Bento Database, and LoJack... Read more

Jobs Board

*Apple* At-Home Team Manager - Apple (U...
Changing the world is all in a day's work at Apple . If you love innovation, here's your chance to make a career of it. You'll work hard. But the job comes with more than Read more
*Apple* Retail - Manager - Apple (Unite...
Job SummaryKeeping an Apple Store thriving requires a diverse set of leadership skills, and as a Manager, youre a master of them all. In the stores fast-paced, dynamic Read more
*Apple* - Solution Architect - CompuCom...
Job Location: US-TX-Dallas Posted Date: 4/18/2013 Overview: The Apple Solution Architect (SA) will be responsible for supporting pre-sales and post-sales solutions in Read more
*Apple* Support Technician; Mid-level -...
A Kforce client in Washington, DC area is seeking an Apple Support Technician. This contractor will have the following types of responsibilities including, but not Read more
Systems Engineer - *Apple* TV - Apple...
Job Summary The Apple TV team is looking for an experienced engineer with a passion for delivering first in class home entertainment solutions. The individual must be Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.