Why does C++ need the scope resolution operator?

43,744

Solution 1

Why C++ doesn't use . where it uses ::, is because this is how the language is defined. One plausible reason could be, to refer to the global namespace using the syntax ::a as shown below:

int a = 10;
namespace M
{
    int a = 20;
    namespace N
    {
           int a = 30;
           void f()
           {
              int x = a; //a refers to the name inside N, same as M::N::a
              int y = M::a; //M::a refers to the name inside M
              int z = ::a; //::a refers to the name in the global namespace

              std::cout<< x <<","<< y <<","<< z <<std::endl; //30,20,10
           }
    }
}

Online Demo

I don't know how Java solves this. I don't even know if in Java there is global namespace. In C#, you refer to global name using the syntax global::a, which means even C# has :: operator.


but I can't think of any situation in which syntax like this would be legal anyway.

Who said syntax like a.b::c is not legal?

Consider these classes:

struct A
{
    void f() { std::cout << "A::f()" << std::endl; }
};

struct B : A
{
    void f(int) { std::cout << "B::f(int)" << std::endl; }
};

Now see this (ideone):

B b;
b.f(10); //ok
b.f();   //error - as the function is hidden

b.f() cannot be called like that, as the function is hidden, and the GCC gives this error message:

error: no matching function for call to ‘B::f()’

In order to call b.f() (or rather A::f()), you need scope resolution operator:

b.A::f(); //ok - explicitly selecting the hidden function using scope resolution

Demo at ideone

Solution 2

Because someone in the C++ standards committee thought that it was a good idea to allow this code to work:

struct foo
{
  int blah;
};

struct thingy
{
  int data;
};

struct bar : public foo
{
  thingy foo;
};

int main()
{
  bar test;
  test.foo.data = 5;
  test.foo::blah = 10;
  return 0;
}

Basically, it allows a member variable and a derived class type to have the same name. I have no idea what someone was smoking when they thought that this was important. But there it is.

When the compiler sees ., it knows that the thing to the left must be an object. When it sees ::, it must be a typename or namespace (or nothing, indicating the global namespace). That's how it resolves this ambiguity.

Solution 3

Why does C++ have the :: operator, instead of using the . operator for this purpose?

The reason is given by Stroustrup himself:

In C with Classes, a dot was used to express membership of a class as well as expressing selection of a member of a particular object.

This had been the cause of some minor confusion and could also be used to construct ambiguous examples. To alleviate this, :: was introduced to mean membership of class and . was retained exclusively for membership of object

(Bjarne Stroustrup A History of C++: 1979−1991 page 21 - § 3.3.1)

Moreover it's true that

they do different things, so they might as well look different

indeed

In N::m neither N nor m are expressions with values; N and m are names known to the compiler and :: performs a (compile time) scope resolution rather than an expression evaluation. One could imagine allowing overloading of x::y where x is an object rather than a namespace or a class, but that would - contrary to first appearances - involve introducing new syntax (to allow expr::expr). It is not obvious what benefits such a complication would bring.

Operator . (dot) could in principle be overloaded using the same technique as used for ->.

