42

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

manlio
  • 18,345
  • 14
  • 76
  • 126
Karu
  • 4,512
  • 4
  • 30
  • 31

7 Answers7

35

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.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Why can't you write `test.foo.blah = 10`? Or `test.base.blah = 10` where `base` is a keyword? – Nawaz Feb 18 '12 at 04:13
  • 2
    @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. – Nicol Bolas Feb 18 '12 at 04:15
  • 5
    @Nawaz: Because this would not give any way of specifying *which* `base` you wanted to use. – Mankarse Feb 18 '12 at 04:16
  • @NicolBolas: It maybe harder from compiler author perspective, but from programmers perspective `base.blah` is lot easier (and less awkward). – Nawaz Feb 18 '12 at 04:21
  • 3
    @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`. – Nicol Bolas Feb 18 '12 at 04:31
  • @NicolBolas: C++ has introduced many *`new`* keywords (pun unintended) : `new`, `delete`, `bool`, etc. Why not `base`? :| – Nawaz Feb 18 '12 at 04:36
  • @Nawaz: Let's also not forget that `base` isn't going to help you with multiple inheritance. – Nicol Bolas Feb 18 '12 at 04:50
  • 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 – Nawaz Feb 18 '12 at 04:57
  • @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. – Nicol Bolas Feb 18 '12 at 05:18
  • 1
    `test.(foo.blah) = 10` would be ok for me. – anton_rh Aug 29 '20 at 07:11
  • @anton_rh would it look up `foo` in the local scope or in `bar` scope? would it be the same as `test.*(&foo.blah) = 10` or not? – Yakov Galka Oct 18 '22 at 01:51
30

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

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 3
    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 Feb 18 '12 at 03:42
  • 1
    You could still just say `.a` to mean the global one, and `M.a` to mean the one in the `M` namespace. – Nicol Bolas Feb 18 '12 at 04:00
  • @NicolBolas: The syntax `.a` looks awkward when the syntax `.` is mostly used for *member-of* or something. – Nawaz Feb 18 '12 at 04:00
  • 3
    Maybe, but if you'd been looking at it for 10 years it wouldn't. Personally, `::` looks more awkward even after 10 years. – Nicol Bolas Feb 18 '12 at 04:08
  • 1
    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. – Karu Feb 18 '12 at 04:57
  • 1
    There is no global namespace in Java because everything is inside one class or another. – Karl Knechtel Feb 18 '12 at 05:08
  • 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 Apr 03 '16 at 15:22
  • `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. http://dlang.org/spec/module.html#module_scope_operators This is essentially what @NicolBolas discussed earlier. – Rusty Shackleford May 16 '17 at 21:52
  • `a.(A.f)()` would be ok for me. – anton_rh Aug 29 '20 at 07:07
10

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)

manlio
  • 18,345
  • 14
  • 76
  • 126
9

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;
}
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 3
    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 Feb 18 '12 at 04:07
  • 2
    C++ did not have multiple inheritance when the `::` operator was introduced. See the [Cfront E manual, page 22 (25 in the pdf)](http://www.softwarepreservation.org/projects/c_plus_plus/cfront/release_e/doc/ReferenceManual.pdf) - `::` in use, but no sign of multiple inheritance in the description of classes. – Jules Apr 03 '16 at 16:20
3

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.

Owen Reynolds
  • 235
  • 2
  • 3
3

Just to answer the final bit of the question about operator precedence:

class A {
public:
  char A;
};

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

int main(int c, char** v)
{
  B myB;
  myB.A = 7.89;
  myB.A::A = 'a';
  // On the line above a hypothetical myB.A.A
  // syntax would parse as (myB.A).A and since
  // (myB.A) is of type double you get (double).A in the
  // next step. Of course the '.' operator has no
  // meaning for doubles so it causes a syntax error. 
  // For this reason a different operator that binds
  // more strongly than '.' is needed.
  return 0;
}
nolandda
  • 2,254
  • 3
  • 17
  • 19
  • 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 Feb 18 '12 at 04:23
  • 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. :) – nolandda Feb 19 '12 at 07:02
  • @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: http://www.softwarepreservation.org/projects/c_plus_plus/cfront/release_e/src/cfront.pdf). 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. – Jules Apr 03 '16 at 16:23
1

Scope resolution operator(::) is used to define a function outside a class or when we want to use a global variable but also has a local variable with same name.