Live data from Hacker News

Please reconsider the Boolean evaluation of midnight

mail.python.org

211–218 of 218 posts

Re: Please reconsider the Boolean evaluation of midnight

#211
post #209
post #206

Earlier quoted context omitted.

Which means you don't like generic programming or templates. That in turn tells me something about the types of programmers you know. For example, neither you nor they likely use the Boost libraries. In any case, it's a bit of a distraction. "Most programmers" aren't all that good at programming, or judging what makes a good language. How important then is it that I weigh your projection of their ideas of right or wr…

Do any of your examples (generic programming, templates, Boost libraries) actually utilize the concept of testing the truthiness of an object of unknown type? I think your criticism is invalid. I like generic programming in Java, though I admittedly have not used templates or Boost libraries for anything substantial. > In Python it absolutely, positively, without a doubt is not a bad thing to have a function which ac…

C++ doesn't have unknown types, so we're working with different definitions. Here's an example:

    [xebulon:~/tmp] dalke% cat tmp.cc
    #include 
    
    template
    int f(T s) {
     return s ? 2 : 0;
    }
    
    main() {
      std::cout 
The function f() doesn't know the type, but its instantiation for f(0) (integer) and f(0.0) float know the type.

C++ containers don't have a bool (or at least vector doesn't). For one, until C++11 there was no "explicit operator bool", and a simple "operator bool" was too permissive because of implicit type conversion. C++11 introduced a more contextual conversion to bool.

More and more components have explicit bool support. For example, http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/shared_p... ?

    Notes: This conversion operator allows shared_ptr objects to be
    used in boolean contexts, like if(p && p->valid()) {}.

    [The conversion to bool is not merely syntactic sugar. It allows shared_ptrs
    to be declared in conditions when using dynamic_pointer_cast
    or weak_ptr::lock.]
and http://en.cppreference.com/w/cpp/memory/unique_ptr/operator_... .

I do not track C++ well enough to go into any more depth than this, especially as it concerns the history and future.

I like to say "if x: ..." and not "if len(x) == 0:" in order to check if a dictionary is empty.

Following Scheme, I can understand that something like "if empty(x)" might be more explicit. But I have a decent amount of code where I do something like:

   def process(a, rename=None):
     if rename:
       a = [rename.get(x, x) for x in a]
     ... do things with a ...
In this toy example, "rename=None" indicates that there is no renaming dictionary, and using {} as the renaming dictionary won't rename anything, so the "if rename" tests for both conditions correctly.

Without bool, I could write it as:

     if rename is not None:
since using the empty dictionary in this case is okay, but if I want the slight extra performance for the empty dictionary case I would have to write it:

     if rename is not None and not empty(rename):
I think that would grow tedious.

BTW, I don't use "def process(a, rename={}):" because that is one of Python anti-patterns: the default values are constant over the life of the function, so

    def something(a, b={}):
      b[a] = a
      return b
will accumulate to b rather than create a new dictionary each time. Thus, seeing a "={}" or "=[]" in a parameter list demands closer inspection because it often leads to errors.

Re: Please reconsider the Boolean evaluation of midnight

#212
post #196
post #189

Earlier quoted context omitted.

If you want that, try the Counter class: >>> from collections import Counter >>> Counter({1: "a"}) + Counter({1: "b"}) Counter({1: 'ab'}) But Python dictionaries won't support '+' because of the ambiguity. This goes back to 1994: http://ftp.ntua.gr/mirror/python/search/hypermail/python-199... Lance Ellinghouse: why can't I add dictionaries like I can other objects? ... if a and b both had the same keys, then I think…

This is neat: >>> a = Counter() >>> a[1] = a >>> b = Counter() >>> b[1] = b >>> a + b Traceback (most recent call last): File " ", line 1, in File "...../collections.py", line 536, in __add__ newcount = self[elem] + other[elem] File "...../collections.py", line 534, in __add__ result = Counter() RuntimeError: maximum recursion depth exceeded If dict() implemented add as you propose then it would be subject to the sam…

That's an interesting point, but I'm inclined to say that very few languages could come up with {1:this} - Prolog could, I think - and that running into those errors in Python would be user error.

That said, this is a good example of the expressivity of this, which mathematical definitions often implicitly disallow.

Re: Please reconsider the Boolean evaluation of midnight

#213

Earlier quoted context omitted.

It's against the grain to think this way in dynamic languages because variables don't have types, only individual values do. Ill-thought truthiness rules are the real problem. IMO every value except boolean false (and, if you insist, nil/null) should be truthy in a dynamic language.

> It's against the grain to think this way in dynamic languages because variables don't have types, only individual values do. So? "The only valid type for a conditional is boolean" still works if types only apply to values. Under that principle, anything but True or False value encountered in evaluating the condition of an if statement ought to throw a TypeError, not be evaluated for truthiness. If you are expecting…

