• (cs) in reply to BitBabe
    BitBabe:
    Aren't macros unsafe as well due to the problems that can be caused due to incompatible types being passed?

    inline functions / templates and const's are the way to go!

    Besides, I was under the impression macros were deprecated in C++ anyhow...

    Their use is discouraged, but not officially deprecated. And their use is unsafe due to a lot more than types too. (Look in the next paragraph at the definition of MAX; thanks to the wonderful world of macros, all those parens are necessary. And it's still not the same as an inline function.)

    I would advocate that macros should almost never be used in either C++ or C99 code to create constants (#define PI 3.14) or functions (#define MAX(a,b) ((a)>(b)?(a):(b))), especially the latter.

    However, macros have other uses where you're not just making an inline function or constant, but using macros almost as new language features where there is no replacement. Here I feel that macros are quite respectable.

    Orion Adrian:
    And yes enums and consts are preferable, especially in a good compiler, but one of the beauties of #defines is they have no binary overhead. There's no type involved so they just kind of melt away post-preprocessor. They just become the number. Now in a good compiler where you haven't externed anything you'll end up with much the same result, but remember that you can change a const in C/C++ either with a C-style cast () in C/C++ or with a const_cast in C++.

    Not legally. "Unconsting" physically const objects (those declared as const double PI = 3.14 for example) produces undefined behavior.

    (Well, okay, this isn't exactly true. But if you declare PI as above then do ((int)&PI) = 5, that IS undefined. You have to change a physically const value. And mutable members complicate matters too.)

    jokeyxero:
    um.. !1 != 0 etc..

    technically... !0 == -1 !1 == -2 !2 == -3

    Hence why VB uses -1 as it's internal true value, though with most systems the conditional logic simply says that 0 is false and anything else is true.

    How do you get that?!

  • (cs) in reply to Orion Adrian
    Orion Adrian:

    Except now you've added three extra symbols to the global namespace (remember C) when you only needed one.

    Some questions I ask myself:

    When reading a line of code will another programmer understand what I'm talking about? e.g.

    if (Intersects()) return TRUE; if (Touches()) return MAYBE; if (DoesntTouch()) return FALSE;

    For future reference, say those lines are the body of IntersectP()

    there's a pretty good chance they'll know what I mean.

    Once explained briefly will another program have difficultly using it in the right context?

    Is it performant?

    Does it create extraneous symbols in the global namespace that might prevent other uses of that name?

    Is the scope appropriate (global, struct, class, local, file)?

    Does it break precident?

    MAYBE in this context passes most of these tests. What tests does maybe fail other than it's not the way it's done? As above breaking precident is an important consideration, but its not the only one.

    What's the return type of IntersectP?

    If you have a #define BOOL int (or typedef BOOL int), now someone sees 'BOOL IntersectP()' and won't even think to check for MAYBE. That's no good.

    You can say 'int IntersectP()', but now the return doesn't really tell you what you need, and it doesn't tell the compiler what it needs, and it doesn't tell Lint what it needs. (Incidentally, these are problems with the previous solution too.)

    Best is 'tristate IntersectP()'. It tells the programmer about all three options, it tells the compiler about all three options, it tells source analysis programs about all three options.

    Even ignoring precedent, I think the last solution is easily worth the extra namespace pollution.

  • James (unregistered)

    Can't believe 4 pages of comments and nobody has added

    #define ASK_AGAIN_LATER 999

  • Orion Adrian (unregistered) in reply to EvanED
    EvanED:
    Orion Adrian:

    Except now you've added three extra symbols to the global namespace (remember C) when you only needed one.

    Some questions I ask myself:

    When reading a line of code will another programmer understand what I'm talking about? e.g.

    if (Intersects()) return TRUE; if (Touches()) return MAYBE; if (DoesntTouch()) return FALSE;

    For future reference, say those lines are the body of IntersectP()

    there's a pretty good chance they'll know what I mean.

    Once explained briefly will another program have difficultly using it in the right context?

    Is it performant?

    Does it create extraneous symbols in the global namespace that might prevent other uses of that name?

    Is the scope appropriate (global, struct, class, local, file)?

    Does it break precident?

    MAYBE in this context passes most of these tests. What tests does maybe fail other than it's not the way it's done? As above breaking precident is an important consideration, but its not the only one.

    What's the return type of IntersectP?

    If you have a #define BOOL int (or typedef BOOL int), now someone sees 'BOOL IntersectP()' and won't even think to check for MAYBE. That's no good.

    You can say 'int IntersectP()', but now the return doesn't really tell you what you need, and it doesn't tell the compiler what it needs, and it doesn't tell Lint what it needs. (Incidentally, these are problems with the previous solution too.)

    Best is 'tristate IntersectP()'. It tells the programmer about all three options, it tells the compiler about all three options, it tells source analysis programs about all three options.

    Even ignoring precedent, I think the last solution is easily worth the extra namespace pollution.

    I never said using #define was ideal, but I'm simply trying to get across that I can imagine a situation, especially given the example domain where this would be a problem.

    Imagine the library described where TRUE and FALSE are already defined and used (with the possibility of typedef BOOL int).

    The problem with enums is that if you have a library that doesn't know about them you can't use them correctly (they don't upcast). You can use #defines without incident.

    So let's say in the external library TRUE and MAYBE do the same thing.

    From the external library:

    typedef int BOOL;

    #define TRUE 1 #define FALSE 0

    void g(void) { }

    BOOL f(BOOL a, float c, float d) { if (a) g(); return (TRUE); }

    From your library:

    enum mytype { MYFALSE = FALSE, MYTRUE = TRUE, MAYBE = 2 };

    mytype h(void) { return f(MAYBE, 0.2f, 0.4f); }

    Now this returns a compile time error because f() returns an int and you're returning something else. Now you're doing this all over the place:

    return (mytype) f(MAYBE, 0.2f, 0.4f);

    which is to say redundant. What you really wanted was something that could participate in a base/derived relationship, but these are enums and that's not how it works.

    I'm not saying this is ideal (for the forth or fifth time), but what I am saying is that perhaps the author was trying to avoid a lot of headaches and code writing.

    There's also the added pitfall that somewhere in the external library they have a call like

    if (a == TRUE)

    and then well you're screwed. Perhaps they tried it the #define MAYBE 2 way and it worked and they never went back. I've certainly got hacks in my code that could use a little love, but then maintainence programmers usually will tell you that if it works -- no touchy. Again all I'm asking for it for people to at least acknowledge that there are circumstances where a compitent, reasonable programmer might find himself or herself writing #define MAYBE 2.

  • (cs) in reply to Orion Adrian
    Orion Adrian:
    I never said using #define was ideal, but I'm simply trying to get across that I can imagine a situation, especially given the example domain where this would be a problem.

    [snip]

    There's also the added pitfall that somewhere in the external library they have a call like

    if (a == TRUE)

    and then well you're screwed. Perhaps they tried it the #define MAYBE 2 way and it worked and they never went back. I've certainly got hacks in my code that could use a little love, but then maintainence programmers usually will tell you that if it works -- no touchy. Again all I'm asking for it for people to at least acknowledge that there are circumstances where a compitent, reasonable programmer might find himself or herself writing #define MAYBE 2.

    I can't speak to the situation here as to how good of an idea it is. I would say that #define MAYBE 2 could be the least bad solution of a few, and that it also could be a "temporary", proof-of-concept hack made permanent.

    My earlier post was mostly doing two things; first, presenting another reason to use enum that I hadn't yet seen (though it's quite possible I missed), and saying that the increased type safety alone outweighs the namespace pollution issue IMO.

  • Jen Larkin (unregistered)

    It's simple. They are testing for true, false, and Schrodinger's Cat.

  • (cs)

    the greatest greatness of this piece of code is that if you ask:

    TRUE || MAYBE

    you get a TRUE answer, which is in fact, correct. And at the same time if you ask:

    FALSE || MAYBE

    you also get TRUE and that is correct too! brilliant.

  • Anonymous (unregistered) in reply to EvanED

    [quote user="EvanED"][quote user="merreborn's nemesis"]

    Then how do you get true and false in C code if you can't use C99? Or are you going to say that using C89 is always stupid?

    [/quote]

    #define TRUE (0==0) #define FALSE (!TRUE)

  • Anonymous (unregistered) in reply to Miauen
    Miauen:
    Oh this is nothing, at my previous job we had a situation where someone wrote, in Java: boolean test;

    [...]

    if( test == true ) { [...] } else if( test == false ) { [...] } else { [...] }

    (with code that is not important in the [...], but suffice it to say did something meaningful).

    Doesn't the Java compiler complain about unreachable code?

  • illiterate schovinist pig (unregistered)

    At first i thought the code is written by a female (men think true|false, black|white, buddy|sexmate , even if they don't admit it )

    But then i realized it couldn't have been ! For women would write it like this

    #ifdef FALSE #define TRUE = FALSE #endif

    #ifdef TRUE #define FALSE = TRUE #endif

    #ifdef FALSE && MEN #define MAYBE = FALSE #end

    #ifdef TRUE && MEN #define MAYBE = FALSE #end

    #ifdef FALSE && LOGIC #define MAYBE = TRUE #end

    Enjoy life as it is, we're all gonna die :D

  • (cs)

    What a hero...

    BTW: I hate programmers which write code like this:

    if (boolVarible == TRUE)
    if (TRUE == boolVariable)
    

    etc.

    But that's my personal view...

    if (boolVariable)

    is the ony and ONLY correct way to use booleans ;-)))

    Also there is no fuzzy logic in this MAYBE anti-pattern...

    It's simple stupid...

    #define SURE          100
    #define REALLY_TRUE   100000
    #define MAYBE_TRUE    1
    

    ;-))))

  • Mike J (unregistered)

    Very amusing. I remember working on some Merant code once that introduced a "Tri State Boolean" class. TRUE, FALSE, and 'CANT_TELL_YET'. Classy.

  • Syrion (unregistered) in reply to Moose

    Please, please... this is a WTF ! multi-value logic does'nt exists, it is fuzzy-logic. In fuzzy logic, MAYBE isn't 2, it is much more precise ! In fuzzy-logic (used in A.I., in washing machines or your elevator system), 0 is FALSE for sure, 1 is TRUE for sure, and all real values between 0 and 1 are probabilities. 0.95 is TRUE with a 95% probability, and is considered as TRUE with 5% error margin. The WTF is to assign 2 for "MAYBE", knowing there is an infinite count of "MAYBE" between TRUE and FALSE.

    According to fuzzy-logic, FILE_NOT_FOUND is -1 and BRILLIANT is 1.1. Or maybe not...

  • Rodger C. (unregistered)

    You should see HTML5's

Leave a comment on “Rarely Just TRUE or FALSE”

Log In or post as a guest

Replying to comment #:

« Return to Article