4 ms·
I disagree about the operator overloading. It's kind of like a hidden function that could have ambiguous connotations. It could confuse people because of the as
by ninetax 14y ago
I disagree about the operator overloading. It's kind of like a hidden function that could have ambiguous connotations. It could confuse people because of the association with the traditional operations.
For simple things like list addition it might be intuitive what the result will be, but if I had a a Vector class and then you were reading some code and saw two vectors being multiplied like this
a * b
well is that a dot product or a cross product? Or maybe a is a scalar and it's scalar multiplication? If it's one of those what do the other operations get for symbols? isn't it easier to do a.cross(b)?
If you keep it simple a little syntactic sugar is probably find. Nobody wants to be writing a.add(b.subtract(c.mult(d))) for a + b - c *d .
Anyone have other thoughts on this?
- nostrademons 14y agoA lot of this depends upon your attitude toward abstraction. For example, there's a Python idiom for flattening a list that is just sum(list, []), taking advantage of the overloaded + for lists. (This is considered bad style for Python; use itertools.chain instead). However, if you're a Haskeller (or a mathematician), this makes perfect sense. Any type with an associative binary + and an identity element is a monoid; any additive monad (MonadPlus in Haskell) is a monoid; List is a monad; therefore it makes perfect sense that operations like "sum" that are defined on monoids should work on lists. This is just the age old abstraction vs. traceability debate that's been going on in programming languages for 40 years. Die-hard C programmers look at Java code that says a.dot(b) and say "How can I possibly know what this does? It depends upon the run-time type of a. Much safer just to do vector_add(a, b)." Then Java programmers look at Python code that says a.dot(b) and say "How can I possibly know what this does? I don't even know what interface a and b have to conform to, they could be anything." Then Python programmers look at Haskell code that says a * b and say "How can I possibly know what this does? You say it depends upon the type of a and b, and it could be either a dot or a cross product? And what's this -XOverlappingInstances flag I need to know about?" Somewhere, there's a happy middle ground between impenetrable code vs. rewriting the same thing over and over again for different types. Personally, I think you won't find it with a blanket rule like "never use operator overloading", and it depends a lot on which abstractions come up in your problem domain.
- curiousdannii 14y agoMost types probably won't have two different product methods. If a type did then I think it'd be best to avoid overloading the operator in that case. But for those with just one? Might as well overload!
- tikhonj 14y agoThis is why I like the ability to define your own operator symbols. I think this is a good compromise between the C++/Python approach and the Java approach. The C++ approach has the problems you outlined. A single operator name (like +) gets overloaded with far too many different--and often completely unrelated meanings. Particularly, this violates reasonable expectations about how certain operators behave; for example, + should be commutative. Python's + for lists, very clearly, isn't. The Java approach of not allowing operator overloading or custom operators is also patently untenable. Just look at the BigInteger class! There are plenty of other cases when using an infix symbol makes for much clearer code. With a language like Haskell, you can just come up with new operators as you need them. In fact, they act exactly like normal function names: the only difference is in how they're parsed. This also means they're overloaded like normal functions. So while there is a + operator for a bunch of different types, it always represents some notion of addition. This feature can be abused--it's relatively easy to write confusing operator names--but I've found it to be a net benefit in practice. If used correctly, it makes the code much clearer; you just have to be a little careful. For example, in Haskell you use ++ to concatenate lists. So you can't mistake list concatenation for addition, which is important because they behave in very different ways. As an aside, if you're willing to use Unicode symbols--and I think you should be!--then you can define cross as × and write a.cross(b) as a × b. In a small expression this does not seem like much of an advantage, but if you are doing more complicated math it makes the code easier to follow. It's also roughly as easy to type: with the right input mode, it's just a \times b.
- mercurial 14y ago> With a language like Haskell, you can just come up with new operators as you need them. In fact, they act exactly like normal function names: the only difference is in how they're parsed. This also means they're overloaded like normal functions. So while there is a + operator for a bunch of different types, it always represents some notion of addition. This feature can be abused--it's relatively easy to write confusing operator names--but I've found it to be a net benefit in practice. If used correctly, it makes the code much clearer; you just have to be a little careful. I found that in practice it is often abused and leads to code full of .+:, >>> and other operators which certainly make a lot of sense to the author of the library, but don't do much for intuitive understanding of a piece of code without reading the documentation for each imported library.
- RegEx 14y agoI'm on the fence when it comes to operator overloading. I appreciate the readability gains, but the behavior absolutely has to be predictable. For example, my biggest gripe with ruby's bcrypt library is how == is non commutative. They do provide a named method alternative, but I was very confused as an infrequent ruby user.