3 ms·
I think the problem with custom operators is they have custom associativity and precedence. Not saying this is a deal breaker, just the biggest issue you'll run
by ben509 8y ago
I think the problem with custom operators is they have custom associativity and precedence. Not saying this is a deal breaker, just the biggest issue you'll run into.
In toy examples, you can see all that because they'll show the declarations.
Here's a case[1] trying to explain monads by showing a simpler example:
parseP5_take2 s =
matchHeader (L8.pack "P5") s >>?
\s -> skipSpace ((), s) >>?
(getNat . snd) >>?
skipSpace >>?
\(width, s) -> getNat s >>?
skipSpace >>?
\(height, s) -> getNat s >>?
\(maxGrey, s) -> getBytes 1 s >>?
(getBytes (width * height) . snd) >>?
\(bitmap, s) -> Just (Greymap width height maxGrey bitmap, s)
Is all that left or right associative?
Generally, to read an expression when you have custom operators, you have to dig up the associativity and precedence. That's why I see many newer libraries avoiding custom operators, [2] vs [3].
I think you can do custom operators in a language, you just need to require that the associativity and precedence be declared in import. I'd also have named levels of associativity, so maybe:
import MyModule.Foo.Bar (op(!$!, additive, right), ...)
Now, that's some boilerplate in your imports, but for readability, it'd be huge. And automated tools can tweak stuff like this.
[1] http://book.realworldhaskell.org/read/monads.html http://book.realworldhaskell.org/read/monads.html
[2] http://hackage.haskell.org/package/pretty-1.1.3.6/docs/Text-PrettyPrint.html#g:6 http://hackage.haskell.org/package/pretty-1.1.3.6/docs/Text-...
[3] https://hackage.haskell.org/package/prettyprinter-1.2.1/docs/Data-Text-Prettyprint-Doc.html#g:17 https://hackage.haskell.org/package/prettyprinter-1.2.1/docs...
- hodgesrm 8y agoOn my first C++ project we enthusiastically implemented customized versions of operators like '+' on new types. It turned out to be really confusing for exactly the reasons you mention. Operator overloading in general only seems to be practical for mathematical types like sets or sequences where the rules are well-defined thanks to generations of people thinking about them. Yet, even the set case works poorly for C++ because in addition to associativity new operators also inherit the built-in operator precedence rules. For example should * take precedence over + in set operations? (Assuming you implement * for cartesian product and + for union.) Maybe C++ has changed since I used it but this sort of thing really gets in the way of writing correct code.
- ktpsns 8y agoFrom my feeling, C++ makes it verbose to overload operators in every possible context. Thinking of Foo::operator()+, there are all these border cases where custom overload functions have to be provided (such as "(int) + (Foo)", "(Foo) + (int)", "... += Foo", etc.). I assume that in other languages it is probably simpler to fully implement own operators.
- hodgesrm 8y agoExactly. This part of C++ always felt experimental to me--something that was plausible to try but ended up digging a hole with a lot more complexity than the language designers perhaps intended.