Topic: Ambiguity with Operator::


Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Thu, 22 Oct 92 23:28:03 GMT
Raw View
Several weeks ago, I posted a message on the ambiguity problem
with operator::, but receives no response. I'd like to post some
discussion with Mr. Stroustrup on this issue (I apologize here
if it is not suitable) The key issue is that wthether a
modification is necessary. If not, what is the clarification
in the standard?

***> However, we have - I think - reached the real problem.
 A base is referred to as an unnamed member of a class yet
 we use the name of its class to refer to the sub-object
 representing it. Had a base B been defined as a member
 named B there would have been no problem. As it is, we
 can define both a base of class B and a member called B
 and need to resolve the potential ambiguity.

Yes, that's exactly what I want to say.

***> As you saw, C++ resolves it in favor of the member - and you
 can't explicitly refer to members of the base class without
 some workaround.

I'm not sure, since I cannot find any supporting statement in any
C++ document. Just look at what some C++ compilers say on this
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 =100;
        b.A::i =100;

BORLAND C++3.1 issues an error message: Type qualifier 'A' must
be a struct or class name. Therefoer BC++3.1. resolves it in favor
of member just as you mentioned:

***>    In B's scope look for the name A. That A is the static
        variable A. Thus B::A::i is the i of B's static member A.
        However, one cannot apply :: to an object so A::i is an
        error.

However, in expression "b.A::i", I don't think C++ will resolve
A::i in favor of member.

On the contrary, Microsoft C/C++7.0 resolves "B::A::i" in favor of
base class: "B::A::i=100" makes A::i==100. However, for nested
classes, Microsoft C/C++7.0 resolves it in favor of the member:

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

"B::A::NA" is B's member A's member NA.

Quite confused, right?

***> I don't think a solution is necessary. The current rules are
 consistent and coherent. They may, however, not be stated
 explicitly enough. Hence the copy to Jonathan.

I agree. As long as a clear statement is made for resolving the
armbiguity, there is no problem with C++. We can always find the
way to work around if we need to resolve menbers defined in base.
For example, if we really need class A's member NA, we can always
use "A::NA", and we need not prefix it with class B.

***> On the other hand, should the issue be opened I'd (with the
 benefit of a few extra years of experience) argue that the
 name of a base class should double as the name of the sub-object
 representing it thus making it illegal to have both a base
 class and a member with the same name.

The real problem is not the name confusion. Yes, we can disallow the
name of a member be the same as a base name. The problem is the
semantic armbiguity of operator "::", its meaning depends on what is
the followed and what is the following. For example,

     b.A::i    // scope resolute, resolve in favor of base
     B::A::i   // member selector, resolve in favor of member by BC++
               // scope resolute, resolve in favor of base by MS C/C++
     B::A::NA  // member selector, resolve in favor of member

When operator"::" appears in a more complex expression, I bet the
programmer will be lost at sea.



My original post:
_____________________________________________________________________

[The 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 member either of a class or
    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 member
    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 member 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 member 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 "::".

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.
_____________________________________________________________________



_____________________________________________________________________

[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 in A, where "A::" is a scope resolute;
"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 in A;
"b.A.i" denotes the integer in 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 {};
     };
_____________________________________________________________________













Author: erc@netcom.com (Eric Smith)
Date: Sat, 31 Oct 1992 15:58:05 GMT
Raw View
In article <1992Oct22.232803.14743@cadsun.corp.mot.com> shang@corp.mot.com writes:
>     b.A::i    // scope resolute, resolve in favor of base
>     B::A::i   // member selector, resolve in favor of member by BC++
>               // scope resolute, resolve in favor of base by MS C/C++
>     B::A::NA  // member selector, resolve in favor of member


The operator precedence of :: is higher than that of . so b.A::i would
correctly mean the A::i member of object b.




Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Mon, 2 Nov 92 15:50:35 GMT
Raw View
In article <1992Oct31.155805.6176@netcom.com> erc@netcom.com (Eric Smith)
writes:
> In article <1992Oct22.232803.14743@cadsun.corp.mot.com> shang@corp.mot.com
writes:
> >     b.A::i    // scope resolute, resolve in favor of base
> >     B::A::i   // member selector, resolve in favor of member by BC++
> >               // scope resolute, resolve in favor of base by MS C/C++
> >     B::A::NA  // member selector, resolve in favor of member
>
>
> The operator precedence of :: is higher than that of . so b.A::i would
> correctly mean the A::i member of object b.

I didn't mention any problem of operator"::" with operator".".
No problem with their precedence order. The problem is the
ambiguious semantics of operator"::". Given an expression
"A::B", should "B" be a member (static member or nested class)
or a base class? When ambiguity happens, which has the
precedence? The member, or the base class? Unfortunately,
the rule is not clear. It is quite confused.

Daivd Shang