Hacker News new | ask | show | jobs
by goostavos 5074 days ago
I'm still a bit of a novice, could someone elaborate on what he means by operator overloading being "problem creating?" I thought that was one of the main, 'core' concepts of OOP. Inheritance, and polymorphism.

How would you make something like a GUI without being able to specialize classes by overriding certain methods?

Have I misunderstood his point?

6 comments

The argument is roughly that it is, in fact, not very useful, while opening up a vast array of misuses - especially in the domain of being all too clever. What does "+" mean on a list and an object? Add, probably. But what if it's two lists? Union? Or add the second list as the last element to the first? Named functions "add" and "union" aren't any less readable and loads more descriptive.

The only situation you positively need operator overloading is when doing arithmetic, and you should do that using the built in types. This, of course, sucks when the built in types are inadequate, and you e.g. want to use a arbitrary precision library such as BigDecimal in Java.

This, of course, is an opinion, and I'm not shy to admit it's been shaped by being burned by Lift, the Scala web framework which makes heavy use of symbolic function names which makes it incredibly difficult to talk about or search for answers online.

Of course, Go itself is completely unsearchable, so you always have to search for Golang, which means that thee mut be hundreds of pages that get missed.
And "C" or "D" are searchable? Or "Java" (island, coffee) or "C#" (musical scale)? Or "Basic" (fundamental)? Or "Python" (snake) or "Ruby" (gemstone)? Or "Lisp" (speech impediment)? Or "Pascal" (French mathematician, SI unit and general given name)? Or "Smalltalk" (informal conversation)? Or "Logo" (emblem)? Or "Lua" (Portuguese word for moon)? ...
In my humble opinion, in the vast majority of cases, yes. Because " C ", " D ", " C# " should be easier for search engines to disambiguate (at least working with Lucene, it is, and I imagine Google etc are similar-ish).

As for Java, Python the context in the page likely to point to its intended audience (and it helps they have been around for ages etc). Otoh, " go " is likely to be used in a lot of literature, including other programming related texts.

Try searching for something with clojure, and then try go -- the quality of results is usually substantially different, and my unsubstantiated hunch is that not all of it has to do with lack of go-related content.

Seems to be getting better though..

I would think that the search algorithms are smart enough to conflate references to go in an article about programming with golang as a search query. I am not a google engineer but I do know that they have very good "did you mean" analysis on search queries.
Maybe they should have named it “gox”. Then you would just have to filter out the Dr Seuss references.
Doesn't ruby with its "operators are actually methods and fair-game for redefinition" implementation disprove the theory operator overloading is an a priori Bad Idea (tm)?

Those guys seem to manage the flexibility pretty well.

In my experience, ruby's '+' doesn't get redefined all that often. The most-redefined operators I've seen are '[]' and '<<'.

I think it works because people don't usually just go around wantonly pushing objects onto each other. It's usually part of a DSL that's used deliberately. Some of the craziest I've seen were things like _why's Hpricot library, which made a sort of xpath-like DSL:

    doc / :div / ".foo"
If I saw it out of context I'd assume it was some sort of pseudocode.
His point is that, if you aren't familiar with the code, operator overloading can be difficult to read. It gives objects the appearance of being native types, and it is sometimes not entirely clear what the result of the overload might be. What does "dog + cat" equal? In an extreme example, if you are crazy enough, it might make sense to have animal + animal = baby animal. You need to temper that example down to something closer to reality :)

I personally like overloading, but I think it's probably too easy to abuse, and I can see how it would cause problems with a team size larger than 5.

As far as I can see, whenever the Go team encountered a language feature that could possibly be abused, they always deferred to leaving it out. Whether that is good or bad I'm not sure we will know until we have years of experience with it.

> As far as I can see, whenever the Go team encountered a language feature that could possibly be abused, they always deferred to leaving it out.

All features can be abused.

The Go philosophy is more to leave out features that obscure the meaning and understanding of code (what is also known as "magic").

Also part of the Go philosophy is to not include any feature unless it is clear that its benefits are greater than its costs, and which might interact in unpredictable ways with other existing features.

In other words, the default is to leave things out, rather than to include them, the opposite of a kitchen sink approach.

I think the poster child for operator overloading abuse is iostreams overloading << and >>.

However, operator overloading is very much needed for when creating user defined types that have arithmetic properties, such as bigint, or matrix.

As for the confusion about whether + means "add" or "concatenate", that is unresolvable. The D programming language deals with it by introducing the ~ binary operator to mean "concatenate". No more problems.

Although in D one can overload operators to mean any crazy thing one wants to, the consensus in the community is to eschew non-arithmetic use in the same manner that the C community has condemned:

    #define BEGIN {
    #define END }
Ah, that makes sense. Really good explanation. Thanks!
Operator overloading has nothing to do with OOP.

In go you get polymorphism via interfaces and you can share implementation via embedding. http://golang.org/doc/effective_go.html#embedding

I haven't seen a GUI written in Go yet, but the basic idea is that you don't customize via inheritance; you do it in a different way. For example, in many UI libraries, you can create a function and ask a widget to call you when you receive an event; the widget will have methods like:

  addClickHandler(myFunction)
Any customization you could do with inheritance could be done with a callback function instead, provided that the object has the hook you want.

In Go, there is also an "interface" which is basically a set of methods.

