Good point, logically there are issues with them.
I agree. However, from an ergonomics point of view, something like let c = a + b is much easier for an end user to parse than something like set(new('c'), add(get_value('a'), get_value('b')))[1]. While it is possible to create a complete language using function notation, or some other wholly clean and consistent syntax, at some point we need to start thinking about ergonomics. Programmers are people, not computers; we have opinions, and often have shared opinions on what is ‘easy’ and what is ‘hard’. I will not voluntarily choose to program in Malbolge. I have programmed quite a bit in C, C++, and Python (and some others). From an ergonomics perspective, Rust feels easier to me. However, magic macros feel hard to me; keywords are the magic of the language, so they can do anything, including things that I can’t do on my own via writing my own functions or macros. Functions and macros feel like things that I should be able to do myself. That is why I prefer an offsetof keyword over a magic offset_of!() macro.
Finally, we need to consider crates that have already defined of offset_of!() (simply because they thought they needed it, and rust didn’t yet offer it). How will they deal with a new magic macro? Is the new macro going to be namespaced? Or is it going to be a built-in that stomps on (or gets stomped on by) the crate’s prior definition? Since we already had some keywords that were reserved, everyone knew not to try to use them as identifiers, so there shouldn’t be any crates in the wild that attempted to use offsetof. This makes the change somewhat less painful, and is part of my thinking for why RFC 2421 should be retracted.
[1] I just made up that syntax, it isn’t meant to be rust or any other language