58

It seems to me that C's arrow operator (->) is unnecessary. The dot operator (.) should be sufficient. Take the following code:

typedef struct {
    int member;
} my_type;

my_type   foo;
my_type * bar;
int       val;

val = foo.member;
val = bar->member;

We see that the arrow operator must be used to dereference bar. However, I would prefer to write

val = bar.member;

There is no ambiguity as to whether I am trying to pull 'member' from a structure or from a pointer to the structure. But it is easy to use the wrong operator, especially when refactoring code. (For example, maybe I am doing some complex operations on foo, so I move the code into a new function and pass a pointer to foo). I don't think I need to care whether foo is a pointer or not; the compiler can worry about the details.

So the question: wouldn't it be simpler to eliminate -> from the C language?

remline
  • 605
  • 1
  • 6
  • 3
  • 4
    There are billions of lines of C code in use today. It wouldn't be simple to remove anything from the C language. That said, explicitness about indirection is A Good Thing. – James McNellis Apr 05 '12 at 21:39
  • 11
    You're right, it is unnecessary. It is syntactic sugar for `(*bar).member`. By definition, we don't _need_ any syntactic sugar. Then again, we don't _need_ functions, either. we _could_ just do everything with `goto`. – jpm Apr 05 '12 at 21:43
  • 1
    Yes, but it seems like syntactic sugar which makes things harder rather than easier. Functions, on the other hand, are handy. :) – remline Apr 05 '12 at 21:48
  • @jpm: What about recursive calls? Note that even BASIC had `GOSUB`, and processors have `call` instructions. – celtschk Apr 05 '12 at 21:54
  • 4
    Duplicate of [Why does the arrow (->) operator in C exist?](http://stackoverflow.com/q/13366083/3425536). – Emil Laine Dec 13 '15 at 23:22
  • 3
    In the Rust programming language, the `.` operator dereferences as many layers of pointers as needed before accessing the struct field. It does exactly what you're asking for in this thread. – Nayuki Dec 15 '20 at 16:27
  • 1
    Due to `*` and `.` precedence, you have to write `(*(*(*a).b).c).d` for `a->b->c->d`. I prefer the readabilty of the second – ghilesZ Jan 12 '21 at 11:33

2 Answers2

93

The 'arrow' operator is syntactic sugar. bar->member is the same as (*bar).member. One reason for the difference is maintainability. With the arrow operator distinct from the dot operator, it becomes much easier to keep track of which variables are pointers and which are not. It might be possible to always use . and have the compiler try to do the right thing, but I doubt that would make the language simpler. Trusting the compiler to interpret what you meant instead of what you literally wrote usually turns out badly.

bta
  • 43,959
  • 6
  • 69
  • 99
  • Not to mention classes that act like pointers (providing `*` and `->` operators), but on which `.` is also a valid operation. – jpm Apr 05 '12 at 21:47
  • 5
    @jpm: C does not have classes. However you have a point insofar as this would introduce a needless incompatibility to C++ (which for the reason you state would probably not adopt that convention). – celtschk Apr 05 '12 at 21:49
  • If `member` is itself a struct, does this equivalence between `(*).` and `→` still apply? e.g. `bar→member→value` is the same as `(*bar).member→value`, but `bar→(*member).value` is different (in fact, it gives a compile error). – Max Coplan Feb 25 '19 at 19:30
  • 1
    @MaxCoplan If `member` is a struct, you can't apply the `*` *or* `->` operators to it. Both `bar->member->value` and `(*bar).member->value` are equivalently wrong. The only correct ways to do it would be `bar->member.value` or `(*bar).member.value`. – bta Feb 25 '19 at 23:53
  • @bta My bad! I meant if `member` is a pointer to another struct. So, ASSUMING `bar→member→value` is valid, `(*bar).member→value` will also work, but `bar→(*member).value` and `(*bar).(*member).value` will be different. – Max Coplan Feb 26 '19 at 18:04
  • 3
    @MaxCoplan Yes the two forms are still equivalent, but operator precedence quickly makes things quite ugly and error-prone (`.` and `->` bind higher than `*`). `a->b->c` would become `(*(*a).b).c`. You really don't want to write this out the long way in a multi-level scenario. – bta Feb 26 '19 at 18:17
  • Explained perfectly, thanks – Max Coplan Feb 26 '19 at 18:31
  • (P.S. for [further reading](https://stackoverflow.com/a/13366476/6100005)) – Max Coplan Feb 26 '19 at 20:38
9

No, it would not be easier to eliminate -> from the language, for the simple reason that megatons of code would have to be rewritten if it were. However one could define that p.x is equivalent to p->x if p is a pointer. That would be a backwards-compatible change because that code is currently illegal.

celtschk
  • 19,311
  • 3
  • 39
  • 64
  • 5
    Yes, but as @bta mentions, it would be an unwise change. `->` helps significantly in determining which variables are values and which are pointers, which in turn can help keep memory management maintainable. – jpm Apr 05 '12 at 21:45