Live data from Hacker News

Please reconsider the Boolean evaluation of midnight

mail.python.org

171–180 of 218 posts

Re: Please reconsider the Boolean evaluation of midnight

#171

Earlier quoted context omitted.

if var: ... is better code (for my value of better, which is subjective) than: if var is not None: ...

In my opinion, the "explicit is better than implicit" mantra of Python (which I find very sensible) should immediately imply preference for the second, even in cases where the first is almost certainly not going to cause problems. Testing for "not None" also immediately tells other devs at least something about what's going on. Example: If var is an argument to a function and you see "if var," really understanding wh…

Once upon a time there was a language called Smalltalk that was the grandfather of dynamically typed languages. Perhaps partially as a consequence of implementing if else as methods on the boolean classes taking block closures to be executed only booleans were allowed(anything else is a missing method). If you wanted to test for null(Nil) you had to say something like

self foo isNil ifTrue: [self defaultFoo]

later some implementations added a method on object to test for nil

self foo ifNil: [self defaultFoo]

if you had to test for nil before testing for a condition it would be a bit ugly.

self foo ifNil: [((self foo) isFooish) ifTrue: [self defaultFoo]]

In ruby which was developed about a bit later perhaps to late to influence pythons bool handling they got rid of this problem by treating either nil or false as Falsey and everything else as truthy.

In python everything is true except:

    None

    False

    zero of any numeric type, for example, 0, 0L, 0.0, 0j.

    any empty sequence, for example, '', (), [].

    any empty mapping, for example, {}.

    instances of user-defined classes, if the class defines a __nonzero__() or __len__() method, when that method returns the integer zero or bool value False. [1]
http://docs.python.org/2/library/stdtypes.html In python 3 __nonzero__ is __bool__ The reason for 0 being a truthy value arguably is arguably due to historical reasons. false used to be 0 and truth used to be 1, when they introduced a bool type they made it be an integer. Some of the important python people(who are much better programmers then me) may disagree(http://stackoverflow.com/a/3175293/259130) but I think it was a ugly stain and should have been removed in python3 along with the whole 0(of any numeric type) being falsey.

The upside to python behaving like this is that in many situations you don't care what kind of falsey value you may have and you can write

if person and person.name: instead of if person != None and person.name != None and person.name != "":

and

if students and "John" in students and students[John"].age and students[John"].friends: print "John has friends" instead of if students != None and "John" in students and students[John"].age != None and len(students[John"].friends) > 0: print "John has friends"

There are downsides to this and people may have a strong personal preference for personal scripts and you can argue that the ruby way or even the smalltalk way is conceptually nicer(and more "explicit") but this is proper pythonic style and generally you should use it in python(maybe not the numerical one except when getting len of a collection)(unless you specifically depend on different code for different falsey values).

Re: Please reconsider the Boolean evaluation of midnight

#172

INADA Naoki's argument [1] is succinct and insightful. I feel zero value of non abelian group should not mean False in bool context. () + () == () "" + "" == "" 0 + 0 == 0 timedelta() + timedelta() == timedelta() time() + time() => TypeError [1] https://mail.python.org/pipermail/python-ideas/2014-March/02...

It doesn't make sense that times should be added at all.

Re: Please reconsider the Boolean evaluation of midnight

#173

INADA Naoki's argument [1] is succinct and insightful. I feel zero value of non abelian group should not mean False in bool context. () + () == () "" + "" == "" 0 + 0 == 0 timedelta() + timedelta() == timedelta() time() + time() => TypeError [1] https://mail.python.org/pipermail/python-ideas/2014-March/02...

And this is why programmers who know math are better programmers.

Adding times is semantic nonsense. It's irrelevant how this relates to Abelian monoids. Mathematically beautiful form is not a virtue if it just creates bizarre and confusing interfaces.

edit: last Tuesday, 5:00pm + Christmas two years ago at noon = ???

Re: Please reconsider the Boolean evaluation of midnight

#174

If I understand the argument there correctly, the responder is saying: Nobody should ever use this functionality, instead they should always check that the date is not None. So, we should leave this broken, because we don't want to break backwards-compatibility with that class of applications that nobody should ever write. That philosophy, taken to its logical conclusion, results in everything being broken forever.

