Hacker News new | past | comments | ask | show | jobs | submit login

Operator overloading is hated among programmers who never use math; in that community all uses of "+" are to do something other than addition, usually something that's not even remotely related to addition. Operators end up as one-character infix method names.



I don’t think I’ve ever seen a library overload math operators when they didn’t do what you’d expect. And just because a language feature is abused doesn’t mean it’s bad. Typescript’s generics are Turing Complete, but they’re still great.


Look at it this way - let's say you're a programmer who never uses math. As a result, 100% of your exposure to operator overloading will be, by definition, to cases that have nothing to do with math. While a programmer that uses math will see 1,000,000 good uses and 10 bad uses, a programmer who never uses math will see 0 good uses and 10 bad uses. I saw a similar effect in the Go community where they were debating whether or not the complex type should be removed. It's absolutely crucial for signal processing, but to the rank and file REST-ist, it's just another annoying case to type out in a generic-less language.


What programmer never uses math?

I mean, most of us aren't going use linear algebra, but still...


I'm using math in a colloquial sense to refer to "mathy math," not "computer science math." So linear algebra would be a leading example, along with stuff like vectors and complex numbers. Accounting math would be another example, because it requires a bignum implementation that doesn't drop decimals like float can.


Ah! Might be helpful to specify that up front. Even so: Interval math could be quite helpful for lots of things that ... aren't using it.


> Might be helpful to specify that up front

I thought his post was pretty clear tbh. For example he mentions complex types so that should be an indicator that he's not talking about the kind of high school maths that the average developer can coast along with.


Do you have an example of someone solving a real-world problem with interval math? I've only ever seen toy examples and theoretical justifications.


1) Most of (micro-)benchmarking in computing. Of course you want a tiny bit more analysis in that case.

2) Slightly more real-world: Measuring things when you only have approximate rulers, have difficult things to measure (odd surfaces, etc.), or have to calculate from 2nd hand measurements (pictures with rulers, etc.)

Not sure if that qualifies as Real World, but...?


By real world I mean code running in production and making someone money. Or a popular open source package. And I'd be interested in which company or project that is and if they have a writeup.


So for those use cases where you will be using a library with custom types anyway, choose one that doesn't overload the operators for those types? This very much seems like a problem on the library- and not the language-level.


Also, in Rust if you don't want to use the overloading, you can still write your code to directly use function calls `a.add(b)`, where `a` is a type that implements the `Add` trait.


I get the truth in that statement. But as a game programmer, I find it interesting the contrast that linear algebra is precisely what is commonly used.


Hah! Touche!

Weird to think that game programming is (weirdly) kind of a niche thing at this point. Compared to programming boring CRUD apps, that is. :)


I encountered something similar when I was trying out Nim. In Nim - ^ is the exponentiationoperator, so x^2 means x squared. The way operator precedence is implemented in Nim is that the unary negate (-) takes precedence over the ^, so - 2^2=4. It threw me off quite a bit (coming from a physical science background I assumed it should always be - 4,took a while in my debugging to figure this out). I went to their discord (?) channel and asked about this, some of the people there could not understand how it would be any other way, which just shows that the way someone who largely translates math into code (like myself) things about code very differently then someone who never does this.


Have you ever used Boost?


First thing that came to mind was Boost Spirit: https://www.boost.org/doc/libs/1_48_0/libs/spirit/example/qi...

Lovely.


Ah, the memories: I once cut the compile time of a multi-million line C++ codebase by over 20%, just by removing one single-line use of Boost Spirit and replacing it with atoi.


I'd rather solve this with code standards around function naming conventions (including symbols as names for functions) than remove a language feature.

I don't override operators often, but when I do it's useful because the operation I'm describing is a really close parallel to other uses and properties of that operation. As an example, it's why I dislike + for list append, + is normally commutative (which list appending definitely isn't) and subtraction is pretty bonkers as a reflected operator on lists.


FWIW, I advocate ~ as array append (a la perl6/raku strings) (and also as wedge product on vectors, * being dot product). It works well with x^y as exponent/repeat, since the rhs is qualitatively different anyway[0], and also gives you (with +) a sum-of-products/dioid/semiring structure for concatenation and alternation on regular expressions. Admittedly, you still don't have a sensible semantics for division, but that's true of plenty of other product operators (even int is iffy - either not closed (div-as-float/rational/etc) or not a multiplicative inverse (divmod)).

0: In particular, exponentiation by natural numbers (or positive integers for things like nonempty lists that deliberately exclude the multiplicative identity) is almost always well defined[1], even if the thing you're exponentiating bears no resemblance to a natural number.

1: Although note than with vectors and dimensional quantities (eg meters), x^2/x^3/etc are all different types: area/volume, bivector, etc.


I get your point. But even in non-mathy business software, data structure access is so much more convenient in languages with an overloadable index operator:

C#: foo[index] = bar[index];

Java: foo.put(index, bar.get(index));


That is a very good point that I hadn't considered, because I was thinking about Go. In Go, the builtin data structures are compiler special-cases, so you get the index behavior on the map structure. Of course, it starts looking like Java for anything more advanced, but the ethos of Go is to not use anything more advanced.


There are more operators than the infix mathematical ones, like increment/decrement (cursors, iterators, custom counters), dereferencing (used for some clever pointer types), etc.

Sometimes there are good reasons to mask complexity.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: