13 ms·
Operator overloading is an anti-feature and every language with it, would be better without it. Fight me.
by coldpie 3y ago
Operator overloading is an anti-feature and every language with it, would be better without it. Fight me.
- mhh__ 3y agoWhat's wrong with being able to add my Complex or Dual numbers together?
- coldpie 3y agoWhatever you save in avoiding having to write "sum = add(l, r)" is not worth allowing programmers to bitshift file handles[1], divide file path objects[2], or subscript objects to launch a process[3]. [1] https://en.cppreference.com/w/cpp/io/cout https://en.cppreference.com/w/cpp/io/cout [2] https://docs.python.org/3/library/pathlib.html https://docs.python.org/3/library/pathlib.html [3] https://pypi.org/project/plumbum/ https://pypi.org/project/plumbum/
- mhh__ 3y agoC++ "bitshifts" (yes, but it's just a symbol in this context) make no real difference to me. It was type safe when it wasn't easy to be back in the day, everyone knows exactly how they work - it's never shot me in the foot (whereas the real meat of the design has, independently of how the composition is expressed syntactically). The others are more sus but you can make a bad API out of anything. Rewriting (say) a load of calculations as a tree of sum pow exp etc. is just a huge burden - a codebase I work on has a formula that takes up about 6 lines for example, outputted by mathematica: total pain to to translate to function calls.
- coldpie 3y ago> The others are more sus but you can make a bad API out of anything. Yahhhh but there's something about operator overloading that is like catnip to clever programmers. Ah ha, file paths have slashes, and the divide operator is a slash! Clearly I should use the divide operator to append paths segments together! I'm so clever! Ah ha, << looks kinda like an arrow I guess, so we can use it to, uh, pass data between objects, I guess. I'm so clever...? It's irresistible. We have abused it and we must give it up for the good of all.
- Georgelemental 3y agoJust because some library writers abuse language features, that doesn't mean everyone else who uses those features correctly should be punished.
- projektfu 3y ago[2] pathlib I quite like that one but I'd be willing to give it up for the hobgoblin of my little mind.
- sva_ 3y agoCounter example: Any Tensor library ever
- enriquto 3y agoYou could argue that there is just one type (tensor) with some invalid operations between its values (e.g., when dimensions mismatch). Just like integer division by zero.
- Hemospectrum 3y agoHow far are you prepared to take this stance, exactly? C has operators that are generic over both integral and floating point types. Was that a mistake? Did OCaml do it better? For my part, I've been persuaded that generic operators like that are a net win for math-heavy code, especially vector and matrix math. Sure, C++ goes too far, but there are middle grounds that don't.
- fsloth 3y agoHaving operators defined for value types within the langauge spec is different thing than defining operator overloading for arbitrary struct and class types. For numeric value types mathematical operators are the only sane option. For arbitrary classes - not so much. A sane language in the slot of C++ in the language ecosystem would not have operator overloading. It would have matrix types defined in the language spec with mathematical operators operating on them.
- repsilat 3y agoOne part of the philosophy of the language maintainers is that they're somewhat humble about their designs in the standard library, and very much against breaking changes. Some folks prefer absl's flat_hash_map over std::unordered_map for a hash table, and it's not great that you need to choose or risk having both in a codebase, but it _is_ nice that you can have your preferred hash table and use operator[] whichever you decide. Python also has operator overloading, and people seem to like that numpy can exist using it. And container types. Weirdly doesn't cause much consternation compared to C++ (maybe because the criticisms of the latter come from C programmers?) I've occasionally missed overloading in JS/TS though.
- cogman10 3y ago> It would have matrix types defined in the language spec with mathematical operators operating on them. This is unfortunately impossible (IMO). The problem is matrixes have multiple operations that don't translate nicely like complex numbers do. If you want to be consistent, you have to pick and choose What A * B means, under which contexts, and when is that illegal (or what should happen on an error). For complex numbers, there's only one definition of A * B that matters and no failure cases. I fear there's not clean way to do matrix operations that won't make some community really irritated for choosing "wrong". (Physics, engineering, science, etc.)
- zadjii 3y agoI personally love glm[1] and the way you can just vec3 foo{1, 2, 3}; vec3 bar{2, 0, -2}; auto baz = foo + bar; // {3, 2, 1} [1]: https://github.com/g-truc/glmhttps://github.com/g-truc/glm https://github.com/g-truc/glmhttps://github.com/g-truc/glm
- tomcam 3y agoCorrected link: https://github.com/g-truc/glm https://github.com/g-truc/glm
- AndrewStephens 3y ago> Fight me. OK. Operator overloading is a useful feature that saves a bunch of time and makes code way more readable. You can quibble whether operator<<() is a good idea on streams and perhaps C++ takes the concept too far with operator,() but the basic idea makes a lot of sense. string("hello ") + string("world"); complexNumber2 * complexNumber2; for (int i : std::views::iota(0, 6) | std::views::filter(even) | std::views::transform(square)) someSmartPtr->methodOnWrapperClass();
- coldpie 3y agoAll the things you wrote could be about as easily written & much more easily read without operator overloading. Operator overloading only allows programmers to feel "smart" for doing a "clever" thing, to the detriment of future readers. string("hello ").append("world"); complexNumber2.mult(complexNumber2); // wtf is even going on with this one in your example? have these people never heard of method chaining? for(int i : std::views::iota(0,6).filter(even).transform(square)) (*smartPtr)->methodOnWrapperClass(); That's all about the same verbosity, it's much more clear to the reader even if they're unfamiliar with your codebase, and dropping operator overloading eliminates the "clever" option to do stupid crap like divide file path objects together.
- AndrewStephens 3y agoWould you advocate getting rid of operators altogether? 3.times(2).plus(7) Some things just lend themselves to being expressed in terms of simple operators. (*smartPtr)->methodOnWrapperClass(); That is still using the overloaded SmartPtr<>::operator*() method. I understand the viewpoint that operator overload is syntactic sugar for things that can easily be done another way, I just disagree that costs outweigh the benefits.
- coldpie 3y ago> Would you advocate getting rid of operators altogether? Of course not. It makes sense for built-in types, as everyone reading the code can be assumed to know them. > That is still using the overloaded SmartPtr<>::operator*() method. Good catch ;) > I just disagree that costs outweigh the benefits. Yah, I think that's the disagreement. My feeling is there's a teeny, tiny handful of appropriate places for it (almost entirely math) and it opens up a pandora's box of terrible decisions that programmers clearly find irresistible.
- tomcam 3y ago> Fight me. Lunch, behind the cafeteria. Closed fists allowed, nothing below the belt.
- coldpie 3y ago"Don't bring your fists to a C++ spec fight."
- yxre 3y agoWhy not do num1.add(num2)? Or str1.append(str2)? Like with many things in C++, its another grenade, but when used appropriately is pretty great
- crickey 3y ago“Fried shrimp should be removed from the all you can eat chinese buffay because i cant help myself from eating at least 20 of them in a single sitting and now i have stomach cramp”
- coldpie 3y agoThe very first Hello World program anyone learning C++ will write uses the godawful iostream bitshifting operators! Not even the language's authors could help themselves eating 20 fried shrimp on the first day the buffet was open!
- crickey 3y agoAgreed the gluttons
- qalmakka 3y agoIf we were set on banning all of the features C++ abused from new languages, we would probably end up writing just empty brackets.
- GuB-42 3y agoAnd even then, some Python fan will come in and this is what you will end up with. https://en.wikipedia.org/wiki/Whitespace_(programming_language) https://en.wikipedia.org/wiki/Whitespace_(programming_langua...
- JohnFen 3y agoThis! The iostream bitshift overload was one of the first features of C++ that I learned to despise. I'm very happy that there's an alternative in the new version.
- spacechild1 3y agoSigh. Do you really think that "(vec1.mul(vec2)).plus(vec3.mul(vec4))" is better than "vec1 * vec2 + vec3 * vec4"? Thanks, but no thanks.
- coldpie 3y agoTry this on: plus( mul(vec1, vec2), mul(vec3, vec4)) Yeah it's a tiny bit clumsier, and prefix notation takes some getting used to. But on the plus side we avoid all the too-clever travesties programmers have inflicted on us with bad operator overloading decisions! On the whole I think it's easily worth the trade.
- ThemalSpan 3y agoSorry but please don't take Eigen (https://eigen.tuxfamily.org https://eigen.tuxfamily.org) away from me. Can't speak for others, but the scientific code I work on would become unreadable like that.
- sva_ 3y agoThe site seems to be down https://downforeveryoneorjustme.com/eigen.tuxfamily.org?proto=https https://downforeveryoneorjustme.com/eigen.tuxfamily.org?prot...
- spacechild1 3y agoAgain, no thanks. I want mathematical notation and I simply won't use any language without operator overloading. Free functions for common mathematical operations are an abomination.
- throwaway894345 3y agoThen you should probably use a language that lets you write DSLs for any given domain, rather than abusing operator overloading which just happens to work for a few subdomains of mathematics (e.g., you can't use mathematical conventions for dot product multiplication in C++). Anyway, I've never seen any bugs because someone misunderstood what a `mul()` function does, but I've definitely seen bugs because they didn't know that an operator was overloaded (spooky action at a distance vibes).
- skeletal88 3y agoI wish that Java had it, so that adding and multiplying BigDecimals would not look as ugly as it does
- zeedude 3y agoNot every day you get your wish. https://github.com/manifold-systems/manifold/tree/master/manifold-deps-parent/manifold-ext#operator-overloading https://github.com/manifold-systems/manifold/tree/master/man...
- pphysch 3y agoOperator overloading is critical for building ergonomic frameworks. The modern web is built on overloading the . operator (e.g. ORMs like Rails and Django). We will never see a Tier-1 ORM in Golang simply because it lacks it. Gamedev, AI also benefits heavily from it.
- KRAKRISMOTT 3y ago> Operator overloading is critical for building ergonomic frameworks. The modern web is built on overloading the . operator (e.g. ORMs like Rails and Django). We will never see a Tier-1 ORM in Golang simply because it lacks it. Not true. It can be replaced with codegen. See Ent (spun out of Facebook I believe) https://entgo.io/docs/getting-started https://entgo.io/docs/getting-started
- pphysch 3y agoAs I said, there won't be a Tier-1 ORM in Go. Ent or Gorm are tier-2 at best. They can get the job done, but it ain't pretty. Any advantages of Go (and there are many) are outweighed by the fact that you have to write and read 2x more code to be equally productive as Rails or Django.
- KRAKRISMOTT 3y agoYou should actually try Ent, it's about as good as commercial ORMs like Prisma.
- 65a 3y ago> We will never see a Tier-1 ORM in Golang That sounds like a good thing, having dealt with Hibernate in production. As a backend developer, I'm pretty happy with C++17 (and beyond), Go and Rust. All of them can be used in fairly explicit ways, which means debugging a problem is easy, and performance issues are right there on the page if any. I want less magic, not more.
- pphysch 3y ago
- tester756 3y agoC#?
- variadix 3y agoI disagree, it’s heavily abused but very useful for types where it’s obvious what the operation is (inherently mathematical types like vectors and matrices). I wrote a macro library for C that vector/matrix math in prefix notation with _Generic overloads and it’s still too clumsy to get used to.
- throwaway894345 3y ago> where it’s obvious what the operation is (inherently mathematical types like vectors and matrices) Considering there are like 3 different types of matrix multiplication operations, I don't think it's obvious at all. Feels like you should either use a language with complete support for implementing custom DSLs (that can express the whole domain naturally) or eschew ambiguous operator overloading altogether (gaining consistency and quality at the expense of a few keystrokes).
- suremarc 3y agoI think we all know what someone means when they say “matrix multiplication”. Asserting that * could mean, say, the Hadamard product or the tensor product is a reach. In practice I have never seen it mean anything else for matrices. DSLs just push the complexity away from the language into someone else’s problem in a way that has much higher sum complexity. You’re making authors of numerical libraries second-class citizens by doing so. For some languages that’s probably not a bad choice (Go is one example where I don’t feel the language is targeted at such use cases). Also, the lack of a standard interface for things like addition, multiplication, etc. means that mathematical code becomes less composable between different libraries. Unless everyone standardizes on the same DSL, but I find this an unlikely proposition, given that DSLs are far more opinionated than mere operator overloads.
- sgt 3y agoCage fight, or arguing about the feature?
- smabie 3y agoYou want different addition functions for floats vs ints vs unsigned ints?
- Aardwolf 3y agoI'll byte: complex numbers and matrix support is bad in languages without operator overloading. Why should only the primitive types of the language be privileged to proper math notation?
- qalmakka 3y agoBS. I thought that Java already demonstrated to the world how dumb it is to disallow operator overloading altogether. Allowing ANY operator to be overloaded was dumb, like C++ did, where you could do batshit crazy stuff like overloading unary & (addressof) or the comma operator (!), or stuff like the assignment operator (that actually opens a parenthesis about how copy/move semantics in C++ are a total hack that completely goes OT compared to this). Sensible operator overloading makes a lot of sense, especially when combined with traits that clearly define what operations are supported and disallow arbitrary code to define new operators on existing types. Rust does precisely that, and IMHO it works great and provides a much nicer experience than Java's verbose mess of method chaining.
- constantcrying 3y agoIt is a very natural feature. Especially when you are writing mathematical code e.g. implementing different types of numbers, e.g. automatic differentiation, interval arithmeic, big ints, etc. Overloading gives user defined types the expressiveness of internal types. Like all features, of they are used badly (e.g when + is overloaded to an operation which can hardly be interpreted as addition) it makes things worse. But you can write bad code in any language, using any methodology.
- CobrastanJorji 3y agoIt is a very natural feature, but it makes discovering what you can and can't do with a library really hard. Learning what is and isn't legal with math libraries that use a lot of them can be really tricky. For example, numpy code is really easy to read, which is fantastic, but figuring out how you're intended to do things from the documentation alone is quite difficult.
- constantcrying 3y agoIn my experience numpy has also been on of the worst numerics libraries to deal with. The main reason is that Python seems designed to be hostile to numerics. Loose typing, assumptive conversions, specific numeric types hard to access, tedious array notations, etc. all are bad preconditions for a language which sadly seems to have become the prototyping standard in that area. The moment you have a language actually designed for numerics all these things vanish. One of Julias core design aspects is multiple dispatch, including operator overloading and it works extremely well there. I also don't see the point for discoverability at all. The documentation will list the overloads and the non-overloaded calls are exactly as discoverable as the others.
- PartiallyTyped 3y agoExhibit a: Haskell.
- ksherlock 3y agoConsider the humble + operator. In most compiled languages -- even those that don't support operator overloading -- it is in fact overloaded. int + int. long + long. float + float. double + double. pointer + int. Would every language be better with it? Built in operators don't always map 1-1 to CPU instructions so don't appeal to that authority. There are still plenty of CPUs -- old and new -- without multiplication, division, or floating point support.
- rdtsc 3y agoAgree. It looks fun when I am writing the code and re-inventing abstract algebra and category theory types for classifying cat pictures. However then at some point I have to read someone else's code, even my own code weeks later and then I start cursing operator overloading.
- projektfu 3y agoIn C++, with its templates, there are only a couple alternatives: 1. Operator overloading 2. Operator desugaring (e.g. __subscript__(), which substitutes the intrinsic function for basic types, but can also be defined for user defined types) 3. Writing templates with weird adaptors for primitive types. Given that its design goal was to embed C, there were already operators that worked with various and mixed types. Adding (+.), etc., would have been unacceptable to the users. So, I think in general, for this language, it was good but, unfortunately, iostream made people think you should overload the behavioral expectation, too.
- duped 3y agoThe alternative GP is advocating for is "none of the above." Meaning "operators are only defined for primitive types" which is perfectly fine when working with C. If you wanted to use an abstraction over non primitive types for such things you would use a normal function.
- c-cube 3y agoBut then you make built-in types special. One of the tenets of C++ is that user defined types have as much power as built-in types.
- duped 3y agoBuilt in types are special. The compiler needs to define operator precedence and certain semantics (commutativity, associativity, overflow, etc) that cannot be expressed in the type system or enforced by the interface. The fact that it makes syntax "nicer" for user defined types is at best subjective and at worst an anti-pattern because it leads to bad compiled code and confused programmers. Function calls are unambiguous and follow the same rules as other function calls, while operator overloading does not.
- pjmlp 3y agoIts design goal was to repeat the author's experience having to downgrade himself from Simula to BCPL, he wasn't keen in repeating the same experience with C, when he went out to write distributed computing applications at Bell Labs. Bjarne has given a couple of interviews on the matter.
- renox 3y agoHow about infix function with a prefix? That is to say #+ would be an overloadable infix function, + would be a non overloadable operator.
- kazinator 3y ago> Fight me. OK, come to my glass labyrinth where you don't know which of a dozen images of me are the real instance. You will soon appreciate obfuscation techniques.
- blackpill0w 3y agoI've never understood why people complain a lot about `std::cout << "string"`, if the problem is that this operator is used for bit shifting, simply stop thinking that way (genius I know), do you think of addition when you see `string + "concatenate"`? Operator overloading is awesome, and like everything in programming, if used correctly; constructing paths with / is sweet, and I find << with streams visually appealing and expressive, it's feeding data to the stdout/file/etc, same for `std::cin >> var`, data goes from the stdin to the variable.
- enriquto 3y ago> do you think of addition when you see `string + "concatenate"` Yes. And it tortures me every time. I religiously avoid string concatenation in Python for this very reason. It's not that "+" necessarily means addition; it's that it always means a commutative operation (to somebody who has learned some algebra). String concatenation is notoriously non-commutative, thus it is extremely disturbing to write it using a visibly commutative operator. Any other operator except "+" would be better. For example, a space, or a product, or a hyphen. Whatever. But please, not a commutative operator. It breaks my brain parser.
- panza 3y agoThis is a really good point. It bothers me too, but I hadn't really articulated why.
- Dylan16807 3y agoIt's also one of the biggest sources of bugs when dealing with loose types around strings and numbers. When it comes to languages that let you mix strings and numbers, Lua has it right. + always adds, and accepts numbers and strings that can cleanly convert to numbers. .. always concatenates, and accepts numbers and strings.
- i-use-nixos-btw 3y agoAside from the syntax (I find it ugly, you find it visually appealing - it's subjective), iostreams are inefficient, awkward to customise, not thread safe (allows interleaving), and mix format and data (that one is also subjective). I love me some operator overloading. I love / for filesystem separators, I love | for piping things. I don't like << and >> so much but that's just because of too many years of writing them everywhere.
- FpUser 3y agoNah. I'll just step away and let you fall on a sword. I am not religious about languages, paradigms, etc. etc.
- anon291 3y agoNot having operator overloading is anti-human. To think so highly of yourself that there is no other thing that can properly be the subject of the field operators (or other basic operators) is the height of hubris. The compiler typically must handle the operators on certain types due to the compilation target's semantics, but in reality, there's nothing special about these 'built-ins'. Operators like +, -, /, *, etc have meanings independent of integers and floats and to not allow these meanings to be expressed is sad. I've heard many programmers express this sentiment and what they actually are attempting to argue is that having overloads of these operators that do not respect the corresponding group, ring, or field laws is confusing. This I agree with. Operators should mainly follow the proper abstract semantics.
- hgs3 3y agoThe big problem is lack of consistency: Most programming languages use infix notation for mathematical operations but polish notation for function calls. This creates an inconsistency. In languages, like LISP, that entirely use polish notation the inconsistency does not exist. One could argue that if a programming language has this inconsistency, then one should at least try to be consistent with one's notation, i.e. for mathematical operations use infix notation (operator overloading).
- Leo_Germond 3y agoOperator overloading has been a feature of many languages dating back to the very concept of using operator notation in programming. I know of no language that has the * operator dedicated solely to a single type. Typically you have at least signed and unsigned overload, as well as various bit sizes (including larger than the machine word size), and floating point representations. Extending that to vectorial operations, arbitrary precision, and others only seem to make sense and to be going with the flow...
- throwaway2037 3y agoI'm on your side, but only after many years of being on the other side. I used to think they were "graceful" and "minimalist", and refused to acknowledge they can be the source of many surprises. The Google C++ style guide has a very nice overview. There are only two pros listed, and large number of cons. And this document is old by Internet (dog) years -- at least 10 years. Ref: https://google.github.io/styleguide/cppguide.html#Operator_Overloading https://google.github.io/styleguide/cppguide.html#Operator_O...
- marmakoide 3y agoIf you do a lot of math code (linear algebra), operator overloading helps a lots to maintain readability.
- SubjectToChange 3y agoOperator overloading is one of the cornerstones of generic programming in C++. And perhaps it is a failure of imagination on my part, but it’s difficult to think of a more elegant approach.
- paulddraper 3y ago> Operator overloading is an anti-feature and every language with it, would be better without it. Fight me. In Scala, infix operators and methods are the same thing. a + b a.+(b) Or a.map(b) a map b It's never been clear to me why there should be special "operator" things.