Phil Hassey - game dev blog
Phil Hassey as Snidely Whiplash
"You can't buy awesomeness.
You're born that way."

Is None more like 0 or -1 ?

In tinypyC++ every variable is a certain type.  In some cases I may have an int x = None;  But I’m not sure what that should mean?

What’s the most pythonic? Here’s some anecdotal evidence:

>>> None,None==None,None==-1,None==0,None==1,None==False,None==True,bool(None)
(None, True, False, False, False, False, False, False)
>>> -1,-1==None,-1==-1,-1==0,-1==1,-1==False,-1==True,bool(-1)
(-1, False, True, False, False, False, False, True)
>>> 0,0==None,0==-1,0==0,0==1,0==False,0==True,bool(0)
(0, False, False, True, False, True, False, False)
>>> 1,1==None,1==-1,1==0,1==1,1==False,1==True,bool(1)
(1, False, False, False, True, False, True, True)

So .. you can see -1 gets 4/7.  0 also gets 4/7.  (1 gets a mere 3/7, so it’s out.)

Anyone care to tilt the scales to -1 or 0?

16 Responses to “Is None more like 0 or -1 ?”

  1. Joseph Lisee Says:

    I think 0 makes more logical sense because when counting having 0 of something is equivalent is to be there being none of that something.

  2. Joey Says:

    -1 nor 0 are very pythonic as either one will work differently from python’s None depending on which you use. Should True == None (-1) or False == None (0) evaluate to True?

    My knowledge how tinpyC++ works is very very limited, so my question is could you create a None type C implementation that works like python’s? Where None compared to anything except another None evaluates False.

  3. Mike Hansen Says:

    If you have to choose either 0 or -1, I’d go for 0 since

    In [1]: bool(None)
    Out[1]: False

    In [2]: bool(-1)
    Out[2]: True

    In [3]: bool(0)
    Out[3]: False

  4. Doug Napoleone Says:

    All depends on exactly how you want to represent the concept of ‘None’ in C++.

    For instance, NULL pointers (i.e. 0) could be used as an equivalent to None. This is fairly standard across some extension modules, but I personally have some strong objections to it. It’s greatest benefit is also its greatest weakness. That is a 0 from one type can be cast to any type in C++. It is essentially typeless. This really impacts constants (defines) in the system. For instance if you have a ‘#define CPP_NONE 0’ in your code and use CPP_NONE everywhere (equates to NULL) and then use CPP_NONE everywhere irregardless of the type of pointer accepted. This is a bit too clever in my opinion.

    We use things like ‘#define FOOBAR_NONE ((FooBar *)-1)’ and never ever allow a NULL. This does mean that you must validate the arguments (checking for both NULL which is an error, and FOOBAR_NONE which is essentially NULL), but this means that we catch problems where a a NULL is passed around due to a failed operation (bug), and provide some extra type safety on the C++ side. On the Python side all the ‘FOOBAR_NONE’ variables (in the module space) are set to None, but we translate the None object into -1 internally. This turned out to be key as python CApi calls which error, return NULL universally, thus we can distinguish between error’s and None’s on the C++ side as 0 and -1 respectively.

    This was a bit of a flip from the normal C/C++ standard which uses -1 and NULL for error and success usually.

  5. Andrew Says:

    If you really want integer that fit in a word its kinda hard to make them nullable unless you set aside some numeric value as being none. Maybe instead of -1 or 0 you should use some less commonly used bit pattern that is the current max or min value an integer supports? 0xFFFFFFFF could be None or something like that.

    I would just disallow ints being None ever unless you declare them as a nullable int.

    You should check out gambit scheme it is a pretty good scheme to c compiler: http://dynamo.iro.umontreal.ca/~gambit/wiki/index.php/Main_Page it might ideas you can steal.

  6. Daniel Stutzbach Says:

    For what it’s worth, in C# they solved this by introduced a “nullable” type modifier denoted by sticking a question mark after the type. For example “int x = null;” is an error, but “int? x = null;” is not. In all other respects, x acts the same way. It’s a bit similar to a C++ reference type (“int &x”).

  7. Doug Napoleone Says:

    @andrew:

    void main()
    {
    unsigned int a = (unsigned int)-1;
    unsigned int b = 0xFFFFFFFF;
    if (a == b)
    {
    printf(“Same thing!\n”);
    }
    }

    >> a.out
    Same Thing!
    >>

  8. philhassey Says:

    @Everyone – your responses are great 🙂 I’m going to hold on really responding much myself with my final thoughts until everyone has said their piece.

  9. Mike Says:

    Seems to me that “int x = None;” is an error, because None is not an int.

    I am guessing this occurs because tinypyC++ needs to declare “x” before it is assigned a value.

    Perhaps you can define a particular int (e.g. -sys.maxint-1) to mean None, analogous to NaN for floating point.

    Alternatively, values can be represented internally by a 2-tuple (valid,value).

    int x = None; would become “Int x = (False, dont_care);”.
    int x = 42; would become “Int x = (True,42);”

    define appropriate casts to convert back and forth between “Int’s” and “int’s”.

  10. jovoc Says:

    I think it has to be 0 or otherwise statements like “if not x:” would fail to evaluate correctly.

    If that’s not an issue, I’d make it a symbolic constant, i.e.
    #define NONE_VAL (0xDEADBEEF)

    That way it’s easy to spot in a debugger.

  11. Larry Hastings Says:

    Definitely more like 0 than -1; you’d want it to be a false value.

    But why are you considering allowing “int” variables to be set to “None” in the first place? Why bother to have typed variables unless you’re going to enforce type safety? Whatever those circumstances are where you wanted to say “int x = None”, you should change *that*.

  12. tonic Says:

    My intuition would be for it to be 0. But then again, I’m not familiar with python and what is the meaning of None.

    OTOH – what about 0x80000000.. 😉
    (for a 32bit machine, this is the one negative number which doesn’t have a positive counterpart)
    I think this is same what Mike also suggested as one possibility.

  13. Ryan Says:

    I agree that “if not x:” is the most common use case so should work.

  14. Ryan Says:

    To expound on my earlier post now that my laptop is working again, I’d say focus on the common use cases and performance above anything else.

    tinypyc++ ints should definitely be ints in C++, so int* or the tuple idea above are out for performance reasons.

    So for use cases, here’s ones I can think of:

    x = None
    if something_condition:
    x = something_other_than_none
    if x:
    do_something()

    x = something_other_than_none
    if some_condition:
    x = None
    if not x:
    do_something()

    x = something_other_than_none
    if some_condition:
    y = None
    else:
    y = some_other_number
    if x == y:
    do_something()

    I know you’re big on unit testing, so I would definitely think that there should be a fair number of x = None : int unit tests to build, and that they should all look reasonable.

    I’m still leaning towards 0 though.

  15. Eric Says:

    For what it’s worth, I have previously invoked the fact that None is less than any integer, so 0x8000000 would certainly be tempting. However, the fact that it’s false is used far more often in my code, so zero is probably better Then again, I have elsewhere relied on the difference between zero and None, so that clearly can’t be optimal. 0xDEADBEEF would be great for the humor value, and very negative, but might occasionally trip on a real value.

    That said, this looks like an exceptional case to me. You have a choice between failing loudly, or doing the wrong thing sometimes. If tinypyC++ will frequently be used on third-party code, then perhaps zero is best; otherwise, error out.

  16. philhassey Says:

    Thanks everyone for the feedback. Sounds like “0” is the winner.

    Here’s the deal, in tinypyC++, when compiling I actually do check for None vs int and throw a compilation error at that point. So your code “can’t” assign None to an int.

    However if you read my post earlier this week about Exceptions, I’ve since added an optional exception-free mode to tinypyC++. So in cases like this [1,2,3].pop(5) it will print an error to stderr and return “None”. But I had to decide if “None” was more like 0 or -1. To be clear, this will never happen when exceptions are enabled (which is the default behavior.) Exception-free mode is enabled by -DTP_NO_THROW.

    In tinypyC++ you can assign an object = None and it will nullify the internal pointer and reduce the ref-count.