• TopTension (unregistered)

    Can I assume that the * characters in the loop line were not there in the original code. It doesn't make sense this way.

  • (cs)

    Ah yes, ban all features that can be abused. I hope they outlawed pointers, multiple inheritance, operator new and templates too. Maybe they should just switch to Java if their programmers aren't competent enough to handle C++.

  • (cs)
    // Returns the same thing as getNextNode() CFNode* operator+(const int rhs);

    getNextNode() doesn't take any parameters, so what does CFNode + 2 do? I'd assume it does CFNode.getNextNode().getNextNode(), but wouldn't be surprised if it did the same thing as CFNode + 1

  • First (unregistered) in reply to TopTension
    TopTension:
    Can I assume that the * characters in the loop line were not there in the original code. It doesn't make sense this way.

    Unfortunately it makes perfect sense.

    for (CFNode* nptr = *firstPtr + 1; *nptr + 1; nptr = *nptr + 1)

    First * denotes a pointer to CFNode. All remaining *'s dereference the pointer and run the overloaded operation, which returns a pointer.

  • Asd (unregistered)

    I don't have a clue what is going on :( It has been too long since I did C++.

    I was going to say I hope Sun ignores the people asking for operator overloading in Java, but, without pointers, if it is restricted to the numeric operators it could be ok (no == overloading etc.).

  • Someone (unregistered) in reply to vt_mruhlin
    vt_mruhlin:
    I'd assume it does CFNode.getNextNode().getNextNode(), but wouldn't be surprised if it did the same thing as CFNode + 1
    Even if it did handle positive vaules other than 1 correctly, what would happen on negative values? ;)
  • TopTension (unregistered)

    All remaining *'s dereference the pointer and run the overloaded operation, which returns a pointer.

    Ah yes, of course. Thanks ! Makes it even worse....

  • anon (unregistered) in reply to Someone
    Someone:
    vt_mruhlin:
    I'd assume it does CFNode.getNextNode().getNextNode(), but wouldn't be surprised if it did the same thing as CFNode + 1
    Even if it did handle positive vaules other than 1 correctly, what would happen on negative values? ;)

    This overloading is a case of a smart person being overly "clever". Hence they probably thought of that scenario and it would return getPrevNode()

  • (cs) in reply to Someone

    Well there is a getPrevNode(), for negative values.

    I'm not sure the poster's logic "Knowing that almost every pointer value plus 1 will result in a non-NULL pointer" makes sense. Since it's a pointer to a class, you don't automatically know WHAT the pointer value plus 1 will equal. The correct objection is that CFNode + integer = pointer, which is not the way arithmetic operation usually work.

  • Hob (unregistered) in reply to First

    I think that WTF is not that someone overloaded operator+ for CFNode and int. It still sematically makes some sense to recceive 'n-th neighbour of current node'. The WTF is that s/he made operator+(CFNode, int) return pointer to CFNode, or made CFNode class implicitly convertable to bool.

  • (cs)

    In one of my CS classes a few years back, we were taught that this was the standard method of handling iterators.

    Of course, I haven't programmed in C++ since then, but still;

  • anon (unregistered)

    it's been forever since i've done c++ so if there are small syntax typos forgive me :-) my guess is the function is defined:

        CFNode* operator+(const int rhs) {
               CFNode* result = &this;
               for (int i = rhs ; i > 0 && result != null; i--) {
                     result = result->getNextNode();
               }
               for (int i = rhs ; i < 0 && result != null; i++) {
                     result = result->getPrevNode();
               }
               return result;
        }
    
  • (cs) in reply to MajinBlayze
    MajinBlayze:
    In one of my CS classes a few years back, we were taught that this was the standard method of handling iterators.

    Of course, I haven't programmed in C++ since then, but still;

    Ah, I see, he's using ptr + 1 in the test case part of the for loop; and returning a pointer to the object instead of the object itself. This is very different from a *standard* iterator WTF
  • (cs)

    Overloading operators is fine, as long as the overloaded operators have the same semantics as the default operator, or some other clear meaning (like operator+ for string concatenation). Here this clearly is not the case - adding an int to a CFNode makes no sense, especially since the value of the int is ignored, and it does not even return a CFNode, but a pointer to one shudder. And I can't help but wonder, why isn't one of the standard STL containers used for something that is clearly some form of linked list?

    I'd say the coding standard should be: Be prudent with operator overloading, yes, but don't ban it completely - it has its place. And use STL wherever possible.

  • anon (unregistered) in reply to anon
    anon:
    it's been forever since i've done c++ so if there are small syntax typos forgive me :-) my guess is the function is defined:
        CFNode* operator+(const int rhs) {
               CFNode* result = &this;
               for (int i = rhs ; i > 0 && result != null; i--) {
                     result = result->getNextNode();
               }
               for (int i = rhs ; i < 0 && result != null; i++) {
                     result = result->getPrevNode();
               }
               return result;
        }
    

    oops, "this" is already a pointer in c++ (as opposed to java), hence change "&this" to simply "this"

  • nco (unregistered)

    They'd better ban (naked) pointers, not a language feature.

  • Shinobu (unregistered)

    The first thing I thought was "No! They should've overloaded the increment operator! That makes much more sense, because then you can iterate through a list of nodes like you can through an array." I haven't worked that much with C++ (although I master it rather well) because in other languages things get done faster, but even that limited exposure has apparently infected me with the disease.

  • (cs) in reply to Shinobu
    Shinobu:
    The first thing I thought was "No! They should've overloaded the increment operator!
    I would still expect the ++ operator to return a reference to CFNode, not a pointer. That really is the biggest offense here - other than re-inventing the linked list, of course.
  • nco (unregistered) in reply to Beowulff
    Beowulff:
    That really is the biggest offense here - other than re-inventing the linked list, of course.

    the standard what? Yeah, all this would never have happen. At least he did not inherit from a std::vector though...

  • (cs) in reply to ciaranm
    ciaranm:
    Ah yes, ban all features that can be abused. I hope they outlawed pointers, multiple inheritance, operator new and templates too. Maybe they should just switch to Java if their programmers aren't competent enough to handle C++.
    Probably they should. Hard as it may be to fathom, some people want to write software that works, with a team of invariably mixed skill levels, and place a shockingly low priority on enabling people to bask in their own leetness.
  • (cs) in reply to Beowulff
    Beowulff:
    Overloading operators is fine, as long as the overloaded operators have the same semantics as the default operator, or some other clear meaning (like operator+ for string concatenation). Here this clearly is not the case -
    The problem is that for too many people "clear meaning" == "obvious" == "what I understand right now because I just came up with it".

    Really, operator overloading is so rarely useful and so often harmful that banning it entirely is a sensible idea.

  • oleg (unregistered)

    Its easy to understand the danger in operator overloading... but for the c++ impaired among us can someone please explain exactly WTF is going on here?

  • SomeCoder (unregistered) in reply to brazzy
    brazzy:
    Beowulff:
    Overloading operators is fine, as long as the overloaded operators have the same semantics as the default operator, or some other clear meaning (like operator+ for string concatenation). Here this clearly is not the case -
    The problem is that for too many people "clear meaning" == "obvious" == "what I understand right now because I just came up with it".

    Really, operator overloading is so rarely useful and so often harmful that banning it entirely is a sensible idea.

    We should ban cars too. Too many people are in car accidents. And fatty food. And alcohol. And tobacco. And airplanes. And sugar. And....

    While operator overloading is often misused, that's the power of C++. You can do pretty much whatever you need to and don't have to worry about limitations of the language. That said, you can also easily blow your entire leg off with it but just because something has the potential to be dangerous doesn't mean it should be banned outright.

    Perhaps in this particular case at this company, operator overloading should have been banned but that's definitely a case by case basis.

  • myname (unregistered) in reply to Asd
    Asd:
    I was going to say I hope Sun ignores the people asking for operator overloading in Java, but, without pointers, if it is restricted to the numeric operators it could be ok (no == overloading etc.).
    "Yeah, Java" + " doesn't do any " + "operator" + " overloading, " + "right?"

    It's sort of like Java's half-assed approach to multiple inheritance. There is no multiple inheritance in Java - except through interfaces.

    Let me guess, you're in the group that thinks that Java not including unsigned variables is a good thing?

    This example of operator overloading is a WTF, but there are plenty of instances where it can make code more readable and does make sense. String comparison and concatenation is one of the classic examples - very infrequently do you want to know if two strings use the same reference, and if you ever do, you can just cast them to (void*) to check anyway.

  • (cs) in reply to Asd

    If you want operator overloading in Java use Groovy as it has a lot of other syntax sugar you would probably want also.

  • (cs) in reply to Beowulff
    Beowulff:
    Shinobu:
    The first thing I thought was "No! They should've overloaded the increment operator!
    I would still expect the ++ operator to return a reference to CFNode, not a pointer. That really is the biggest offense here - other than re-inventing the linked list, of course.
    Yes and no. (Mostly yes.)

    Let's ignore the red herring of the overloaded operator (which is actually operator+(), but I know what you mean) for a moment, shall we? After all, it's just syntactic sugar -- or in this case, syntactic cyanide.

    Replace that with the (supposedly) equivalent member function, and you have:

    bool fixNodes(State &s)
    {
        CFNode *firstPtr = s.getFirstNode();
        bool done = false;
     
        while(!done)     
        {
               for (CFNode* nptr = firstPtr->getNextNode(); 
                            nptr->getNextNode();
                            nptr = nptr->getNextNode())
               {
                // Some code ...
               } 
            // ... more code
        }
    }
    

    ... at least, I think you do. Even trying to rationalise this makes my head hurt.

    ... and I had to rewrite the rest of this comment, based upon substituting the member function.

    How the hell is a maintenance programmer supposed to guess what's going on here?

    This code is still bizarre. Why check that the next node is "false" (one has to hope that the end of the list is specified as NULL) and then go ahead and assign it to nptr anyway?

    I don't see pointer arithmetic on a NULL anywhere here (perhaps I'm short on caffeine), but why not use the STL? Or at least iterators? Or possibly a good, old-fashioned for-loop in C that makes sense?

    The guy who wrote this should be taken out back and forcibly re-educated, with a pointy stick. The fact that it misuses features of the C++ language is entirely besides the point.

    The while-loop just adds to the insanity.

  • snoofle (unregistered) in reply to Beowulff

    As a former C++ coder, I tended to judiciously use operator overloading where it made sense. Unfortunately, I inherited an 800K+ LOC mess, where the authors believed that you should use every conceivable feature of C++, whether it made sense or not. After much debugging and banging of head on desk, I discovered the following in a deeply nested hierarchy:

    overload >> to write to database and return what was written overload << to read from database overload > to write to stream overload < to read from stream overload [] to read the nth record from a stream/result-set overload ++ to implicitly create a new version of the transaction in the db (version=version+1)

    The << was particularly annoying as innocent calls to cout would start hitting the db and loading the stored version of the object instead of the one you were trying to print - it drove me nuts trying to figure out why the variable I had just set seemed to still have the old value from the db - the debugger showed the correct value but cout showed the old value (from the db).

    The guy who wrote it had moved on to another team - I hunted him down and publicly ripped him a new one.

    For the record, to make it easier to understand what the thing was doing I replaced all the overloaded operations with descriptively named functions. At least new team members could follow what it was doing.

  • (cs) in reply to brazzy
    brazzy:
    Beowulff:
    Overloading operators is fine, as long as the overloaded operators have the same semantics as the default operator, or some other clear meaning (like operator+ for string concatenation). Here this clearly is not the case -
    The problem is that for too many people "clear meaning" == "obvious" == "what I understand right now because I just came up with it".

    Really, operator overloading is so rarely useful and so often harmful that banning it entirely is a sensible idea.

    I take it you've never wanted to multiply matrices before. Operator overloading turns that hell into something wonderful.

  • Zygo (unregistered)

    Banning operator overloading is stupid. C++ is limited enough as it is, without intentionally ignoring its feeble attempts try to act like a real programming language.

    That said, I probably would require that coder in future to go through code reviews on all their submissions with someone who knows their head from their ass (or at least their arithmetic types from their pointer types).

    Another commenter suggested allowing only arithmetic operator overloading, not boolean or other operators. This is stupid as well. You need to overload pointer and equality operators to design classes that can replace standard pointer types. You need inequality operators to implement sorting or ordered containers. You need to overload function operators to use templates or generics. You need to overload bitwise-boolean operators to implement set union/difference/intersection operations. You need to overload type conversion operators for, well, type conversions. And so on...

    About the only operator that you never need to overload is the comma (",") operator.

  • Grant (unregistered) in reply to Welbog

    So multiplying matrices would be one of those "rarely useful" instances where you would use it.

    You people really do have an unhealthy love affair with your language features don't you?

  • Zygo (unregistered) in reply to snoofle
    snoofle:
    Unfortunately, I inherited an 800K+ LOC mess, ...

    overload >> to write to database and return what was written overload << to read from database overload > to write to stream overload < to read from stream overload [] to read the nth record from a stream/result-set overload ++ to implicitly create a new version of the transaction in the db (version=version+1)

    The << was particularly annoying as innocent calls to cout would start hitting the db and loading the stored version of the object instead of the one you were trying to print - it drove me nuts trying to figure out why the variable I had just set seemed to still have the old value from the db - the debugger showed the correct value but cout showed the old value (from the db).

    Part of me sympathizes with your pain. Really.

    Another part of me wonders...

    how the hell did he managed to arrange things so that "std::ostream &operator<<(std::ostream &, const T &)" gets replaced with "T operator<<(std::ostream &, DB &)" without a whole pile of ambiguous function call errors?

  • TexDex (unregistered)

    When I was first learning Java and just beginning to understand the concept of OOP I hit on a great idea to demonstrate objects by making a "measurement" class. The way I planned it, you would be able to convert from one unit type to another, and multiply those units so they would follow logical rules. For example: If I added two Length objects I'd get another length object; if I multiplied two Length objects together it would return an Area object; if you divided a Length unit by a Time unit you would get a Speed object.

    So the code would look like this: maxHeight = myHeight + hatHeight cubeVol = h * w * d

    This would be a perfect and perfectly logical use of operator overloading, particularly useful for use in, say, physics simulations (not that I had any illusions about this being used in any real context but that was the general idea). I was pretty disappointed when I found that you couldn't actually make it look like that, and instead had to use awkward methods like .plus(x). I maintain that operator overloading, if used properly, adds to the readability of the code, and I've always been annoyed that Java didn't support it.

  • (cs) in reply to Welbog
    Welbog:
    I take it you've never wanted to multiply matrices before. Operator overloading turns that hell into something wonderful.
    Actually, no, I haven't had to work with matrices anytime recent. If I had to, I don't see what's so hellish about using methods.

    Whenever there is a discussion about the merits and problems of operator overloading, its fans always come up with the same two examples: matrices and complex numbers. Do we really need a highly abusable language feature for the sake of two specific applications? The vast majority of software is not very math-intensive at all. Sure, if you do work on a math-intensive app, then anything that lets you code as close to the mathematical notation as possible looks like a gift from heaven, but even that is an illusion because all except the most trivial math needs far more symbols than there are appropriate operators in ASCII.

  • AJS (unregistered)

    A particularly egregious example of operator overloading is in JavaScript, where the + operator serves for both numeric addition and string concatenation. While that is bordering on acceptable in a statically-typed language (such as BASIC, which is where I believe the practice originated), JavaScript is dynamically-typed. In other words, variables can be interpreted as numeric or string depending on context.

    So you can get something like document.theform.users.value += 1 concatenating a figure "1" to the end of the text field, rather than incrementing the value.

    I normally rewrite all additions in JavaScript as subtractions; it has no problem with document.theform.users.value -= -1 though it looks a bit strange at first glance.

    Perl (the original dynamically-typed language) and its crazy bastard son PHP had the common sense to use a separate operator (the dot) for concatenation (although since all Perl and PHP variables begin with a $ sign and variables whose names are mentioned inside "double speech marks" get replaced with their values, this is redundant: one may write $name = $title . " " . $initial . " " . $surname as $name = "$title $initial $surname" with no ill effect).

  • (cs) in reply to Zygo
    Zygo:
    Banning operator overloading is stupid. C++ is limited enough as it is, without intentionally ignoring its feeble attempts try to act like a real programming language.

    OK, I'll bite: what is, in your opinion, a "real programming language"?

  • eh (unregistered) in reply to Welbog

    Banning a language feature because of a bad judgement call by a programmer ... especially something as basic and useful as operator overloading ... thats just absolutely, positively insane.

    Mathematical operations on UDTs (matrices, quats, vectors, fixedpoint, complex), serialization, string operations, sort comparisons, equivalance-by-key, new/delete overloading for memory management...you want to return all of this (and so much more!) to C style function calls because someone, somewhere might overuse the language feature?

    Are you people serious?!

    I guess you should also throw out STL as well because in case you haven't heard it's actually requires operator overloading for many of it's most common containers.

  • (cs) in reply to Zygo
    Zygo:
    Banning operator overloading is stupid. C++ is limited enough as it is, without intentionally ignoring its feeble attempts try to act like a real programming language.

    That said, I probably would require that coder in future to go through code reviews on all their submissions with someone who knows their head from their ass (or at least their arithmetic types from their pointer types).

    Another commenter suggested allowing only arithmetic operator overloading, not boolean or other operators. This is stupid as well. You need to overload pointer and equality operators to design classes that can replace standard pointer types. You need inequality operators to implement sorting or ordered containers. You need to overload function operators to use templates or generics. You need to overload bitwise-boolean operators to implement set union/difference/intersection operations. You need to overload type conversion operators for, well, type conversions. And so on...

    About the only operator that you never need to overload is the comma (",") operator.

    As Albert Einstein would say, "All programming languages should be made as limited as possible, but not more limited." In what viscerally important way is C++ limited?

    (Actually, that neatly encapsulates my loathing of built-in "libraries" that people seem to think are actually part of their language these days, but no matter.)

    There are, in fact, several other operators that should never be overloaded -- the ternary operator springs to mind, not to mention operator *->() -- but again, we're drifting from the point here, people.

    This is rank, bloody awful code with or without operator overloading.

    And please, please, let's get away from this juvenile language-war thing.

    (Unless, of course, some kind soul wishes to "anonymize" the OP as VB6...)

  • Zygo (unregistered) in reply to Grant
    Grant:
    So multiplying matrices would be one of those "rarely useful" instances where you would use it.

    You people really do have an unhealthy love affair with your language features don't you?

    Overloaded operators are rarely useful. 99% of the time, they're more trouble than they're worth, and they're not something anyone with less than two years' experience developing C++ with other human beings should attempt outside of a controlled academic setting.

    The other 1% of the time, there's some problem domain that can be easily and readably solved by using a small set of functions, with particular relationships between their types, and the best possible names of those functions are +, -, *, &, <, >, !=, ...

    Since we're stuck with the names and semantics of +, -, etc (which are fairly sophisticated--there's dozens of pages in the C and C++ standards that define exactly what "+" does and does not do without mentioning operator overloading even once), it follows that if we're going to get anything done in this language then we need to be able to redefine the behavior of the operators for non-trivial data types. This is a requirement for C++ and not a requirement for C, because C doesn't have non-trivial data types.

    Arguably, C++ (and C, from which most C++ operators arise) has too many operators to start with. We wouldn't want to overload them if it weren't so much more convenient to use them on intrinsic types, or if the alternative function-call syntax wasn't so fugly and didn't have subtly different semantics.

    Compare C++ with LISP, which has only a half-dozen or so operators (and that's really stretching the meaning of the word "operator"), no operator overloading, and a lot more expressive power than C++. In LISP, you can redefine the meaning of an entire expression, not just the operators used within it.

  • (cs) in reply to AJS
    AJS:
    A particularly egregious example of operator overloading is in JavaScript, where the + operator serves for both numeric addition and string concatenation. While that is bordering on acceptable in a statically-typed language (such as BASIC, which is where I believe the practice originated), JavaScript is dynamically-typed. In other words, variables can be interpreted as numeric or string depending on context.

    So you can get something like document.theform.users.value += 1 concatenating a figure "1" to the end of the text field, rather than incrementing the value.

    I normally rewrite all additions in JavaScript as subtractions; it has no problem with document.theform.users.value -= -1 though it looks a bit strange at first glance.

    Perl (the original dynamically-typed language) and its crazy bastard son PHP had the common sense to use a separate operator (the dot) for concatenation (although since all Perl and PHP variables begin with a $ sign and variables whose names are mentioned inside "double speech marks" get replaced with their values, this is redundant: one may write $name = $title . " " . $initial . " " . $surname as $name = "$title $initial $surname" with no ill effect).

    Sigh. In Perl, and particularly in this case, TMTOWTDI...

  • Ubersoldat (unregistered) in reply to ciaranm
    ciaranm:
    Maybe they should just switch to Java if their programmers aren't competent enough to handle C++.

    You should duck... now!

  • visitor (unregistered)

    An overloaded operator is nothing but a function call that looks prettier. (You could imagine a language, where you don't have for example arithmetic operators, and have to use assign(n, add(x, y)) instead of n = x + y.)

    Operator overloading abuse is no different than misnaming functions, both are just as easy to happen.

    So, if someone would misname/misconstruct a function, you'd be happy to ban function usage? WTF!

  • mos (unregistered) in reply to ciaranm
    ciaranm:
    Ah yes, ban all features that can be abused. I hope they outlawed pointers, multiple inheritance, operator new and templates too. Maybe they should just switch to Java if their programmers aren't competent enough to handle C++.
    Actually, I interviewed with one company that was an all-C shop for almost that very reason. Someone had implemented a matrix class's operator+ incorrectly, and it took the lead programmer (not familiar with C++) a couple of days to track it down. He had been assuming A + B would "just work", and never bothered to check the addition function. He banned C++ after that. I thought it was a fairly heavy-handed way of dealing with your own failings. I mean, at least his junior programmer had been trying to do addition, I can't imagine what the WTF's implementer had been thinking.
  • Weezer (unregistered) in reply to Zygo
    Zygo:
    Overloaded operators are rarely useful.
    We have a domain difference here. I work with math all day long. I would go insane without operator overloading.

    Here's an experiment for you operator overloading haters - go back to one of your university math books and convert the largest equation you can find into prefix notation and then compare the readability to the original text.

    Now imagine the entire book was written that way.

  • Zygo (unregistered) in reply to brazzy
    brazzy:
    Welbog:
    I take it you've never wanted to multiply matrices before. Operator overloading turns that hell into something wonderful.
    Actually, no, I haven't had to work with matrices anytime recent. If I had to, I don't see what's so hellish about using methods.

    Actually, for matrix work I prefer to use overloaded functions. "Matrix add(const Matrix &M, const Vector &V)" can be overloaded with "Matrix add(const Matrix &M, const Matrix &M2)" and all the other supported combinations. To use it with some objects "V1" and "V2" you just write "Matrix M = add(V1, V2)" without caring what types V1 and V2 are.

    brazzy:
    Whenever there is a discussion about the merits and problems of operator overloading, its fans always come up with the same two examples: matrices and complex numbers.

    In C++, I find operator overloading for iterator types essential. Usually I'm replacing a pointer type with a class type without changing all the code that used the pointer type, and the sematics of pointer operations are both well-defined (so I always know what operator *() does) and limited (anything outside of what C++ pointer operators can already do isn't pointer semantics any more by definition).

    The other big use of operator overloading I use is for stream operations. This is really common for I/O tasks (such as streams, obviously) and for building data structures to be used by other languages where there is one and only one mapping from C++ datatypes to the other language (e.g. LISP and Tcl) and the data in question is mostly lists or trees of object values. It's not possible to do this with methods because in C++ you can't expand the set of methods on an object outside of the class declaration. Overloaded global functions are overly verbose and don't use infix notation, which severely hurts readability.

  • snoofle (unregistered) in reply to Zygo
    Zygo:
    snoofle:
    Unfortunately, I inherited an 800K+ LOC mess, ...

    overload >> to write to database and return what was written overload << to read from database overload > to write to stream overload < to read from stream overload [] to read the nth record from a stream/result-set overload ++ to implicitly create a new version of the transaction in the db (version=version+1)

    The << was particularly annoying as innocent calls to cout would start hitting the db and loading the stored version of the object instead of the one you were trying to print - it drove me nuts trying to figure out why the variable I had just set seemed to still have the old value from the db - the debugger showed the correct value but cout showed the old value (from the db).

    Part of me sympathizes with your pain. Really.

    Another part of me wonders...

    how the hell did he managed to arrange things so that "std::ostream &operator<<(std::ostream &, const T &)" gets replaced with "T operator<<(std::ostream &, DB &)" without a whole pile of ambiguous function call errors?

    I left out a whole bunch of other interesting constructs that were in place. Essentially, he had overloaded the db to look like a homemade ostream, and he had similarly overloaded cout/cerr. Throughout the app, the internal stream object was used in lieu of cout/cerr/db. Depending on the context, and what had been dynamically assigned, the app's variable for the internal stream that was used for cout could actually point to the db.

    I spent a lot of time refactoring / rewriting that mess.

  • Zygo (unregistered) in reply to real_aardvark
    real_aardvark:
    There are, in fact, several other operators that should never be overloaded -- the ternary operator springs to mind

    Don't worry about the ternary operator, you can't overload it (13.5.3 forbids overloading the operators . .* :: and ?:, and also mentions that # and ## are not really operators so you can't overload them either).

    real_aardvark:
    not to mention operator *->()

    Hmmm...that would permit smart pointer-to-member classes (analogous to smart pointer classes, but they choose a member function for you instead of an object). That opens up entire worlds of polymorphism...

  • Captcha Robot (unregistered) in reply to AJS
    AJS:
    Perl (the original dynamically-typed language) and its crazy bastard son PHP had the common sense to use a separate operator (the dot) for concatenation (although since all Perl and PHP variables begin with a $ sign and variables whose names are mentioned inside "double speech marks" get replaced with their values, this is redundant: one may write $name = $title . " " . $initial . " " . $surname as $name = "$title $initial $surname" with no ill effect).

    I'm not so sure about being the original (it could be) but it's certainly very good at it.

    Also, the . operator is not redundant. Take, for instance:

    sub wtf { return "worse than f.." }
    # Works:
    $badname = "The Daily " . wtf();
    # Doesn't work:
    $badname = "The Daily wtf()";
  • ali (unregistered)

    I don't think it's such a big WTF actually. He just made his structure follow the C idea of null-terminated arrays. IIRC, in C, adding a number to a pointer to something, adds numbersizeof(something) to the pointer, making something and something[] the same types.

    It is possible that "CFNode* operator+(const int rhs)" does the correct analogon of the pointer arithmetic. Or it contains

    assert(rhs==1); /* implement pointer arithmetic here if needed */

    I suggest to get a copy of K&R and look at the code examples in it. The code in the article looks to me like being perfectly in the spirit of K&R's strdup.

    If there is a WTF, then it's the hacker tricks proposed by the inventors of C. Or the WTF is that people who don't know the roots laugh at stuff they don't understand anymore. Granted, it's 35 years old, but that's not a crime.

    (I'd like to add some examples where operator overloading is nice, because I belong to those who write math-related code and think op overloading is the first thing we add to Java when the revolution comes: Game engines with specific gfx-card-friendly "3D vector" types. Critical financial systems where you don't want your $2^31 to become $-2^31. Computations with exact arithmetic. BigNumber packages.)

    p.s.: The must stupidest thing IMO is that Java thinks that "+" must exist for int and String, but not for Integer. My last Java experience is a few years old, so: Is it still so that the result of (new Integer(1))+(new Integer(1)) is legal code and results in the String "11"?

    p.p.s.: The real WTF is that the author thinks that NULL must be 0. Is not true.

    p^3.s: My first WTF post. Yay.

  • (cs) in reply to AJS
    AJS:
    A particularly egregious example of operator overloading is in JavaScript, where the + operator serves for both numeric addition and string concatenation. While that is bordering on acceptable in a statically-typed language (such as BASIC, which is where I believe the practice originated), JavaScript is dynamically-typed.
    Congratulation, you fail. Static or dynamic typing has no relation with the issue at hand, the problem with the auto-coercion between numeric and string types which javascript retardedly tries to perform (PHP is also very guilty of that one).

    As a matter of fact, this issue also exists with Java -- which was still a statically typed language last time I checked -- as the following:

    class AutoCoercion {
        public static void main(String[] args) {
            System.out.println("Do stuff " + 3 + 5);
        }
    }
    prints `Do stuff 35`, since expressions are evaluated left-to-right, `"Do stuff " + 3` is evaluated first, so `3` is converted to a string and appended, and only then is the second addition performed.

    But things become much funnier when you get the expression "Do stuff " + 3 * 5. No it doesn't blow up, it prints "Do stuff 15", probably because the precedence for the "*" operator is higher than the addition.

    Please note that the very example you used against javascript gives exactly the same result in Java: document.form.users.value is of type string, Java will convert the "1" to a string and append it, go ahead and test it.

    Therefore the first part of your statement ("+" for both concatenation and addition is ok for statically typed languages) is plain and simply wrong.

    Now let's look at the second one "but it's not ok for dynamically typed languages. Python is as dynamically typed as a language can be. Let's see how it behaves:

    # "+" works for the addition or ints
    >>> 3 + 5
    8
    # + works for the addition of floats
    >>> 3.5 + 2.4
    5.9000000000000004
    # + works for string concatenation
    >>> "foo" + "bar"
    'foobar'
    # + even works for lists (Java arraylists) concatenation
    >>> [1, 2, 3] + [4, 5, 6]
    [1, 2, 3, 4, 5, 6]
    # Let's try my example
    >>> "Do stuff " + 3 + 5
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: cannot concatenate 'str' and 'int' objects
    # Let's try yours
    >>> value = "3"
    >>> value + 1
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: cannot concatenate 'str' and 'int' objects
    >>> value += 1
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: cannot concatenate 'str' and 'int' objects
    >>>
    Cleary, Python has a perfectly sane behavior.

    The problem is not with using "+" for both number addition and string concatenation, the problem is with performing automatic coercion between strings and numbers when using the + operator.

  • Zygo (unregistered) in reply to brazzy
    brazzy:
    Zygo:
    Banning operator overloading is stupid. C++ is limited enough as it is, without intentionally ignoring its feeble attempts try to act like a real programming language.

    OK, I'll bite: what is, in your opinion, a "real programming language"?

    Real programming languages can generate, inspect, or modify existing code at runtime, including (within reason) the code of the language compiler and runtime library.

    The biggest clue that you have a real programming language is that you can 1) write a function body in the argument list of a function, and 2) generate a function body by combining data passed as arguments. C++ can do both of these things with templates, but template code generation is only at compile time (unless your C++ program has a compiler and debugger hidden in a library somewhere), and is highly restricted even then (thanks to ISO C++ section 14.7.3, it is not possible to extend the set of available template specializations available to the arguments of a member template after the member template has been declared or instantiated, no matter how damn useful that capability would be in practice).

    Another clue that you have a real programming language is that you can iterate over function bodies as you would any other data structures. C++ programs that can do this are called "debuggers" or "virtual machine emulators"--these capabilities are certainly not expected from standard C++ implementations. Real programming languages expect nothing less from their standard libraries.

    Another sign is that the language is very small--a complete syntax description for most real programming languages fits on a single page--and just about every language feature is implemented by library functions (although often library functions are themselves just code generators, so you get the same machine code at the end whether you used "x+y" or "add(x,y)").

    Templates and RTTI are about as far away from this kind of capability as Microsoft Word macros are from assembly-language programming.

    Once a problem domain reaches a critical level of complexity, the only solution available to a C++ developer is to implement a real language in C++, then implement the rest of the solution in the real language. Most people fail when they try to do this, they fall victim to Greenspun's Tenth Law, and their code ends up here.

Leave a comment on “Yet Another Operator Overloading Abuse”

Log In or post as a guest

Replying to comment #:

« Return to Article