By expressivity I don't mean conrecte syntax, but the number of lines needed to express an algorithm (up to a small constant). C doesn't have C++'s expressivity because it lacks templates, and while you can sort of express that kind of thing with macros, it's not all the way there. Zig, however, gets you all the way (you might need to write matrix_plus instead of +, but the expressivity is the same).
Which seems to be something Zig can't do.
Hell, you can define operators for generic length SIMD lane.
Can I write my SIMD/number abstraction and have it work?
Let's say I need rotors. With six dimensions. Can I overload it's basic numeric operations?
A more humble critique would be to just acknowledge that you don’t seem to be a member of Zig’s target audience, and move on.
Saying "you don't want operator overloading" in such cases is a reductionist view of how systems programming should look.
I actually don't like Rust's choice to implement + for Strings but most people seem to accept that, however C++ goes ludicrously far beyond "I don't like it but some people do" and straight off the cliff into "Nobody thinks that's OK" leaving you to wonder why there was effort to implement this bad idea. For example C++ can overload the short-circuiting boolean operators... but the overloaded versions don't short circuit. So now you've made things dramatically worse!
This depends on how you're squinting at this word "resolution".
Remember on a modern CPU an XOR R1 R1 does not result in an ALU operation, the decoder understands this idiom and just renames a zero'd register as R1, whereas of course it can't do that for say XOR R2 R3 because that's an actual XOR operation. So if "resolution" means "exactly what happens on the CPU" apparently there is no such facility provided even in assembler.
So apparently we mean only that it should have, in some sense, the same effect. I think the fact Rust is OK with
assert!("Goose".contains('o'))
assert!("Goose".contains("Goo"))
assert!("Goose".contains(&['a', 'e', 'i', 'o', 'u']))
.. meets this criterion, whereas presumably you do not agree.For a somewhat different example of the same general idea, look at how Java handles primitives and their boxed counterparts. = on two ints always compares their value. = on two Integers compares their pointers. But it uses flyweight instances for values up to 256, so in Java, whether two Integers with the same numeric value are equal according to the = operator depends on what that value is.
Then throw autoboxing and generics into the mix, and it suddenly becomes very easy to do refactorings that work fine in the unit tests (which tend to use small numbers) but fails in confusing ways in production.
This isn’t an example of operator overloading, of course. But I hope it more simply illustrates why, at least in certain problem domains, there’s value in being able to visually tell when surprising runtime shenanigans are and are not possible. And also to make it impossible to cross that boundary without touching all code that falls within the blast radius of that change.
I believe Java caches Integer objects for values -128..+128, not 256. But that may be an implementation detail, and not something to count on.
We both misremembered. I found where this is documented and the range is -128..127 inclusive: <https://docs.oracle.com/en/java/javase/27/docs/api/java.base...>