From: shang@corp.mot.com (David (Lujun) Shang)
Subject: Proposal: Semantic Change on Operator "::"
Reply-To: shang@corp.mot.com
Organization: Motorola, Inc., Software Research and Development, Rolling Meadows, IL. 60008
Distribution: World
Date: Fri, 11 Sep 92 17:38:23 GMT



[Purpose] 

Eliminate the ambiguity of the operator "::" currently used in C++.

[The Existing Problem]

Two kinds of meaning are associated with operator "::" in the current C++:


(1) "::" as a selection operator:
    class::name   // name is a component of the class.

    This expression is commonly used in accessing a nested class and 
    a static member.

    Example1:
       class A { public: static int i; };
       int i = A::i;
    Note that a static member can also be accessed through an object,
    Therefore, "i" can be viewed as a component both of a class and of
    an instance of this class.

    Example2:
       class A { public: class B {}; };
       A::B  ab;
    where "A::B" means that "B" is a component class of class "A".

(2) "::" as a scope resolution operator:
    ::name    // name is defined in global scope
    class::name   // name is defined in this class or its super

    Example1:
       class A { public: int i; };
       class B: public A { public: int i; };
       B b;
       b.A::i;
    where "A::i" suggests that "i" is defined in class "A", 
    but "i" is not the component of "A", instead, it is the component 
    of object "b". Therefore, in expression "b.A::i", the selector of 
    "i" is "b" and "A" is only the scope resolute of "i".

    Example2:
       class A { public: void foo (); };
       void A::foo () {...};
    where "A::foo" suggest "foo" is defined in class "A" ( Note that
    "foo" is not the compnent of class "A", it belongs to an instance
    of class A).

The problem is that we can not always distinguish the real role of operator  
"::" in an expression.

[Ambiguity Examples]

        class A { public: static int i; };
        class B: public A { public: static A A;   };

    What is the meaning of the expression "B::A::i"? If we consider 
    the first "::" as the scope resolutor, "B::A::i" means the interger 
    "i" defined in the base class. But if we consider the first "::" as 
    a selector, the expression denotes the integer defined the component 
    object A which is defined in class B.

    Thoung in fact the integer "i" is unique in this case, but how about
    the following example:

        class A { public: static int i; };
        class A_ { public: static int i; };
        class B: public A { public: static A_ A;   };

    Now "B::A::i=100" will have different effect if we explain "::" in 
    different meaning. Further, if we consider expression:

        B b;
        b.A::i =100;

    Which "i" should get the value "100"? It depends on whether "::" is 
    a selector or a scope resolute.
       
Example2

    class A { public: class NA {}; };
    class B: public A 
    { public:
        class A { public: class NA{}; }; 
    };

    What is the meaning of the expression "B::A::NA"?

We can set up a rule to avoid the ambiguity: whenever the ambiguity 
happens, we apply the scope resolute meaning to the operator "::". (In
fact, the langauge implementation has already apply this rule to solve 
the ambiguity problem.). Therefore, "b.A::i" is the interger defined
in class A, not the interger of the component A, i.e. the integer of 
class A_.

But how about if the user wants the selector meaning rather than the scope  
resolute? For example, in expression "B::A::NA", I actually mean the class NA  
nexted in class A nested in class B, not the NA nested in global class A. And  
unfortuenately, this the common case. ( And the langage implementation apply  
the reverse rule for this case:  whenever the ambiguity happens, we apply the  
selector meaning to the operator "::".)

What a chaos!

[Solution]

We use "::" only as a scope resolute. Whenever a selector must be used, use  
operator ".". Then we come to a clear solution.

In example:

        class A { public: static int i; };
        class A_ { public: static int i; };
        class B: public A { public: static A_ A;   };
        B b;

"B.A::i" denotes the integer of A_;
"B::A.i" denotes the integer of A;

Note that a static member is also a member of the object, therefer,

"b.A::i" denotes the integer of A;
"b.A.i" denotes the integer of A_;

In example:

    class A { public: class NA {}; };
    class B: public A 
    { public:
        class A { public: class NA{}; }; 
    };

"B.A::NA" denotes the NA nested in global class A (i.e. A.NA)
"B.A.NA" denotes the NA nested in nested class A in B;

Nested class cannot be accessed through objects.

[Syntatic Modification]

qualified-name
    constrained-name
    constrained-name . qualified-name

constrained-name
    :: simple-name
    simple-name :: constrained-name

simple-name
    identifier
    (qualified-name)

Note that simple-name can be a parenthesized qualified name. Thus we can have  
the expression like:

     C.NC.(BC1.NBC)::BBC1::NBBC

to denote a nested class NBBC in the following class definitions:

     class BBC1
     { public:
         class NBBC {};
     };
     class BBC2
     { public:
         class NBBC {};
     };
     class BC1
     { public: 
         class NBC: public BBC1, public BBC2 {};
     };
     class BC2
     { public: 
         class NBC: public BBC1, public BBC2 {};
     };
      class C
     {  public:
          class NC: public BC1.NBC, public BC2.NBC {};
     };


David Shang













Newsgroups: comp.std.c++,comp.lang.c++