(Bjarne Stroustrup's C++ Style and Technique FAQ)

Solution 4

Unlike Java, C++ has multiple inheritance. Here is one example where scope resolution of the kind you're talking about becomes important:

#include <iostream>
using namespace std;
struct a
{
    int x;
};
struct b
{
    int x;
};
struct c : public a, public b
{
    ::a a;
    ::b b;
};
int main() {
    c v;
    v.a::x = 5;
    v.a.x = 55;
    v.b::x = 6;
    v.b.x = 66;
    cout << v.a::x << " " << v.b::x << endl;
    cout << v.a.x << " " << v.b.x << endl;
    return 0;
}

Solution 5

I always assumed C++ dot/:: usage was a style choice, to make code easier to read. As the OP writes "they do different things, so should look different."

Coming from C++, long ago, to C#, I found using only dots confusing. I was used to seeing A::doStuff(); B.doStuff();, and knowing the first is a regular function, in a namespace, and the second is a member function on instance B.

C++ is maybe my fifth language, after Basic, assembly, Pascal and Fortran, so I don't think it's first language syndrome, and I'm more a C# programmer now. But, IMHO, if you've used both, C++-style double-colon for namespaces reads better. I feel like Java/C# chose dots for both to (successfully) ease the front of the learning curve.

Share:
43,744
Karu
Author by

Karu

.

Updated on June 08, 2020

Comments

  • Karu
    Karu almost 4 years

    (I know what the scope resolution operator does, and how and when to use it.)

    Why does C++ have the :: operator, instead of using the . operator for this purpose? Java doesn't have a separate operator, and works fine. Is there some difference between C++ and Java that means C++ requires a separate operator in order to be parsable?

    My only guess is that :: is needed for precedence reasons, but I can't think why it needs to have higher precedence than, say, .. The only situation I can think it would is so that something like

    a.b::c;
    

    would be parsed as

    a.(b::c);
    

    , but I can't think of any situation in which syntax like this would be legal anyway.

    Maybe it's just a case of "they do different things, so they might as well look different". But that doesn't explain why :: has higher precedence than ..

  • Nicol Bolas
    Nicol Bolas about 12 years
    That doesn't explain why you can't just say b.A.f instead of b.A::f. If A is a typename instead of a variable or function, then using . could easily have meant scope resolution instead of the regular meaning.
  • Nicol Bolas
    Nicol Bolas about 12 years
    You could still just say .a to mean the global one, and M.a to mean the one in the M namespace.
  • Nawaz
    Nawaz about 12 years
    @NicolBolas: The syntax .a looks awkward when the syntax . is mostly used for member-of or something.
  • Nicol Bolas
    Nicol Bolas about 12 years
    Technically that's not about multiple inheritance. It's about being able to name your variables the same names as your derived classes.
  • Nicol Bolas
    Nicol Bolas about 12 years
    Maybe, but if you'd been looking at it for 10 years it wouldn't. Personally, :: looks more awkward even after 10 years.
  • Nawaz
    Nawaz about 12 years
    Why can't you write test.foo.blah = 10? Or test.base.blah = 10 where base is a keyword?
  • Nicol Bolas
    Nicol Bolas about 12 years
    @Nawaz: Because introducing a keyword is a lot harder than introducing an operator. And test.foo.blah is ambiguous; is it the base-class's blah or the thingy member's blah? Java (as I understand it) gets around this by stating that it's always the member; you can only get at base class member variables by casting the type.
  • Mankarse
    Mankarse about 12 years
    @Nawaz: Because this would not give any way of specifying which base you wanted to use.
  • Nawaz
    Nawaz about 12 years
    @NicolBolas: It maybe harder from compiler author perspective, but from programmers perspective base.blah is lot easier (and less awkward).
  • Nicol Bolas
    Nicol Bolas about 12 years
    Are you saying that a parser couldn't simply wait and check the next token to see if it's a . before deciding on the ambiguity?
  • Nicol Bolas
    Nicol Bolas about 12 years
    @Nawaz: Unless of course your code ever used the identifier base anywhere. Which is entirely possible. Keywording things isn't hard because of the compiler; it's hard because it makes things that used those keywords break. Even a context-specific keyword means you can't have a type named base.
  • Nawaz
    Nawaz about 12 years
    @NicolBolas: C++ has introduced many new keywords (pun unintended) : new, delete, bool, etc. Why not base? :|
  • Nicol Bolas
    Nicol Bolas about 12 years
    @Nawaz: Let's also not forget that base isn't going to help you with multiple inheritance.
  • Nawaz
    Nawaz about 12 years
    NicolBolas: Haha. I knew that you would bring that point (which I was waiting for :D). Anyway, it means your answer isn't complete in itself, as it technically depends on another feature of C++ called multiple inheritance. But I also note that you commented on @dasblinkenlight's answer, saying : "Technically that's not about multiple inheritance. [..]".... :D
  • Karu
    Karu about 12 years
    The assumption I made about a.b::c not being sensible is what was causing my confusion. Accepted this answer because I think it's as good as the others but also points out my mistake.
  • Karl Knechtel
    Karl Knechtel about 12 years
    There is no global namespace in Java because everything is inside one class or another.
  • Nicol Bolas
    Nicol Bolas about 12 years
    @Nawaz: What? You're suggesting a keyword, which isn't a working suggestion because of multiple inheritance. You brought it up; it had nothing to do with what I or the OP said. The OP is asking why there is a difference between member field selection and scope selection. He's asking why there is special syntax to state one vs. the other; .base is no better in this regard than ::. He's asking why they can't be the same. And I answered that.
  • nolandda
    nolandda about 12 years
    No, certainly such a parser could be written. The intermediate result would be ambiguous and when the next token comes in you can assume that the user didn't mean to make a syntax error. So it isn't strictly necessary in that sense, but the '::' operator is useful elsewhere and C++ parser authors have enough problems already. :)
  • Jules
    Jules about 8 years
    Early versions of C++ changed from . to :: for some reason, and as namespaces were not implemented until much later than that change it is unlikely that this is the motivation.
  • Jules
    Jules about 8 years
    C++ did not have multiple inheritance when the :: operator was introduced. See the Cfront E manual, page 22 (25 in the pdf) - :: in use, but no sign of multiple inheritance in the description of classes.
  • Jules
    Jules about 8 years
    @nolandda The first version of C++, "Cpre" had a working parser that used . for scope resolution (See source code of Cfront, which was written to be compiled by Cpre: softwarepreservation.org/projects/c_plus_plus/cfront/release‌​_e/…). Having figured out how to do it, I doubt Stroustrup would have then backed down from doing it again when he reimplemented the language. I therefore don't think the technical difficulty of using it was part of the reason.
  • Rusty Shackleford
    Rusty Shackleford almost 7 years
    I don't know how Java solves this. FWIW, the D language uses syntax similar to Java and it solves it just by prefixing a dot to the name. dlang.org/spec/module.html#module_scope_operators This is essentially what @NicolBolas discussed earlier.
  • anton_rh
    anton_rh over 3 years
    a.(A.f)() would be ok for me.
  • anton_rh
    anton_rh over 3 years
    test.(foo.blah) = 10 would be ok for me.