That is more or less how UIs using Cocoa/Cocoa Touch are working from a developer standpoint of view. Most standard views/controls have a delegate property which is informed about certain things happening or asked when an important decision has to be made. This works extremely well and by implementing a delegate you get around the problems related to subclassing UI controls/views. Now that Objective-C/C has blocks Apple began to replace (or add) block based "callbacks" which makes life easier in most cases.
Opertor overloading is really horrible.

By reading the code "foo + bar" you can't know what is really doing internally.

He is talking about operator (+-*=[]&) overloading. Not method overloading.

I wish I could agree, but experience has shown that not having operator overloading makes (a) operating polymorphically over different number types and (b) creating new number types (decimals, bigints, etc.) really awkward. The former is much of the reason we had to add it to Rust. We have matrices that can operate over any numeric type T that implements the basic operations (so we can write matrix math once and have it work on 32-bit floats and 64-bit floats; this is important for speed vs. precision for browsers vs. scientific computing), but we couldn't put an addition operator in the Num interface, so we had to make "add", "sub", etc. methods. The result made our matrix math operations nigh-unreadable.
How did you solve the problem in your matrix libraries of overloading a single operator multiple times? I was trying to make rudimentary, game-oriented linear algebra library in rust along the lines of glm. I immediately ran into the problem of not being able to implement "mat4 * float->mat4", "mat4 * vec4->vec4" and "mat4 * mat4->mat4" overloads at once. The alternative was only to go with "mult_float", "mult_vec4" and "mult_mat4", but as you say this leads to "nigh-unreadable" code.

It might seem petty, but whilst I understand rust avoiding overloading functions entirely (due to type problems and code obfuscation), it was enough to turn me off entirely, in this case sending back to D.

Bear in mind this is not to say Rust is a bad language - there's plenty to like about it. ;)

I was about to say "you can't do it", but I think you can -- the trick is to use a bounded generic implementation. Once "Mul" becomes a trait, you'll be able to say this:

    trait MatrixMultiplyRHS<Result> {
        fn mul(matrix: Matrix) -> Result;
    }

    impl<RHS:MatrixMultiplyRHS<Result>,Result> Matrix : Mul<RHS, Result> {
        fn mul(rhs: RHS) -> Result {
            rhs.mul(self)
        }
    }

    impl float : MatrixMultiplyRHS<Matrix> {
        fn mul(matrix: Matrix) -> Matrix {
            // ...implementation of matrix scalar multiply...
        }
    }

    impl Vector : MatrixMultiplyRHS<Vector> {
        fn mul(matrix: Matrix) -> Vector {
            // ... implementation of matrix multiply for vectors ...
        }
    }

    impl Matrix : MatrixMultiplyRHS<Matrix> {
        fn mul(matrix: Matrix) -> Matrix {
            // ... implementation of matrix multiply for matrices ...
        }
    }
It's admittedly a bit awkward, but maybe that's OK to discourage overloading unless you actually need it. Still, your point was very interesting -- I didn't realize this was possible! -- and I'll spread it around the team.
Ahh neat.

Just as a warning, I've already aired this topic on github, so maybe that might be a good place to discuss it: https://github.com/mozilla/rust/issues/2961

I don't want to cause a fuss. While Rust might not work for my needs/wants/desires, that's ok. I highly respect those who don't attempt to please everyone. :)

I don't know rust but rust seems very much like C++.

Did you have a look at the Eigen library (C++)?

http://eigen.tuxfamily.org/dox/TutorialMatrixClass.html

I have never worked with this library but it seems to me that they have not the problems you described. Maybe having a look at it brings up some new ideas...

Although on superficial level it shares the AGOL/C-style syntax, Rust is a very different language from C++. Some things are possible or easier in Rust as opposed to C++ and vice-versa. Copying directly from a C++ library would be difficult, and wouldn't take advantage of Rust's unique strengths.
Okay. Thanks for the info. I just had a quick look at Rusts wikipedia entry and saw that it has been influenced by C++. But as you pointed out, this might not mean much...
And how do you know what add(foo, bar) does internally?
You are missing the point. You might not know exactly what add() does internally but "+" only gives you a 1 character description, requiring you to know, or assume behaviour of the terms being added. By using a function name instead, you have far more opportunity to describe more clearly what actually is going to happen, requiring less assumption which as we know is the mother of ....
add(foo, bar) isn't any clearer than foo + bar, but usually an overloaded operator doesn't correspond to "add".

For example, in Javascript: "Hello" + " " + "World!". What the operator there is doing is concatenating the strings, so if you had a method to do it you wouldn't call it add - you'd call it concat.

But then you lose the information that both ((usually modular) arithmetic, and strings with concatenation, et al.) are monoids, and have a similar structure, and creating generic functions which might use that symmetry becomes more difficult.
In python you can overload + and a lot of other numeric operators by implementing certain methods __add__ for +, see others here: http://docs.python.org/reference/datamodel.html#emulating-nu...

In ruby you can implement certain numerical methods including +

In smalltalk + is a binary method, you can give your methods all sort of symbol names. Same with Scala I think.

> For example, in Javascript: "Hello" + " " + "World!". What the operator there is doing is concatenating the strings

Hmm, are we talking about (user defined) operator overloading as a language feature, or about overloaded operators? For example, I hate that 1/2 and 1.0/2 are different things in most languages, but I haven't heard anyone call this operator overloading in the context of C.

"foo + bar" looks like a string
Yes, I think you misunderstood. You are thinking of overriding methods, which is very important. Operator overloading is where you redefine the behavior of a "+" symbol, for example.
In a number of oo languages + is a method(smalltalk, ruby, python)(possibly using some sort of special casing of addition for integers/floats to speed up the common cases)/