Yes. This is where Linus would step in and say "SHUT THE FUCK UP! We don't break user space, EVER!" Developers who enter into the mindset that the users of their code are using it "wrong" are a blight and will always be a blight. Too bad Python has a BDFL and not a Raging DFL.

As another commenter pointed out, nuance is important. However, there are times to break break compatibility and accept that people will struggle. The way to do this right is to give real warning and provide reasonable migration paths.

I will give you an example that bit my project hard, caused hours upon hours of wasted time for bugfixes, broke our software, etc. and yet was a good thing: PostgreSQL 8.3's removal of most implicit type casts. Prior to PostgreSQL 8.3, the following query would be valid and evaluate to false:

     select '2014-01-01' = 2014-01-01;
What would happen is the system would look for possible types to compare and find that text matched. It would then treat this as:

     SELECT '2014-01-01'::text = (2014 - 1 - 1)::text;
And further to:

     SELECT '2014-01-01'::text = '2012'::text
which was not what you meant. The team made the right decision to make this change and subsequently broke a lot of apps out there. I think it took us a couple months to be sure we had all the breakage out of LedgerSMB 1.2.x. Painful change. Broke a whole bunch of apps. But it was an important one and we are all better off for it.

Now, Linux exists in an ecosystem of mostly source-compatible operating systems. People write portable software that they expect to run on FreeBSD, Linux, and so forth with minimal tweaking. I am not sure "we don't break user space ever" would be a compelling argument against fixing non-POSIX-compliant but existing and documented behavior. But this scenario (and frankly the stupidity in the midnight type handling in Python) is what pre-review is supposed to help prevent in the first place.

Re: Please reconsider the Boolean evaluation of midnight

#175

INADA Naoki's argument [1] is succinct and insightful. I feel zero value of non abelian group should not mean False in bool context. () + () == () "" + "" == "" 0 + 0 == 0 timedelta() + timedelta() == timedelta() time() + time() => TypeError [1] https://mail.python.org/pipermail/python-ideas/2014-March/02...

And this is why programmers who know math are better programmers.

An ironic comment, considering that appears to me to be a misuse of "abelian group." Abelian groups are those whose group operation is commutative, which has nothing to do with the code examples provided.

Re: Please reconsider the Boolean evaluation of midnight

#176

INADA Naoki's argument [1] is succinct and insightful. I feel zero value of non abelian group should not mean False in bool context. () + () == () "" + "" == "" 0 + 0 == 0 timedelta() + timedelta() == timedelta() time() + time() => TypeError [1] https://mail.python.org/pipermail/python-ideas/2014-March/02...

What do those code samples have anything to do with abelian groups? Abelian groups are those whose group operator is commutative, i.e. a + b = b + a for all a and b.

The code examples seem to be referring to the existence of an identity element, which is necessary for all groups.

Re: Please reconsider the Boolean evaluation of midnight

#177

So ignoring the hype, here's the outcome-to-date... The ticket was reconsidered, reopened and classified as a bug. http://bugs.python.org/msg212771 Nick Coghlan's dissection of the issue here: https://mail.python.org/pipermail/python-ideas/2014-March/02... is pretty much perfect - wonderful piece of technical writing! Donald Stufft has expressed an interest in making the patch for this happen, and assuming all goes a…

Will it be resolved in 2.x though? That's what most people care about.

Re: Please reconsider the Boolean evaluation of midnight

#178

I think he understates the most powerful part of his argument. Midnight is a value, not a special value. There is no reason why it or any other valid time should be falsey on a daily cycle.

Couldn't the same argument be made about zero?

There are times when I like the fact that zero is false in Perl.

However, usually I am happy that '0 is false' in PostgreSQL raises a type exception.

Re: Please reconsider the Boolean evaluation of midnight

#179
post #177

So ignoring the hype, here's the outcome-to-date... The ticket was reconsidered, reopened and classified as a bug. http://bugs.python.org/msg212771 Nick Coghlan's dissection of the issue here: https://mail.python.org/pipermail/python-ideas/2014-March/02... is pretty much perfect - wonderful piece of technical writing! Donald Stufft has expressed an interest in making the patch for this happen, and assuming all goes a…

Will it be resolved in 2.x though? That's what most people care about.

2.x is EOL and only remains for legacy programs. A backwards-incompatible change won't even be considered for this branch.
Post reply on HN