15 ms·
Sigh. Do you really think that "(vec1.mul(vec2)).plus(vec3.mul(vec4))" is better than "vec1 * vec2 + vec3 * vec4"? Thanks, but no thanks.
by spacechild1 3y ago
Sigh. 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).
- pjmlp 3y agoAssuming mul does actually a multiplication.
- throwaway894345 3y agoIt doesn’t matter, you can look it up easily because without overloading, you know exactly which implementation will run.
- pjmlp 3y agoAh, just like I do when I press F12 over an operator.
- enriquto 3y agoYou come across as a bit facetious here. Of course, the compiler or an advanced IDE can know what your code means. If all your identifiers were random permutations of l and I: lIllI1lI, your IDE would not mind either, but the code would be horrific, don't you agree? The point of the OP is that overloaded operators (and functions) make it harder to reason about the code for a human that reads it. At least for some people. At the end, everything is "just" syntactic sugar, but it makes a significant difference.
- throwaway894345 3y agoExactly. If you don't care that the code is unreadable and you can rely on every human viewing the code through an IDE with symbol resolution (and not say, online code review platforms) and remembering to use said symbol resolution to check every operator, then operator overloading is great!
- spacechild1 3y agoActually, I'm quite happy what C++ has to offer :) Yes, the * operator can be ambiguous in the context of classic vector math (although that is just a matter of documentation), but not so much with SIMD vectors, audio vectors, etc. Again: a) vec4 = (vec1 - vec2) * 0.5 + vec3 * 0.3; or b) vec4 = plus(mul(minus(vec1, vec2), 0.5), mul(vec3, 0.3)); Which one is more readable? That's pretty much the perfect use case for operator overloading.
- moshegramovsky 3y ago[dead]
- dekhn 3y agoplus(x, y) IS mathematical notation. It's Polish Notation without symbol shortcuts. Mathematica has used this for decades.
- danzk 3y agoIt's Polish Notation actually.
- dekhn 3y agoThanks, corrected in place.
- spacechild1 3y agosure, I was a bit sloppy there, but I think you know what I meant. Polish notation is just not how most people write arithmetic expressions :)
- kazinator 3y agomul(x, y) can be overloaded! x and y could be any cobination of matrix, vector, or integer, float. You're mixing up overloading (which is semantics) with syntax.
- spacechild1 3y agoWe all know that functions can be overloaded. The emphasis is on operator overloading. So yes, it is about syntax.
- slavik81 3y agoWhy have operators at all? If that notation is good enough, then you might as well use it for the built-in types too. We're halfway to designing a Lisp!
- pjmlp 3y agoHow can you be sure that plus() and mul() actually do what they say?
- coldpie 3y agoThey're functions. Whatever they do, my code will go execute some code from whatever library implements them, which is what a function does. I just want to be able to rely on [] being an array subscript when I read some unfamiliar code. Is that too much to ask?
- pjmlp 3y agoJust like the function that happens to be named [].
- kristiandupont 3y agoCan IDE's detect this and offer "go to implementation" on an overloaded operator these days? Because besides from the surprise-element in the fact that there even is code to debug hiding somewhere, not being able to quickly navigate to it is much worse in my opinion. And with infix operators where you can't even be sure which operand the implementation belongs to, figuring it out can be a bit of a detective task.
- pjmlp 3y agoVisual Studio does show a popup, go to implementation, and if the implementation happens to be visible on the same screen, also highlights it.
- circuit10 3y agoIf you’re using it right then [] is still an array subscript, just with a custom implementation for getting array elements
- throwaway894345 3y agoYou read the code. And unlike operator overloading, you know at a glance exactly which implementation to look at. There is no spooky action at a distance.
- bigbillheck 3y agoFunction overloading's not that much better.
- dleslie 3y agoEven better: (plus (mul vec1 vec2) (mul vec3 vec4)) Lisp is love.
- fsloth 3y agoThat't literally the only place where operator overloading makes any sense. In other places they monkey patch c++ defincies as a language. And they are confusing and error prone. Nobody is pretending we will get rid of any c++ syntax ever. So the discussion is about a hypothetical language syntax that fits C++ slot. In that world C++ would have N x M matrices as native value types in the language (as fortran does) and those operators would be defined in the language spec for matrix types just as they are defined for standard number types at the moment. And it would not have any operator overloading.
- crickey 3y agoMaking such assumptions about what is correct or proper use is why c++ is so successful, it doesnt make assumptions it leaves it up to the project / community using it. Go ahead make a language that dictates alot and makes srict assumptions it will be depricated or forced to open up before the end of the decade. Notr this is why i think python and lisp is so populare meta programing is very powerful and expressive.
- suby 3y agoThat's a good observation about C++ not making assumptions, it strikes me as true. C++ apparently doesn't even make assumptions about what the C++ filename extension is. .h, .hh, .hpp, .hxx, .C, .cc, .cpp, .cxx, .ixx, cppm
- fsloth 3y agoThe fact C++ has so many ways of defining things is not the reason it's so popular. The reason is the enormous industry investment on the language tooling and ecosystem. IMO the language itself is the worst part of the ecosystem, but the other parts create a totality that is the best development language ecosystem in industry for my niche (graphics and geometry) including libraries, copmpilers, debugger & profiling etc. Any language with the level of industrial support C++ has had would have grown to prominence. C++ came abut a judicious time in history when "object orientation" was becoming the latest buzzword. And now we have ended up with gazillions of lines of C++ code. It's a tragedy of our trade that two mongrels - C++ and Javascript - became to be among the most prominent in our trade.
- kristiandupont 3y agoVectors and perhaps matrices are about the only valid use case I have ever come across, so I agree with GP that it's not worth it. And that's speaking as someone who once implemented a path class with a subtraction operator that would return the relative path between two absolute ones. I thought I was very clever. I feel sorry for the developers who had to figure out what that was about after I left..
- coldpie 3y agoAh, matrices! Does * mean dot product, cross product, or the usually less useful matrix multiplication? Ooh, or maybe you should you use . for dot! How clever that would be! > And that's speaking as someone who once implemented a path class with a subtraction operator that would return the relative path between two absolute ones. I thought I was very clever. Haha! It's ok. The temptation to be clever with operators is too strong, few can resist before getting burned (or more usually, burning others!) at least once.
- owalt 3y ago> Ah, matrices! Does * mean dot product, cross product, or the usually less useful matrix multiplication? Ooh, or maybe you should you use . for dot! How clever that would be! Why the snark? The fact that you're free to make a bad choice does not imply that having a free choice must be bad. Obviously neither dot nor cross product should be *. It should be the Hadamard product or matrix multiplication. You can choose one convention for your code and be perfectly happy for it. As a follow-up question: How do you feel about languages like Fortran and Matlab then? Is it actually a good thing that mathematics convenience features are relegated to a few math-oriented languages and kept away from all the others? (Or are the linear algebra types in these languages offensive as well?)
- kps 3y agoMaybe C++26 will let us write operator·() and operator×().
- 3y ago
- bhouston 3y agoAs someone who has written math libraries over and over again for the last 25 years (I wish I was joking, but it turns out it is something I'm good at [1]), I find that operator overloading works only for the simple cases but that for performance and clarify, function names work best. Function names let you clarify that it is an outside product or inside product (e.g. there are often different types of adds, multiplies, divides), and I can not stand when someone maps cross product onto ^ (because you can both exponent and cross product some vectors, like quaternions, so why use exponent operator for cross?) or dot product onto something else that doesn't make any sense. Also operator overloading often doesn't make clear memory management, rather it relies on making new objects constantly, whereas with explicit functions, you can pass in an additional parameter that will take the result. Lastly, explicit functions allow you to pass additional information like how to handle various conditions, like non-invertible, divide by zeros, etc. I find word-based functions more verbose but significant less error prone and also they are more performant (because of the full control over new object creation.) Operator overloading is only good for very simple code and even then people always push it too far so that I cannot understand it. [1] 1997: https://github.com/bhouston/BezierCurveDemo1997/blob/master/src/AZRMATH.H https://github.com/bhouston/BezierCurveDemo1997/blob/master/..., 2001: C# math library: https://github.com/bhouston/ExoEngine3D/tree/master/Libraries/Exocortex.Geometry3D https://github.com/bhouston/ExoEngine3D/tree/master/Librarie..., 2013: a bunch of the core Three.js math library, 2023: https://github.com/bhouston/threeify/tree/master/packages/math/src https://github.com/bhouston/threeify/tree/master/packages/ma...
- spacechild1 3y ago> rather it relies on making new objects constantly, whereas with explicit functions, you can pass in an additional parameter that will take the result. We have move semantics since C++11.
- gpderetta 3y agoAnd expression templates even before that.
- deleted 3y ago[deleted]
- Etherlord87 3y agoWhat if you could type the asterisk to multiply vectors, but then your editor of choice would replace it with the symbol that actually means vector multiplication? Perhaps that idea falls apart once you realize you would need hundreds of symbols for just addition… But what if those symbols were (automatically) imported and named at the beginning? Perhaps it would be annoyingly inconsistent how in various files different symbols are used for the same operation…
- JohnFen 3y ago> then your editor of choice would replace it I realize this is a minority opinion, but I don't want my editor to replace anything unless I've deliberately told it to.
- gpderetta 3y agoIt could annotate the view without changing the source. For example my editor annotates auto with inferred types and function parameters with parameter names.
- Etherlord87 3y agoThe idea is, operator overloading is a convenience feature. Why not have that convenience as an option in an editor, without influencing the language? If you want scalar multiplication to look the same as vector multiplication, set it in your editor. If you want to insert scalar multiplication with the same key you insert vector multiplication, set it in the editor (to figure out which you mean, based on context, when you press that key). Just to be clear, I'm not being a smartass, just considering this as an option and wondering if the HN crowd has some thoughts on this.
- JohnFen 3y agoSure, there is a place for operator overloading. That said, in my experience over the decades, operator overloading has been one of the primary causes of bugs that are very hard to pin down, so I have come to hate it. It hides far too much. The cost/benefit ratio of operator overloading is generally unfavorable in practice, in my experience. Which is not to say it shouldn't be used when it actually clarifies things! But those situations tend to be fairly niche. Interestingly, where I work right now, using operator overloading is specifically prohibited. So I'm confident that my dislike of the practice is not just a personal quirk.
- Q6T46nT668w6i3m 3y agoYes (I’m a numerical analysis researcher and wrote a handful of ubiquitous mathematical packages)! The implementation of even primitive types can vary considerably! It’s way too much to hide. Nevertheless, I understand I’m biased. :)
- nunuvit 3y agoIn engineering practice, we often start using math without first consulting numerical analysts. It takes a long time to identify and fix the inevitable issues, which eventually becomes a lesson we have to teach students and practicing engineers because the field has accumulated so much historical baggage from doing it the wrong way. As an example, early device models for circuit simulation were not designed to be numerically differentiable, leading to serious numerical artifacts and performance issues. Now we have courses dedicated to designing such models, and numerical analysis is used and emphasized throughout. Is there anything today that you look at and think "yeah, they're gonna need to fix that at some point"?
- duped 3y agoNo but I think sum({ mul(vec1, vec2), mul(vec3, vec4) }) definitely is.
- dekhn 3y agoIn a certain pedantic, functional way, yes. For fast visual parsing, no.
- kazinator 3y agoOverloading is orthogonal to the issue you're striking at: infix operators versus postfix function calls. Functions can be overloaded just like operators.
- achates 3y agoI'd prefer MultiplyVecs(v1, v2) + MultiplyVecs(v3, v4) myself. Makes it easy to jump to the function definition and see exactly what's going on.