A classic; true, false, maybe



  • Got this today reviewing code from a developer on loan to me from another department. I left my comment in...
     

    public void testSupportsResultSetConcurrency4() throws SQLException {
    	boolean retValue = databaseMetaData.supportsResultSetConcurrency(
    		ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
    
    // FIXME Holy shit what the hell is this testing? assert true or 
    // false? What if the boolean wasn't true or false? -JFBP
    assertTrue(retValue || !retValue);
    

    }



  • That's so enterprisey!



  • Hah, that's funny. However, it looks like it's probably just a typo, or a debugging change gone unreturned. The assert was probably returning false and causing problems, so it was turned off for a minute or so.

    Still, great find.



  • http://brittens.org/public/WTFASP.asp

    This seems mildly relevant.
     



  • [quote user="db2"]

    http://brittens.org/public/WTFASP.asp

    This seems mildly relevant.
     

    [/quote]

    MySQL is like that too.

    1 = 1 returns 1

    1 = 0 returns 0 

    1 = null returns null 

    1 + 1 returns 2

    0 + 0 returns 0

    0 + null returns null 

    1 + null returns null

    1 < 0 returns 0

    1 > 0 returns 1

    null > 0 retuns null

     

    So basically, you're left with trinary logic. 



  • But a Java (I think it's java) bool isn't a trinary object so it'll get resolved to true or false anyways, right?

    The only logic behind the above that I can see is that someone was being lazy and wanted to make sure that the code never got called...
     



  • [quote user="Devi"]

    But a Java (I think it's java) bool isn't a trinary object so it'll get resolved to true or false anyways, right?

    The only logic behind the above that I can see is that someone was being lazy and wanted to make sure that the code never got called...
     

    [/quote]

     If I want to barf when something is called, I write something like:

     

     assert(!"The excrement has collided with the air circulation device");

     

    or, in languages other than C and C++ where people can't just cast strings to boolean,

     

    assert(!"The excrement...device".length());
     

    or syntactically appropriate (not to mention politically correct) variations thereof. 



  • [quote user="db2"]

    http://brittens.org/public/WTFASP.asp

    This seems mildly relevant.
     

    [/quote]

    It's an SQL-like NULL.

    NULL means "unknown" or "undefined" depending on context.

    All scalar data types have the full range of values allowed by their underlying data type, plus an extra value NULL which has all kinds of annoying (but useful) special case properties.  So a BOOLEAN in SQL has three values:  true, false, and NULL.  A 32-bit integer has 4294967297 values, from -2147483648 through 0 to +2147483647, and NULL. A string has many values ranging from empty string to all possible combinations of characters...and NULL.

    Comparing something with NULL returns NULL as a result, because you don't know what the result of comparing something with an unknown value might be.  So:

         1 = NULL -> NULL (don't know if something unknown is equal to 1)

        1 <> NULL -> NULL (don't know if something unknown is not equal to 1)

        1 > NULL, 1 < NULL, 1 <= NULL, 1 >= NULL, ... = NULL (just don't know, dammit!)

    Also, NULL = NULL is NULL, because we don't know either of the things we're comparing, so we have no idea whether they're equal.

    Adding things with NULL returns a NULL result, because "1 + unknown" is still unknown. 

    Just to be confusing, in SQL there are aggregate functions, which calculate functions over lists of values including NULLs.  These functions simply ignore the NULLs (interpreting the meaning of NULL as "missing" instead of "unknown"), so SUM(some expression equivalent to 2 + 3 + NULL + 4 + 5) = 15, but  "2 + 3 + NULL + 4 + 5" in a non-aggregate context would be NULL.

    On the other hand, sometimes we do know the results of expressions even if some of the operands are unknown.  For example:

         TRUE AND NULL -> NULL (sure, true is true, but null is unknown, so we don't know if it's true or false)

         FALSE AND NULL -> FALSE (false is false, and everything "AND" false is false, so we do know this is false)

         TRUE OR NULL -> TRUE (regardless of what the unknown thing is, TRUE OR something is always true)

         FALSE OR NULL -> NULL (we don't know whether "unknown" or "false" will be true, so it's unknown)

         NOT NULL -> NULL (don't know what the opposite of unknown is)

         (NOT NULL)  = NULL -> NULL (the unknown value on the left is not necessarily the same on the right)

    Now, just when you think you've got all the rules down, in contexts where decisions are to be made (e.g. WHERE and HAVING clauses in SQL, IF, WHILE, CHECK, CASE statements, and so on), suddenly NULL becomes equivalent to FALSE, except when it's equivalent to TRUE.  It makes more sense to talk about "true" and "not true", meaning the two possible values other than true (false and null), or "false" and "not false", meaning the two possible values other than false (true and null).

    -- 

    The thing called NULL in C and C++ (and probably several other languages) which has reference or pointer semantics is more like the LISP "nil" value.  In these languages, NULL is a single specific value which only some data types support.  There is no NULL int or bool value (although NULL tends to be convertible to int or bool). The NULL pointer is a real memory address, just one guaranteed to never have a valid object living there.  NULL Is not unknown--often NULL has the specific value 0 (although in C it is valid for NULL to have an in-memory value like 0xfee1dead or 0x55555555, although such magic values must be converted to 0 by the C compiler when the pointer is used in an integer expression).



  • Oh yes, I'm plenty familiar with the behavior of NULL in SQLServer. It just struck me as odd that it would leak out so much into the behavior of VBScript when I ran across that little quirk. I blame that stupid "Nothing" keyword for letting this one happen. Heh.



  • [quote user="brill"]

    Got this today reviewing code from a developer on loan to me from another department. I left my comment in...
     

    public void testSupportsResultSetConcurrency4() throws SQLException {
    boolean retValue = databaseMetaData.supportsResultSetConcurrency(
    ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

    // FIXME Holy shit what the hell is this testing? assert true or
    // false? What if the boolean wasn't true or false? -JFBP
    assertTrue(retValue || !retValue);
    }

    [/quote]

     

    Just to be clear, a boolean in thie context (Java) has only two possible values. The code is from a unit test so essentially the unit test is useless because it will always pass when it should fail on one or the other of those situations. So, broken code will never actually be caught.

    I'm being a wise-ass in my comment when I ask "What if the boolean wasn't true or false?" and the point is to make somebody think about what kind of dumb-ass code they are writing.

    That kind of crap will get you fired.

     



  • If it's using JUnit, it looks like it's testing that the called routine doesn't throw an SQLException with those parameters.  -20 points for not having a message string in the assert, -30 for not just saying "true."  OTOH, the coder could just have been trying to pad code coverage, in which case -90 for that, and -10 for including the assert in the first place.  Maybe you guys have a tool that checks to see that there are assertions in all the tests?  I've seen it done...



  • [quote user="brill"]

    I'm being a wise-ass in my comment when I ask "What if the boolean wasn't true or false?" and the point is to make somebody think about what kind of dumb-ass code they are writing.

    [/quote]

    [url=http://thedailywtf.com/forums/thread/80084.aspx]FileNotFound?[/url]



  • [quote user="poochner"]If it's using JUnit, it looks like it's testing that the called routine doesn't throw an SQLException with those parameters.  -20 points for not having a message string in the assert, -30 for not just saying "true."  OTOH, the coder could just have been trying to pad code coverage, in which case -90 for that, and -10 for including the assert in the first place.  Maybe you guys have a tool that checks to see that there are assertions in all the tests?  I've seen it done...
    [/quote]

     Its actually testing that the driver returns the expected result (support for the option) and not for an exception.

    what's complicated about assertTrue(true)? it means you expect the result to be true. -40 for cluttering your tests with obvious messages...



  • [quote user="brill"]

    Got this today reviewing code from a developer on loan to me from another department. I left my comment in...
     

    public void testSupportsResultSetConcurrency4() throws SQLException {
    boolean retValue = databaseMetaData.supportsResultSetConcurrency(
    ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

    // FIXME Holy shit what the hell is this testing? assert true or 
    // false? What if the boolean wasn&#39;t true or false? -JFBP
    assertTrue(retValue || !retValue);
    

    }

    [/quote]

    This comment (and by the way a lot of the posts in this thread) makes a lot more sense if you assume that the developer had a solid dose of LSD in his system.

    // FIXME Holy shit what the hell is this testing? assert true or
    // false? What if the boolean wasn't true or false? -JFBP QQTTSUIU^^38

    // What if the boolean's a cow? Hey, how about what if it's just what it is

    // without being in a state between which is in the greater cosmological

    // realm of oneness with be? Oh my holy fucking shit of stars!!!

    // Oh wow. Just wow. What am I testing for again? --JJTTWGGSFF##

    If you don't know your primitives, you probably spent too long at school.



  • [quote user="merreborn"]

    So basically, you're left with trinary logic. 

    [/quote]

    Which the few literate developers call ternary.



  • [quote user="brill"]

    Got this today reviewing code from a developer on loan to me from another department. I left my comment in...
     

    public void testSupportsResultSetConcurrency4() throws SQLException {
    boolean retValue = databaseMetaData.supportsResultSetConcurrency(
    ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

    // FIXME Holy shit what the hell is this testing? assert true or
    // false? What if the boolean wasn't true or false? -JFBP
    assertTrue(retValue || !retValue);
    }

    [/quote]

    Everyone is so inured by the return-via-exception paradigm that they don't even comment? :p

    Someday someone needs to design a language based entirely on exceptions and void functions, no return values of any sort. =D



  • The basic type "boolean" can never be NULL (as (obviously) opposed to an Object of type Boolean). Thus, the assertTrue call is redundant. If the test aimed at checking for exceptions then this way is even twice the WTF it seems to be. I assume that the person who wrote that isn't very familiar with java nor bothered trying to find out whether booleans can be NULL. I think that even the compiler would give you an error message if you wrote something like "... (b == null)..." (where b is a boolean).



  • [quote user="Phalphalak"]The basic type "boolean" can never be NULL (as (obviously) opposed to an Object of type Boolean). Thus, the assertTrue call is redundant. If the test aimed at checking for exceptions then this way is even twice the WTF it seems to be. I assume that the person who wrote that isn't very familiar with java nor bothered trying to find out whether booleans can be NULL. I think that even the compiler would give you an error message if you wrote something like "... (b == null)..." (where b is a boolean).
    [/quote]

     

    It's is certainly redundant because it will always return true. As for boolenas not being null, thats not exactly true anymore. in Java 5, with the new auto boxing feature, the primitive boolean would be converted to a Boolean object by the compiler... but it would still never be null because the primitive can't be null.

    And yes, the throws SQLException is a WTF because it has nothing to do with the test (I don't think that method even throws it) and it's clearly a copy & paste job.

     



  • [quote user="brill"]

    And yes, the throws SQLException is a WTF because it has nothing to do with the test (I don't think that method even throws it) and it's clearly a copy & paste job.

    [/quote]

    Supposing that databaseMetaData is an object that supports the inteface DatabaseMetaData, the method supportsResultSetConcurrency can throw SQLException according to the specification, though it's unlikely that any implementation would ever do that.

     

     



  • [quote user="ammoQ"][quote user="brill"]

    And yes, the throws SQLException is a WTF because it has nothing to do with the test (I don't think that method even throws it) and it's clearly a copy & paste job.

    [/quote]

    Supposing that databaseMetaData is an object that supports the inteface DatabaseMetaData, the method supportsResultSetConcurrency can throw SQLException according to the specification, though it's unlikely that any implementation would ever do that.

     [/quote]

     

    In that case the throws is natural when your not testing for exception. If one is thrown, you'll get an error instead of a failure which is what you would want because it means that is some other problem with the test.

    I guess it would depend on the implementation as to why one would be thrown. for instance most implementations I've seen simply return a true/false depending on support, but its possible that an impl might go back to the DB to check. 

    Thanks for pointing that out. I guess I should have checked the javadocs, particularly in this forum!



  • [quote user="brill"][quote user="ammoQ"][quote user="brill"]

    And yes, the throws SQLException is a WTF because it has nothing to do with the test (I don't think that method even throws it) and it's clearly a copy & paste job.

    [/quote]

    Supposing that databaseMetaData is an object that supports the inteface DatabaseMetaData, the method supportsResultSetConcurrency can throw SQLException according to the specification, though it's unlikely that any implementation would ever do that.

    [/quote]

    I guess it would depend on the implementation as to why one would be thrown. for instance most implementations I've seen simply return a true/false depending on support, but its possible that an impl might go back to the DB to check. 

    [/quote]

    I think in JDBC nearly every single method of every single interface is allowed to throw SQLException, because the creators of the JDBC specifications did not want to restrict implementations in doing so. Of course catching all those never-thrown-in-this-life exceptions makes programs ugly; that's one reason why C# handles it differenty. (Exceptions do not have to be caught or declared)

    I guess I should have checked the javadocs, particularly in this forum!

    Definitely ;-) 


Log in to reply