Hacker News new | ask | show | jobs
by aliasEli 1826 days ago
User defined operators frequently lead to programs that are difficult to understand, e.g. what is this '+'. When reading you will probably at first assume that it is adding two numbers, but then you also have to consider all other versions of this operator function. A function call with a good descriptive name is much clearer.
2 comments

To me, operator overloading is doing it's job well if I didn't even notice that's what was happening until I really started to think pretty hard about the details.

For example, I spent a while staring at assert_eq! statements in Rust docs wondering if an array reference is redundant, like this:

  assert_eq!(args, &["first", "second"]);
Can I just write:

  assert_eq!(args, ["first", "second"]);
Yes, I can. But wait, why can I compare these things at all, with or without taking a reference? Because the equality operator == is overloaded to be able to compare args (in this case it's a Vector of OS-specific string types) against this local array of constant strings. And clearly there's no way for the compiler to just magically "know" how to compare those somehow, the standard library explicitly tells it how to do so with an overload (by implementing the trait PartialEq)

But it made intuitive sense that you can compare them, I only wondered how it was done after I started specifically investigating this code. At a glance it made sense, and it actually does what I expected.

In contrast overloading is silly when it invents a new meaning for the operator. C++ gets a (rightful in my opinion) kicking here for streams, but I can also see an argument for the same claim about using + for string concatenation.

Restated: If I see a = b + c in a program, I am OK with a, b and c all really being some complicated object and not just numbers, just so long as intuitively you can add the a object and the b object together and that is in fact what this code does. If that makes no sense, or it doesn't do that, then you shouldn't have overloaded the operator.

Operator overloading in the style of C++ is pretty silly, and your concerns apply.

Have a look at how eg Haskell deals with operators:

- You can define your own, so you don't need to re-use bit-shifting for IO. And in fact, you wouldn't be able to do so.

- There's also specific kind of overloading, so that '+' can work with different types. But eg you couldn't turn bit-shifting '<<' into an IO operator.

The rules for shadowing of operators are the same as the rules for shadowing any other function or variable name.

In fact, operators are just a weird syntax to write binary functions in Haskell. Otherwise they behave exactly the same.

Whether to use operators or functions with 'normal' names is then only a stylistic question, and a library can offer both styles to its users. (And you can retrofit the style of an existing library without having to have access to the library.)