Because back in the old days, there was no requirement that the left
operand have a structure or pointer to structure type. You could (and
people did!) use . or -> on integers, arrays, or whatever. Since the
operators do different things, they had to be distinct so the user could
specify which operation was desired. Now that the left operand is
restricted, there's no technical reason for having distinct operators.
Given that they already exist, however, there doesn't seem to be any
particular benefit to merging them and there would be real costs
involved to do so.
yes, ok.
seems I am not so fammiliar then with C from that era (I am not particularly
sure then how struct or union access would work at all...).
as noted, there is a cost, but more in the form of someone accidentally
writing non standards-conformant code. existing code works fine (there not
being cases where both work but have different meanings), so this is not as
much of a problem.
Although you describe it as being "lazy", I can't imagine that
implementing one operator that can do either of two things is any less
work than implementing two operators each of which only does one thing.
one can be lazy, because at nearly every stage of the compilation process
(much past the parser), they can be treated as one operator, and doing it
this way requires less effort (we would have, one case for '.' and another
case for '->').
this is infact less work in general (less cases is easier than more cases).
and, in what way to either of these operators only do one thing?
we already have to figure out which types they are being used with, and to
handle a pointer-to-case along with a raw struct case (often internally
represented by passing a pointer anyways), there is no real savings in work
by having them split (actually, there is more work, since then one is
obligated to diagnose their accidental misuse, ...).
(we are long past the days where we can claim any one operator does any one
thing, in fact, any one operator does any number of a wide variety of
possible but related things...).
now, when one gets a little closer to the final code generation, it is
fairly trivial to recognize what types are being applied (after all, we have
to do this much already), and so, slightly different code is generated (from
this point on, they are different operators, but past this point, any real
notions of 'structs' or 'operators' have already since gone away, us having
moved into the land of register allocation and CPU-level operations).
of course, in my tweakery, I went and used this operator for a few
non-struct types as well, such as vector access and permutations (like in
GLSL...).
and, if I were to add special operators for vector operations, I would end
up having to deal with them at each and every stage in the compilation
process, but overloading them, I only have to deal with this difference once
it actually matters...