About this blog

Save duplicate questions from disappearing from Google

Wouldn't it be possible to use just dot (.) to access members of namespace and static members of a class

Question

In C++ we use double colon (::) to access members of namespace, use dot (.) to access members of class/structure and use arrow (->) to access members of class/structure via pointer.

Wouldn't it be possible to use just dot (.)? E.g. my_namespace.my_class.my_static_pointer.my_member. Why are separate lexemes used? Would there be any problems with syntax, if only dot (.) were used for all three cases?

Answers

Answer #1

As observed by Jules it's a fact that early C++ implementations (CFront pre-1.0) had a dot for scope identification.

A dot was also used in C with Classes (1980). Indeed this is a simple snippet from Classes: An Abstract Data Type Facility for the C Language 1:

class stack {
    char    s[SIZE];  /* array of characters */
    char *  min;      /* pointer to bottom of stack */
    char *  top;      /* pointer to top of stack */
    char *  max;      /* pointer to top of allocated space */
    void    new();    /* initialization function (constructor) */
public:
    void push(char);
    char pop();
};

char stack.pop()
{
    if (top <= min) error("stack underflow");
    return *(−−top);
}

(the code was an example of how member functions were typically defined "elsewhere")

The :: was one of the additions to C with Classes introduced to produce C++.

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

(A History of C++: 1979−1991 [2] page 21 - § 3.3.1)


  1. Bjarne Stroustrup: "Classes: An Abstract Data Type Facility for the C Language" - Bell Laboratories Computer Science Technical Report CSTR−84. April 1980.

  2. Bjarne Stroustrup: "A History of C++: 1979−1991" - AT&T Bell Laboratories Murray Hill, New Jersey 07974.

Comment

It is still unclear what those minor confusion and ambiguous examples are.

Answer #2

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)

Answer #3

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.

Comment

"test.(foo.blah) = 10" could be used in such ambiguous cases.