bool(ffi.cast("bool", False)) should be False

Issue #255 resolved
Amaury Forgeot d'Arc
created an issue

int-like cdata objects are correctly converted to int with the int() function, but their bool value is always True.

bool(ffi.cast("int", 0)) should be False

bool(ffi.cast("int", 1)) should be True

Comments (10)

  1. Armin Rigo

    Currently only NULL pointers are False. It's easy to fix so that integers and floats of value 0, 0.0 or -0.0 are False, but it comes with a backward-compatibility issue. Should it be done anyway? I guess so.

  2. Armin Rigo

    A similar issue occurs with comparison. They are both meant to work with pointer cdata, and give potentially strange results with integer and float cdata. For example:

    >>> ffi.cast("int", 0) == 0
    False
    >>> ffi.cast("int", 0) == ffi.cast("int", 0)
    False      # because the ints are stored at different addresses
    >>> ffi.cast("int", 0) > ffi.cast("int", 0)
    TypeError: cannot do comparison on a primitive cdata
    
  3. Armin Rigo

    There are more problems with the long double type: we can't convert between it and the Python long for values that are too big to fit into the double range. We should be able to.

    If we fix the issues above, we need to fix hash() too---including making sure that hash() of a very large long double value is equal to hash() of the corresponding long.

  4. Armin Rigo

    Does it make sense to give C-style comparison to cdatas? This looks like a good idea, but it implies that ffi.cast("unsigned int", -1) == ffi.cast("int", -1), but ffi.cast("unsigned short", -1) != ffi.cast("short", -1). So, what should we do:

    • either we follow the C rules, and say that ffi.cast("int", 0) always compares different from 0;

    • or we say instead that we automatically cast to a Python int or float, and then do the comparison there? Then ffi.cast("int", -1) compares equal to -1 and different from ffi.cast("unsigned int", -1).

    Any preference?

  5. Andrea Waite

    I definitely would prefer c-style semantics. When you compare numbers you're comparing their value, not their address.

    If someone's casting negative numbers to unsigned values I think they're a grownup programmer and know what the implications of that are. If they don't want modulo effects to happen, don't cast before comparing numbers!

  6. Armin Rigo

    Right, but unless I'm missing it, you're not answering the questions. In C, if you have a variable int x = -1; and a variable unsigned int y = 4294967295U; then they compare equal. The questions are:

    • do we want a x=<cdata 'int'> containing -1 and a y=<cdata 'unsigned int'> containing 4294967295 to compare equal?

    • do we want the x above to compare equal to -1?

    • do we want x to be hashable?

    Note that I'll leave it as an exercise to the reader to figure out why we can't answer "yes" to both the first and the third question.

  7. Andrea Waite

    The Zen of Python says "explicit is better than implicit" and "in the face of ambiguity, refuse the temptation to guess" Python numbers are abstract and try to avoid weird and freaky C behavior. In C sometimes one uses the aliasing of numbers modulo 2^N for speed and cleverness, but that's not what a user is likely to want nor expect in python, at least not implicitly and without warning.

    Therefore, I propose simply converting each to python integers first, then compare. Therefore: x != y as such, x should == -1 * of course x should be hashable (no unexpected behavior)

    If one wants the first behavior (x == y), one can easily have it by explicitly doing x == ffi.cast('int', y)

  8. Log in to comment