8 ms·
Operator overloading is one of those things that needs to be done with good taste.
by dzogchen 3y ago
Operator overloading is one of those things that needs to be done with good taste.
- TillE 3y agoHonestly I can't think of many notable abuses of operator overloading in C++. The worst is probably the original idea to overload the bit shift operators for stream I/O, something which never really caught on outside the standard library.
- blt 3y agoAgree. Meanwhile there are flagship C++ libraries like Eigen where it's indispensable. C++ has mistakes but operator overloading isn't one of them.
- hawski 3y agoThere could be a couple of examples in Boost like Boost Spirit [0]. Qt had some like putting stuff in containers with bitshift operator. There was a GUI toolkit that used + operator to put widgets on a window. [0] https://www.boost.org/doc/libs/1_78_0/libs/spirit/doc/html/spirit/introduction.html https://www.boost.org/doc/libs/1_78_0/libs/spirit/doc/html/s...
- 1letterunixname 3y agoContinuation passing monads form the basis of a perfectly valid and usable software architecture and programming pattern. In the case of ostream and operator<<, this pattern reduces the number of intermediate objects that would otherwise be constructed. If you object to iostream on religious or stylistic grounds, there's always fmt which is more like Go or Python string interpolation.[0] 0. https://fmt.dev https://fmt.dev
- rwbt 3y ago> If you object to iostream on religious or stylistic grounds, No I object to it on usability grounds. It took more than 30 years for the committee to admit it but C++ now has typesafe std::print/std::format finally, after admonishing programmers for using `printf` in C.
- gpderetta 3y agoC++ only acquired the capabilities to have a statically type safe format string only recently. Iostreams have a lot of issues, but overloading<< is a very minor one.
- hawski 3y agoBut it is achievable without operator overloading, isn't it? There is also a reason why format strings seem to be more popular among the crowd.
- gumby 3y agoStreams have numerous design problems (e.g. representation is managed by the stream, not the thing you’re printing) making the shift operator syntax the least of the problems.
- kccqzy 3y agoWhich part of operator<< involves continuations, let alone continuation passing monads?
- rwbt 3y agoThe soon to be standard C++26 Reflection library?
- gpderetta 3y ago2126 that is?
- TrianguloY 3y agoI remember a university project where I used the >> (and <<) operators to "send" data between services. The code was a simulation of a parallel system with multiple services that sent messages between them, or something like that. Instead of using serviceA.send("hello",serviceB) you had something like serviceA >> "hello" >> serviceB. I really loved that (my classmates not so much)
- puffybuf 3y agoI did something similar as a student, making my own exception class with std::ostream: throw exceptionC() << "error code: " << t; I often found myself having to format error strings for exceptions, so I thought I could just do it like cout in one line. I know now this is bad for i18n strings.
- rockwotj 3y agoGoogletest does this: http://google.github.io/googletest/primer.html#assertions http://google.github.io/googletest/primer.html#assertions
- codr7 3y agoWhy would you prefer that over: throw exceptionC("error code: ", t); ? Ever since perfect forwarding I've been using this pattern to get out of arrow hell: template <typename Arg, typename...Args> string to_string(Arg &&arg, Args &&...args) { stringstream buf; buf << arg; ((buf << std::forward<Args>(args)), ...); return buf.str(); }
- lioeters 3y agoReminds me of the ChucK operator. SinOsc b => Gain g => BiQuad f => dac; https://chuck.stanford.edu/doc/language/oper.html#chuck https://chuck.stanford.edu/doc/language/oper.html#chuck
- duped 3y agoI've seen operator* overloaded to return RAII guards, including ones for RCU, and operator() overloaded for so many things that should just be lambdas it's hilarious
- DrFalkyn 3y agoYeah the () overload was for functors, the old school way of doing closures before lambdas.
- duped 3y agoIt was certainly how I learned to do it, but lambdas have been around for over a decade and I still see people writing functors. The only use case I've seen where it made sense is for things like coroutines.
- ksherlock 3y agoFor std::visit() (std::variant.visit in c++26 I see) which is the visitor pattern, you can use a functor with multiple visit types or roll your own overload() template to merge multiple lambdas into one class. https://en.cppreference.com/w/cpp/utility/variant/visit https://en.cppreference.com/w/cpp/utility/variant/visit https://en.cppreference.com/w/cpp/utility/variant/visit2 https://en.cppreference.com/w/cpp/utility/variant/visit2
- duped 3y agoBut why would I want to do this instead of just having multiple lambdas that capture the same values by reference, or using shared_ptr and synchronization? I can see lifetimes of the data being an issue, but you shouldn't be calling std::visit in a way where that could cause a problem without synchronization anyway.
- gpderetta 3y agoLambdas these days cover 99% of the needs for custom function objects. But for that 1% it is useful to be able to have full control of your closure. For example how would you implement std::function without overloaded operator()? Also lambdas are defined in term of structs with overloaded operator (). Without overloading, the standard could still ad-hoc define the specifications of lambdas and std::function, std:: ref, etc, but the language would be worse off.
- barosl 3y ago> to overload the bit shift operators for stream I/O MFC extends this idea to network programming, allowing the use of shift operators to send and receive data.
- wolfspider 3y agoMFC also has CComPtrBase which uses & to represent pointer lifetimes to COM objects such as while(pEnum->Next(1, &pFilter, &cFetched) == S_OK). Especially fun when debugging DirectShow filtergraphs someone made in the UI completely. There is more of an explanation here: https://devblogs.microsoft.com/oldnewthing/20221010-00/?p=107269 https://devblogs.microsoft.com/oldnewthing/20221010-00/?p=10...
- garaetjjte 3y agooperator/ for concatenating path components in std::filesystem
- Sharlin 3y agoOne of the most magnificent abuses of operator overloading ever: multi-dimensional analog literals (http://www.eelis.net/C++/analogliterals.xhtml http://www.eelis.net/C++/analogliterals.xhtml)
- gumby 3y agoTruly marvellous!
- Q6T46nT668w6i3m 3y agoI don’t hate this! The author is, despite their sarcasm, correct—sometimes integers are insufficiently expressive. It’s the C++ equivalent of geometry in the Wolfram Language.
- layer8 3y agoThis could potentially be extended to UML diagrams to express program logic (or at least to generate SVG versions).
- rramadass 3y agoWhaaaaat? Jesus! Some people are just too creative; i am almost afraid to test out the code.
- Quekid5 3y agoThat was a very cheeky comment, and fully agreed. I'm on the permissive side (Haskell and Lenseful Haskell at that!), but make it consistent and principled and it's usually fine.
- kibwen 3y agoExtreme take, but the older I get the more I start thinking that the very concept of operators was a mistake, overloadable or otherwise, especially in a systems language. Even for something as simple as addition there's just too many actual operations that I might want to invoke (wrap on overflow, saturate on overflow, crash on overflow, raise exception on overflow, flag on overflow so I can raise later, return boolean to indicate overflow, return tuple of wrapped result and overflowed remainder on overflow).
- wwalexander 3y agoPerhaps operators could only be overloaded, without any defined by the language itself. Then projects could define useful operators for their specific case to make things more terse/infix/etc. while still requiring awareness of their implementation.
- knome 3y agoNo. Haskell made me decide that operators should not be definable by users. It is truly a miserable affair to read terse point free code riddled with operators from a half dozen libraries ( or one overly clever library ). Cleverness is a register that is easy to overflow, and too many don't have to good taste to avoid doing so. Give me names every time.
- hollerith 3y agoDo you consider them as bad as user-definable Lisp or Scheme macros?
- j16sdiz 3y agoIt depends on what you tries to do. Doing linear algebra without any operator overloading is just unreadable
- layer8 3y agoI think GP meant users should not be able to define new operators (as is possible and fairly common in Haskell), but may still be allowed to overload the existing operators.
- deleted 3y ago[deleted]