S s;
S *p;
To read a field: s.field
p->field
It turns out that there's no ambiguity in using `.` for both `.` and `->`. Both can be: s.field
p.field
But what's the problem with `->`? It's when you want to refactor the code to switch between a value to a reference. If `.` is used for both, just change the typedef and maybe a couple places. With `.` and `->`, there are maybe thousands of tedious changes to make in the code base. The inevitable result of this is you're not going to attempt such a refactor, as it's too much work. The code stays in the way it was originally designed.I was able to see this only via broader experience with other languages. I never even noticed the issue before.
C++ addressed this not by fixing it, but by introducing the reference type. But the C++ ref type brings along with it all kinds of new problems, which I won't get into here.
your language is too sloppy for me, a pointer-to-a-struct contains a value (could say "is" a value), and some struct-members might resolve as values, but a switch from a struct to a pointer-to-a-struct is not a switch between a value and a reference; while you might call a pointer "a reference", a struct is never a value. Or did you mean a "dot" r-value and a "dereference to an" r-value? This all makes a difference because C is a call-by-value language, and you can't pass a struct, so it's an important distinction to maintain.
This kind of change might be something a student or newb might encounter, but an experienced C programmer is going to have a sense from the start whether to go with a static/local struct or a malloc'ed one. Maybe on more common a struct containing a struct might switch to a struct containing a pointer to another struct.
personally, I use hungarian and ps->x vs s.x is a nice reinforcement of what hungarian is trying to reinforce. Using parenthesis to illustrate a sort of precedence, I guess I associate the (pointer->) like that as opposed to the (.member) though I can't defend that as making an inordinate amount of sense :)
In my and others' extensive experience in C, almost everyone is wrong about where their programs are consuming time. Profiling almost always produces surprising results. Being about to easily refactor programs to experiment with different data organizations is a superpower for a language.
C programs are difficult to refactor, and so they tend to persist with their earliest design decisions despite changing requirements and profile results.
As soon as you have been in a place 3 or 6 months you are used to all the workarounds and the reasons why things can't be done.
For example, I happily programmed in C for many years while not even noticing severe problems with the language. Later broader experience with other languages led me to wonder why I didn't see the problems with C before, even though they were negatively affecting my work.