Re: C++ nested classes, namespaces, structs, and compound statements

Jim Blandy
2002-04-10T01:35:56Z

Ah, this is exactly the kind of debate I was looking for. :)

Daniel Jacobowitz <drow@mvista.com> writes:
> But let me put my cynic's cap on for a moment and point out some
> problems. I'd love to see us just decide to overcome them all, and I
> think it's viable, but we need to make sure we consider them first.
>
> The "incremental change" Problem

This I especially suck at. So folks, please insist on getting an
answer you're really comfortable with.

Here's one way we could approach it:

- First, we could simply replace the `nsyms' and `syms' members of
`struct block' with a reference to our opaque `environment' object.
There isn't that much code which works on those directly, so this
wouldn't be too bad.

- Next, we could replace the static and global blocks with `environment'
objects, too.

At this point, our environment object would be known to work. *ahem*

- Make accessing a symbol's name go through an accessor function. It
goes through a macro already, but we'd have to make sure it *always*
goes through the macro. (Renaming the structure member and tweaking
the macro accordingly would help us find code which doesn't go
through the macro.)

- Then we could go through an intermediate phase where things worked
like this:

a) The symbol table stores names either way: with an explicit
namespace tree, or with qualified names sitting directly in the
symbol table. (When I say "namespace", please understand that to
also include classes, etc.) Any given symbol is stored only one
way or the other, but any given symbol table can hold a mix of
symbols in each form. Symbols stored in the explicit tree would
have a `fully_qualified_name' field, so symtab clients expecting
to see fully qualified names would still get them.

b) The object representing a namespace keeps around the prefix it
corresponds to (`std::' or `A::B::' or whatever), so that lookups of
single name components relative to that namespace can find entries
stored in either form.

c) For backwards compatibility, the symbol lookup function would check
for `::' in symbol names, and do a component-by-component lookup.

Then, we could gradually do the following (some of these are
interdependent, some not):

- Change symbol table clients to call a function to print a symbol's
qualified name relative to the current scope, rather than expecting
to see a fully qualified name in the symbol structure itself. This
would make b) unnecessary.

- Change symbol table clients to do lookups one component at a time,
making c) unnecessary.

- Change symbol table readers to build explicit namespace trees,
rather than dumping qualified names into the symbol table. This
would make a) unnecessary.

Now we've got symbol lookups switched over. Given the new
representation, we can implement namespaces in a straightforward way.

But what about structs? I don't have enough of a grasp on how data
members, member functions, static members, etc. really work now to say
how we'd switch struct types over to the new representation, but it
seems like the same general approach should work:

- Gradually replace code which manipulates the type structures
directly with simple accessor functions, until the type can be made
opaque.

- Switch to an intermediate representation which allows both the old
and the new representations, mixed.

- Migrate clients and producers over to the newer interfaces. This is
now a set of independent changes, that can be done in any order.

- Once the producers are all creating data in the new style, remove
support for it. Now you've got your new data structure, used as an
opaque datatype.

I feel like we're planning a construction project like Boston's Big
Dig or something: everything's got to keep running while we do the
work, and things will get pretty ugly in there for a while, but we
hope (if our funding doesn't run out) that in the end it'll all be
beautiful.