We're on the same page - I just didn't phrase that well. I mentioned it because most of the time what's written is a test of a variable, not a literal value, and that couldn't get a thumbs-up as robust without someone putting a static analyzer hat on.

Having a simple universal truthiness rule seems preferable and more in the spirit of a dynamic language.

Re: Please reconsider the Boolean evaluation of midnight

#214

Earlier quoted context omitted.

It's against the grain to think this way in dynamic languages because variables don't have types, only individual values do. Ill-thought truthiness rules are the real problem. IMO every value except boolean false (and, if you insist, nil/null) should be truthy in a dynamic language.

> variables don't have types, only individual values do. It really depends on what language you're using. This is more or less true in Python, Ruby, and Javascript. In Lisp generic methods you can specify the type for the input variables and be guaranteed that if you are inside the method the parameters are of that specific type. For optimization reasons you can also declare to the compiler that variables are a speci…

Interesting. Admittedly I have only used (UnCommon) Lisps in a hobbyist way and haven't been concerned with techniques for extra speed/robustness there.

Re: Please reconsider the Boolean evaluation of midnight

#215

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…

Wow. This "Mark Lawrence" guy is absolutely worthless. I googled him and cannot believe the Python community still has guys like him.

Re: Please reconsider the Boolean evaluation of midnight

#216
post #212
post #196

Earlier quoted context omitted.

This is neat: >>> a = Counter() >>> a[1] = a >>> b = Counter() >>> b[1] = b >>> a + b Traceback (most recent call last): File " ", line 1, in File "...../collections.py", line 536, in __add__ newcount = self[elem] + other[elem] File "...../collections.py", line 534, in __add__ result = Counter() RuntimeError: maximum recursion depth exceeded If dict() implemented add as you propose then it would be subject to the sam…

That's an interesting point, but I'm inclined to say that very few languages could come up with {1:this} - Prolog could, I think - and that running into those errors in Python would be user error. That said, this is a good example of the expressivity of this , which mathematical definitions often implicitly disallow.

An analysis shouldn't stop at "user error". Instead, ask if the programming language design plays a role.

For example, NUL terminated strings lead to a lot of user errors, some of which lead to security holes. Other string representations don't have that flaw, though come with a different cost concern. Is a buffer overflow "user error"? Some would say it is. But the language design makes those errors more dangerous.

Or in Python, there's no technical reason to have a ":" at the end of the line before an indented block. Instead, it's there because user studies show that people learning ABC (which influenced a lot of early Python) made fewer mistakes if the ":" was present than if it wasn't.

Are indentation mistakes user error? Certainly users play a role. But again, the design does as well.

So saying that something is a "user error" with no further analysis absolves the designer of any responsibility, and I disagree with that idea.

There are at least 4 different ways to handle dict+dict in Python. At least three have come up in this thread as the proposed correct solution. Even if there is a mathematically clean solution, if only 10% of the people expect it to work that way, then why should Python introduce something which is so error prone? No support for dict+dict is 100% error prone, of course, but trivially identified in testing. While Counter+Counter-like behavior has subtle consequences that will trip people up.

(As another example of the subtleties, consider an inverted index mapping word to a list of document ids:

    collection_a = {"a": [0, 3, 4], "the": [0, 2, 3]}
    collection_b = {"a": [5], "an": [6, 7]}
    collection_c = {"the": [10], "not": [10]}
    merged_collection = a+b
    merged_collection += collection_c
This is wrong because the += changes merged_collection["the"], which is the same list as collection_a["the"]. So even though it looks like good code, and it is good code for any value where x+=y is the same as x=x+y, it may cause problems which are hard to spot.)

"In the face of ambiguity, resist the temptation to guess."

Re: Please reconsider the Boolean evaluation of midnight

#217

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…

Wow. This "Mark Lawrence" guy is absolutely worthless. I googled him and cannot believe the Python community still has guys like him.

I took a look and yes, this is the kind of guy that results in a system with a hundred weird exceptions that have to be memorized.

Re: Please reconsider the Boolean evaluation of midnight

#218

Earlier quoted context omitted.

beginner-friendly doesn't mean stupid-friendly. And I am in favor of "teaching people to style their code better" in the language even if in this case, it's not about style but the meaning of midnight. semantic != style. Also, language must also help/structure/offer rails for thinking, create et cetera. Industry must bend before truth, not bend truth over itself...

We have mostly the same principles but have come to different conclusions. The semantics of midnight are indeed what is important here, but midnight does not qualify as a zero. Zero implies identity for some addition, and there is no addition for which midnight is the identity. This is because midnight does not even support addition: you have to use timedeltas if you want to add times. Timedelta 0, then, is the prope…

Agreed, midnight is not False.
Post reply on HN