Method and operator overloading



  • There has been some debates, as always on programming fora co-habituated by both Java and C++ coders, about operator overloading: the anti-C++ Java camp tend to hold that operator overloading is evil. Out of curiosity, since Java does not support operator overloading but supports method overloading, how come we never hear from the same vocal antagonists that method overloading is equally evil? They should give rise to the same (mythological) "code complexity and subtle bugs", as it is often put.



  • There is only a handfull of operators to overload, so someone who wants
    to use this feature is relatively likely to "abuse" an operator, i.e.
    give it a meaning that doesn't match the original meaning. Like
    << in C++.

    Method names are words and there is no motivation to use an improper
    word for a method. No sane programmer would denominate a method
    "leftShift" when he means "output".




  • @ammoQ said:

    There is only a handfull of operators to overload, so someone who wants
    to use this feature is relatively likely to "abuse" an operator, i.e.
    give it a meaning that doesn't match the original meaning. Like
    << in C++.

    Method names are words and there is no motivation to use an improper
    word for a method. No sane programmer would denominate a method
    "leftShift" when he means "output".


    And no sane programmer would overload an operator in a completely stupid and abusive way.

    Point is, being downright stupid can easily replace insanity in both these "use cases", and this very forum teaches us that The World has an endless supply of Stupid.



  • @ammoQ said:

    There is only a handfull of operators to overload, so someone who wants
    to use this feature is relatively likely to "abuse" an operator, i.e.
    give it a meaning that doesn't match the original meaning.

    By giving an operator a meaning that doesn't match the original meaning--do you mean, like, using + to denote string concatenation?



  • @ammoq:

    So, you're saying that since there are only a finite number of operators in C++ then someone must abuse them? Then, say, Perl would be a better language for overloading operators?

    We have discussed operator overloading in other threads, and I remember you have used the "<<" operator example there too. I said then that there's nothing wrong with using the operator that way.

         First, the pictographical meaning of the operator is very clear: movement to the left. The meaning is evident in the very image of the operator in a way that is remenescent of pictoral usage dating back to neolithic art, and I refuse modern programmers are worse at symbolic comprehension and manipulation than troglodytes.

         Thus secondly: in context, it is principally impossible to misunderstand the code where that operator is used.

         Third, if you can move bits to the left then why can't you move less atomic components to the left? Again there's no semiotic contradiction in using that operator, rather the opposite.

         Four, provide a more suitable operator to overload. Five: overloading the operator facilitates, for instance, stream handling (as in your example) on a language-external (library) level that is incredibly more flexible and aesthetic than a method-only counterpart in a operator overloading-less language.



  • You should overload an operator
     * A when it makes complete sense, to say, have one object less than another
     * You must (e.g. to use an object in an STL container that sorts, like std::set)

    Just overloading an operator to be slick or cool is going to end up causing some confusion



  • So why is method overloading less evil than operator overloading? The only bid we've had so far is "because there are only a few operators to overload".



  • Operator overloading is evil. Nobody likes readable vector math terms. People like javax.vecmath.* and 20 lines of all these explicitly constructed temporaries instead of one-liners.



  • @Mikademus said:

    So why is method overloading less evil than
    operator overloading? The only bid we've had so far is "because there
    are only a few operators to overload".




    Obviously, it's not. After all, on a semantic level, methods and
    operators are the same thing. Unlike Java, C++ acknowledges that. With
    an interesting side-effect: the string class doesn't have to be built
    into the compiler in order to provide a concatenation operator. In
    other words, C++ doesn't need special cases. Talk about elegance...



  • Due to the lack of replies I think the point has been made. Operator overloading isn't evil because that would principally make all method overloading just as evil. And since no-one seems to want to claim that method overloading is bad practice then it is impossible to in good faith or of a logical mind claim that operator overloading on the other hand would be.

    As I've always understood it, and remember that I code in Java too, the argument that "overloading operators lead to subtle bugs, intransparent and unmaintanable code and more difficult compiler design" etc was just marketing speak (each point can easily be refuted) that took root and got a life of its own, and that a lot of zealot exclusivists have internalised as Unquestionable Truth and chant as a mantra.

    After all, the alledged bugs from overloading operators are from my 13+ years experience as a C++ developer are a chimera: illusive, never really found in real code. And one of the things I miss when I code Java is being able to overload operators. Not being able to do this is a shortcoming of the language that pre-empts some elegant solutions.



  • @Mikademus said:

    @ammoq:
    So, you're saying that since there are only a finite number of operators in C++ then someone must abuse them? Then, say, Perl would be a better language for overloading operators?

    APL is the best ;-)

    We have discussed operator overloading in other threads, and I remember you have used the "<<" operator example there too. I said then that there's nothing wrong with using the operator that way.

       First, the pictographical meaning of the operator is very clear: movement to the left. The meaning is evident in the very image of the operator in a way that is remenescent of pictoral usage dating back to neolithic art, and I refuse modern programmers are worse at symbolic comprehension and manipulation than troglodytes.

    IMO, the pictographical meaning of
    "hello world" >> cout 
    is even better but for some reasons, it doesn't work. (in our culture, moving something to the right means "moving it forward" and moving something to the left means "moving it back", just look at your browser icons).


      Four, provide a more suitable operator to overload.

    If I did, it would invalidate my point of not having enough operators ;-)

    Five: overloading the operator facilitates, for instance, stream handling (as in your example) on a language-external (library) level that is incredibly more flexible and aesthetic than a method-only counterpart in a operator overloading-less language.

    Methods with variable arguments (and auto-boxing) provide a means for equally aesthetic code.
    Instead of
    cout << w << t << f
    it could be
    cout.out(w,t,f);



  • @ammoQ said:


    Methods with variable arguments (and auto-boxing) provide a means for equally aesthetic code.
    Instead of
    cout << w << t << f
    it could be
    cout.out(w,t,f);


    This I accept as another way of accomplishing approximately the same thing. Given, of course, that the variable arguments could contain stream manipulators, like
    io.out( foo, io::dec(2), bar, io::hex, baz, io::ends );

    Still, I don't think that contains the same sense of sequenciality as when linked by operators, and thus not being as elegant or transparent. Also, why would anyone cry "Wolf!" less for variable arguments than for operator overloading? VAs would be "evil" the same way as operator and method overloading.



  • @Mikademus said:



    This I accept as another way of
    accomplishing approximately the same thing. Given, of course, that the
    variable arguments could contain stream manipulators, like
    io.out( foo, io::dec(2), bar, io::hex, baz, io::ends );

    Why not? Stream manipulators are just objects, like everything else. Java5 style:

    public class io {
        static final Object hex=new Object();
        static final Object ends=new Object();
        private class decMan {
           public int n;
           public decMan(int n) {
              this.n = n;
           }
        }
        static void out(Object... args) {
           for (Object o:args) {
              if (o instanceof decMod) {
                 // process dec manipulator
              }
              else if (o == hex) {
                 // process hex manipulator
              }
              else if (o == ends) {
                 // process ends manipulator
              }
              else {
                 output(o.toString());
              }
           }
        }      
        public static Object dec(int n) {
           return new decMan(n);
        }
    }

    Still, I don't think that contains the same sense of sequenciality as when linked by operators, and thus not being as elegant or transparent. Also, why would anyone cry "Wolf!" less for variable arguments than for operator overloading? VAs would be "evil" the same way as operator and method overloading.



    I disaggree. At least, "io.out(a,b,c)" makes clear that io.out does something with a, b and c;
    the c++ notion of "cout<<a<<b<<c" might lead to the wrong assumption that some kind of interaction of b and c takes place.


  • @Mikademus said:

    Due to the lack of replies I think the point has been made. Operator overloading isn't evil because that would principally make all method overloading just as evil. And since no-one seems to want to claim that method overloading is bad practice then it is impossible to in good faith or of a logical mind claim that operator overloading on the other hand would be.

    As I've always understood it, and remember that I code in Java too, the argument that "overloading operators lead to subtle bugs, intransparent and unmaintanable code and more difficult compiler design" etc was just marketing speak (each point can easily be refuted) that took root and got a life of its own, and that a lot of zealot exclusivists have internalised as Unquestionable Truth and chant as a mantra.

    After all, the alledged bugs from overloading operators are from my 13+ years experience as a C++ developer are a chimera: illusive, never really found in real code. And one of the things I miss when I code Java is being able to overload operators. Not being able to do this is a shortcoming of the language that pre-empts some elegant solutions.


    The biggest reason why I am not a fan of operator overloading is that for most languages we have ever used in our programming careers, an operator is a fixed part of a language's syntax.   It's something the eye is trained to almost "overlook" when examining code; we kind of subconciously evaluate a + or - operator when reading code. We are used to it being considered a core part of a language, like the semi-colon at the end of each line in C or the curly brackets we use.   It's almost like how we only subconciously processing the punctuation in a sentence while obviously spending more times examining and considering the words themselves.  (or even the way we process words like "the" and "a" in a sentence as well)

    Conversely, a class method is never considered a core part of the programming language -- it is a part of the class library you are using.  It is our job to take the time to understand the classes we are using, and all of our programming lives we have learned that one classes implementation of isValid() is certainly going to be differnet form anothers.  It's something that we need to consciously think about when reading code.  We almost never think "what does + do?" but we certainly more often think "was does GetData() do?". 

    That's not to say that me or anyone else using C++ or C# or whatever isn't aware that you can overload operators, it's just that it's not always intuitive to examine code taking that into consideration. 

    I hope I was able to explain that, it was a little tough to put into words ....



  • @Jeff S said:

    @Mikademus said:
    Due to the lack of replies I think the point has been made. Operator overloading isn't evil because that would principally make all method overloading just as evil. And since no-one seems to want to claim that method overloading is bad practice then it is impossible to in good faith or of a logical mind claim that operator overloading on the other hand would be.

    As I've always understood it, and remember that I code in Java too, the argument that "overloading operators lead to subtle bugs, intransparent and unmaintanable code and more difficult compiler design" etc was just marketing speak (each point can easily be refuted) that took root and got a life of its own, and that a lot of zealot exclusivists have internalised as Unquestionable Truth and chant as a mantra.

    After all, the alledged bugs from overloading operators are from my 13+ years experience as a C++ developer are a chimera: illusive, never really found in real code. And one of the things I miss when I code Java is being able to overload operators. Not being able to do this is a shortcoming of the language that pre-empts some elegant solutions.


    The biggest reason why I am not a fan of operator overloading is that for most languages we have ever used in our programming careers, an operator is a fixed part of a language's syntax.   It's something the eye is trained to almost "overlook" when examining code; we kind of subconciously evaluate a + or - operator when reading code. We are used to it being considered a core part of a language, like the semi-colon at the end of each line in C or the curly brackets we use.   It's almost like how we only subconciously processing the punctuation in a sentence while obviously spending more times examining and considering the words themselves.  (or even the way we process words like "the" and "a" in a sentence as well)

    Conversely, a class method is never considered a core part of the programming language -- it is a part of the class library you are using.  It is our job to take the time to understand the classes we are using, and all of our programming lives we have learned that one classes implementation of isValid() is certainly going to be differnet form anothers.  It's something that we need to consciously think about when reading code.  We almost never think "what does + do?" but we certainly more often think "was does GetData() do?". 

    That's not to say that me or anyone else using C++ or C# or whatever isn't aware that you can overload operators, it's just that it's not always intuitive to examine code taking that into consideration. 

    I hope I was able to explain that, it was a little tough to put into words ....

    I don't think I agree with you, Jeff.

    Operators are no more a "fixed" part of languages than are the flow control keywords; they change from language to language and from version to version. When reading code, one has to glean semiotic meaning from all the elements, operators included.

    In C#, the meaning of the compound assiginment operator, +=, changes depending on its operands:

    <font style="font-family: Courier New;" size="1">// integer increment
    int x = 0;
    x += 1;</font>

    // event hander wiring
    Foo f = new Foo();
    f.EventRaiser += new Foo.EventHandler(f_EventRaiser);

    The second use is a lot different than the first, but it's not hard to understand.

    Consider another overload for += :

    <font style="font-family: Courier New;" size="1">        static void Main(string[] args)
            {
                Account account = new Account();
                account.Balance = 10M;

                Display(account);

                account.Post(new Transaction(5M, true));
                Display(account);

                Transaction transaction = new Transaction(5M);
                account += transaction;

                Display(account);
            }

            static void f_Raiser()
            {
                throw new Exception("The method or operation is not implemented.");
            }

            private static void Display(Account a)
            {
                Console.WriteLine(String.Format("Balance is {0}", a.Balance));
                Console.ReadLine();
            }
        }

        public class Account
        {
            public decimal Balance;

            public static Account operator + (Account a, Transaction t)
            {
                a.Post(t);
                return a;
            }

            public decimal Post(Transaction transaction)
            {
                if (transaction.IsCredit)
                    Balance += transaction.Amount;
                else
                    Balance -= transaction.Amount;

                return Balance;
            }
        }

        public class Transaction
        {
            public Transaction(decimal amount)
                : this(amount, false)
            { }

            public Transaction(decimal amount, bool isCredit)
            {
                this.Amount = amount;
                this.IsCredit = isCredit;
            }

            public decimal Amount;
            public bool IsCredit;
        }</font>

    I think that this is more intuitive than the event/delegate example. I certainly wouldn't consider it evil.



  • When you say that you disagree, I am not sure what are you disagreeing to ... from your response, it seems like you may have missed my points (or most likely I did not make it clear enough). 

    >>Operators are no more a "fixed" part of
    languages than are the flow control keywords; they change from language
    to language and from version to version. When reading code, one has to
    glean semiotic meaning from all the elements, operators included.

    I never said that operators are the same for ALL languages.  As for the meaning of operators changing from version to version of a particular language, I can't think of too many instances where this has happened (unless you consider, for example, C and C++ and C# all the same languages, just different versions ... I definitely don't)  Even if we can dig up one or two instances (out of a combination of every langauge and every operator out there) I think it will be a very small percentage -- thus, further making my point about what we are used to dealing with in terms of the definitions of the symbols in the languages we are using.

    The fact that an operator might have two meanings or usuages in particular language is irrelevant to what I was saying. (or trying to say, anyway).

    I also never said that we don't have to read operators or interpret what they mean or what they are doing or that we can ignore or skip them.

    And, finally, I never said operator overloading was "evil".



  • @ammoQ said:

    Why not? Stream manipulators are just objects, like everything else. Java5 style:

    [...]
        static void out(Object... args) {
           for (Object o:args) {
              if (o instanceof decMod) {
                 // process dec manipulator
              }
              else if (o == hex) {
                 // process hex manipulator
              }
              else if (o == ends) {
                 // process ends manipulator
              }
              else {
                 output(o.toString());
              }
           }
        }      


    Now that is some very fine OO programming. I'm impressed.

    By the way, you could very well make implement the cout.out( blah, blah, blah ) syntax in C++, by overloading the comma operator. Why even have a out method, anyway ? It's redundant. You could make cout a callable object and just write cout( blah, blah, blah ).

    Again, it leads to the fact that operator overloading do allow some interesting and meaningful extensions of the language semantics... But again, only if used in a sensible way.
    I still prefer a language that don't hold back features on the ground that idiots would misuse them.
    <c" might="" lead="" to="" the="" wrong="" assumption="" that="" some="" kind="" interaction="" of="" b="" and="" c="" takes="" place=""></c">


  • @Jeff S said:

    When you say that you disagree, I am not sure what are you disagreeing to ... from your response, it seems like you may have missed my points (or most likely I did not make it clear enough). 

    >>Operators are no more a "fixed" part of
    languages than are the flow control keywords; they change from language
    to language and from version to version. When reading code, one has to
    glean semiotic meaning from all the elements, operators included.

    I never said that operators are the same for ALL languages.  As for the meaning of operators changing from version to version of a particular language, I can't think of too many instances where this has happened (unless you consider, for example, C and C++ and C# all the same languages, just different versions ... I definitely don't)  Even if we can dig up one or two instances (out of a combination of every langauge and every operator out there) I think it will be a very small percentage -- thus, further making my point about what we are used to dealing with in terms of the definitions of the symbols in the languages we are using.

    The fact that an operator might have two meanings or usuages in particular language is irrelevant to what I was saying. (or trying to say, anyway).

    I also never said that we don't have to read operators or interpret what they mean or what they are doing or that we can ignore or skip them.

    And, finally, I never said operator overloading was "evil".


    Jesus, it's just exhausting dealing with you. Forget it.



  • I think there are times where operator overloading is actually less evil than using methods for the same purpose. Suppose you have a class representing a complex number. Do you suppose the method complex.Add(otherComplex) modifies the value of complex, or does it add the two together and return a third value? Or does it do both? Can you think of a nice, concise naming scheme which intuitively differentiates + from +=? OTOH, if we just overload the arithmetic operators it's pretty damned obvious what they're gonna do, since they're being used for arithmetic operations.

    I'm definitely in the pro-overloading camp.

    It seems to me that everyone here will agree that there are certain situations where operator overloading is a good thing. No-one so much as blinks when they see + used for string concatenation. As long as it's only used rarely, where appropriate and where the meaning is obvious, it's not going to cause problems.

    Well? Operator overloading is used sparingly and intuitively. You can talk all you want about potential pitfalls, but I think you'll find that if you take a random sample of code from a random sample of industry-level programmers, you'll find that overloading is barely ever used, and where it is, you'll know what's going on. Particularly in C++, the syntax for implementing an operator overload tends to keep idiots at bay.

    One thing that does bother me is operator overloading for vector classes (vector as in coordinates). People implement + and - without problems, but invariably decide to implement * as either cross or dot product. Bad move. IMO, * should only be implemented for scalar multiplication, since "multiplying" two vectors has no obvious meaning.



  • @Zlodo said:

    @ammoQ said:

    Why not? Stream manipulators are just objects, like everything else. Java5 style:

    [...]
        static void out(Object... args) {
           for (Object o:args) {
              if (o instanceof decMod) {
                 // process dec manipulator
              }
              else if (o == hex) {
                 // process hex manipulator
              }
              else if (o == ends) {
                 // process ends manipulator
              }
              else {
                 output(o.toString());
              }
           }
        }      


    Now that is some very fine OO programming. I'm impressed.


    It's not meant as a masterpiece of elegance, more like a proof-of-concept.


    By the way, you could very well make implement the cout.out( blah, blah, blah ) syntax in C++, by overloading the comma operator. Why even have a out method, anyway ? It's redundant. You could make cout a callable object and just write cout( blah, blah, blah ).


    Back to "good old" BASIC:
    10 print bla, blah, blabla


Log in to reply