LWN: Comments on "A false midnight" https://lwn.net/Articles/590299/ This is a special feed containing comments posted to the individual LWN article titled "A false midnight". en-us Sat, 30 Aug 2025 18:10:23 +0000 Sat, 30 Aug 2025 18:10:23 +0000 https://www.rssboard.org/rss-specification lwn@lwn.net A false midnight https://lwn.net/Articles/591691/ https://lwn.net/Articles/591691/ quanstro <div class="FormattedComment"> from a math pov, programming DOES (generally) make sense. by generally, i mean with the exception of floating point. operations in math are defined over a thing. that thing might be a group, a field or a ring. so there is such a thing as division on Z (integers), and there is such a thing as division on R (real numbers), but Z is not a division ring. programming typically operates on Zn, where n = 2^m, m is typically one of 8,16,32,64 for unsigned numbers. signed numbers are similar. note that the fact that Zn is not a division ring (i.e. there's a n satisfying n = a/b for all a, b in Zn) does *not* make this strange to mathematicians. <br> <p> floating point is problematic. it's not a ring. not abelian. and has all sorts of other ... rather unexpected properties.<br> <p> </div> Mon, 24 Mar 2014 17:21:07 +0000 A false midnight https://lwn.net/Articles/591642/ https://lwn.net/Articles/591642/ moltonel <div class="FormattedComment"> Just stumbled upon a nice writeup of many python2 gotchas that got fixed in python3 : <a href="http://python-notes.curiousefficiency.org/en/latest/python3/questions_and_answers.html#why-is-python-3-considered-a-better-language-to-teach-beginning-programmers">http://python-notes.curiousefficiency.org/en/latest/pytho...</a><br> <p> And these are only items that were well known and discussed while moving to python3. As the lwn article shows, it isn't an exaustive list. See also <a href="https://wiki.python.org/moin/Python2orPython3">https://wiki.python.org/moin/Python2orPython3</a><br> </div> Mon, 24 Mar 2014 13:58:16 +0000 A false midnight https://lwn.net/Articles/591498/ https://lwn.net/Articles/591498/ Jandar <div class="FormattedComment"> It's embarrassing to see how much one can forget. My mathematical studies lie some 20 years in the past and almost anything about sheaf and germs is lost.<br> </div> Sat, 22 Mar 2014 15:23:51 +0000 A false midnight https://lwn.net/Articles/591479/ https://lwn.net/Articles/591479/ mathstuf <div class="FormattedComment"> Depends on the context[1] :) . Each series resulting from the ζ(n) with n as a negative, odd integer has a single, useful value which can be used in its place when it occurs in equations (physics, chemistry, etc.).<br> <p> [1]<a href="https://en.wikipedia.org/wiki/Particular_values_of_Riemann_zeta_function#Negative_integers">https://en.wikipedia.org/wiki/Particular_values_of_Rieman...</a><br> </div> Sat, 22 Mar 2014 10:46:37 +0000 A false midnight https://lwn.net/Articles/591478/ https://lwn.net/Articles/591478/ Jandar <div class="FormattedComment"> ζ(n) with negative odd n is infinite.<br> </div> Sat, 22 Mar 2014 09:54:39 +0000 A false midnight https://lwn.net/Articles/591454/ https://lwn.net/Articles/591454/ mathstuf <div class="FormattedComment"> <font class="QuotedText">&gt; Usually one doesn't consider the set an object was *selected from* to be an identifying characteristic of the object.</font><br> <p> Well, in algebra "1 - 1 + 1 - 1 + …" is undefined since algebra cannot reach the end; in the realm of infinite series, ½ is a valid value for the series (and the only one). There's a similar thing with any of ζ(n) when n is a negative odd integers (ζ(-1) = 1 + 2 + 3 + 4 + … = -1/12, ζ(-3) = 1 + 8 + 27 + 64 + … = 1/120, etc.). Computations definitely rely on the context in which they reside; I see no reason why numeric values would be exempt.<br> </div> Sat, 22 Mar 2014 00:03:38 +0000 A false midnight https://lwn.net/Articles/591367/ https://lwn.net/Articles/591367/ apoelstra <div class="FormattedComment"> Integer overflow is a property of the integer type in many languages (though as you say, not Python). It's intuitive that a fixed-width type is going to overflow at some point, by the pigeonhole principle. In languages like Python or Lisp which hold arbitrarily-sized integers, this overflow is not a property of the type. In either case there is no type transition caused by adding 1 repeatedly to an integer, so I can be sure of the types of my objects before and after the addition.<br> <p> I really don't like that in C, signed integer overflow is undefined behaviour -- in this case, I can't be sure of anything after the addition. :(<br> <p> I like your "date - date = duration" example. I think you're right that POLS says division should have a floating-point output (and the truncation behaviour should be relegated to some other construct, e.g. a truncate() function), since what '/' does to ints in C is not, in fact, division.<br> <p> In this case I can still be sure of the types of objects before and after the operation --- of course there is no intrinsic reason that these should be the same.<br> <p> </div> Fri, 21 Mar 2014 15:37:23 +0000 A false midnight https://lwn.net/Articles/591350/ https://lwn.net/Articles/591350/ apoelstra <div class="FormattedComment"> <font class="QuotedText">&gt; That's certainly an interesting way to look at it. Usually one doesn't consider the set an object was *selected from* to be an identifying characteristic of the object. The same object can belong to multiple sets, and, mathematically speaking, there is no difference between 2, 2/1, and 2.0.</font><br> <p> The reason I look at it this way is because I have encountered "type errors" when building mathematical proofs, for example when working with two groups whose group operations are both denoted as multiplication. The extra mental effort to tag every object with its originating set, in order to see which operations are available and meaningful, feels exactly like the extra mental effort to analyze code in an implicitly typed language.<br> <p> Often hypotheses in mathematical proofs are actually type declarations, as in "Let M be a compact closed manifold". Early "proofs" before the late 19th century would lack this type information (in fact people were unaware that they needed it) and the result was an enormous body of confused and incorrect mathematical work. For example it was common practice for "proofs" to have corresponding lists of counterexamples. This is evidence that it's very easy and natural for people to lapse into defective reasoning when faced with implicit typing. Though of course programmers have a big advantage over 18th-century mathematicians in that we know not only that the types are there, but also a complete (and small) list of all available types.<br> <p> Maybe this is a confused analogy. But I don't think it is, and it's helpful to me in both mathematics and programming.<br> <p> <font class="QuotedText">&gt; I'm not quite sure what you mean when you say that "rational 2" is not prime... "rational 2" is the same number as "integer 2", which is a prime number. If you're referring to a different kind of prime, like a prime field, then you'll have to be more specific before you can classify 2 as prime or not.</font><br> <p> It's a bit of an aside, but I mean prime in the sense of commutative rings: an element p is prime if it is (a) nonzero and not a unit, and (b) if p divides ab, it divides one of a or b.<br> <p> In the ring of integers 2 is prime; in the ring of rationals 2 is not (because it is a unit, which means it has a multiplicative inverse).<br> <p> <p> </div> Fri, 21 Mar 2014 15:10:08 +0000 A false midnight https://lwn.net/Articles/591322/ https://lwn.net/Articles/591322/ moltonel <div class="FormattedComment"> <font class="QuotedText">&gt; It seems very counterintuitive to me that mathematical operators would change numeric types, I'd expect that adding extra magic type-conversion rules to a language in which everything type-related is already done magically will increase your potential for bugs.</font><br> <p> Do you also find it intuitive that adding 1 to a big enough value yields a very low negative value ? Some languages, python included, will convert that machine-level integer into an object that can store arbitrarily long numbers (BTW, it's transparent in python3, but python2 appends an 'L' suffix to that number), and that is a good thing in most cases.<br> <p> Type-changing operators are actually common and expected, as long as they follow some common sense (how about the classic "date - date = duration" for example ?). And common sense says that numbers are numbers are numbers.<br> <p> You only find "2/3=0" intuitive because you've been formated by years of using languages where this is the case for technical reasons. But tell that to any non-programmer or user of other languages and they'll be asking "WTF?". Python3 fixed that gotcha. This is a Good Thing.<br> </div> Fri, 21 Mar 2014 10:42:22 +0000 A false midnight https://lwn.net/Articles/591312/ https://lwn.net/Articles/591312/ abket <div class="FormattedComment"> What a shitty language.<br> <p> In reasonable languages, you can only test boolean values, and nothing is implicitly converted to them.<br> <p> But anyway, this is a language where variable assignment is effectively best-effort, since any typo in the variable name will make it have no effect without warning, so that's the least of the problems.<br> <p> Don't use Python.<br> <p> </div> Fri, 21 Mar 2014 08:21:11 +0000 A false midnight https://lwn.net/Articles/591311/ https://lwn.net/Articles/591311/ mbunkus <div class="FormattedComment"> Well, from the maths POV a lot of stuff in programming doesn't make sense. Underflows/overflows? All operations should operate on arbitrarily-sized numbers, of course. And 0.3 - 0.2 - 0.1 should always == 0.0, of course. And infinity handling could be better, too – you know, there are no exceptions in real life (or processor flags or…) ;)<br> <p> So what's my point? Not sure, maybe something like: computer maths aren't like real world maths anyway, so arguing we should make an operation like division more like real-world maths doesn't make much sense to me.<br> <p> However, int/int = int makes a lot of sense to me, coming from C and C++. Those are languages whose explicit goal is to make you pay for what you use, but not for anything more. Back when C was specified there were no FPUs in processors. Floating point number operations were exceedingly expensive. They're still more expensive than their integer counterparts. So yes, keeping division of integer operands an integer makes a lot of sense.<br> <p> Note: I'm only arguing C/C++ here, not Python, as one of the OPs mentioned C/C++, and the reason for the integer division is simply speed/efficiency and giving the programmer control over the runtime cost.<br> </div> Fri, 21 Mar 2014 08:20:12 +0000 A false midnight https://lwn.net/Articles/591257/ https://lwn.net/Articles/591257/ nybble41 <div class="FormattedComment"> <font class="QuotedText">&gt; Well, even in mathematics there are different 'types' corresponding to the set in which an object is supposed to lie. For example, the integer 2 is prime while the rational 2 is not; the rational 2 is a unit while the integer 2 is not. The real 2 is a square while the rational or integer 2 is not, etc. etc.</font><br> <p> That's certainly an interesting way to look at it. Usually one doesn't consider the set an object was *selected from* to be an identifying characteristic of the object. The same object can belong to multiple sets, and, mathematically speaking, there is no difference between 2, 2/1, and 2.0. The number 2 is a member of the set of integers, and the set of rationals, and the set of reals, all at the same time. It has a square root in the set of reals, but not in the set of integers. It's a unit in the rings of rationals and reals but not in the ring of integers. The set qualifier goes with the property (has an integer square root, is a unit in the ring of rationals), not the number.<br> <p> I'm not quite sure what you mean when you say that "rational 2" is not prime... "rational 2" is the same number as "integer 2", which is a prime number. If you're referring to a different kind of prime, like a prime field, then you'll have to be more specific before you can classify 2 as prime or not.<br> </div> Thu, 20 Mar 2014 20:28:44 +0000 A false midnight https://lwn.net/Articles/591225/ https://lwn.net/Articles/591225/ apoelstra <div class="FormattedComment"> Well, even in mathematics there are different 'types' corresponding to the set in which an object is supposed to lie. For example, the integer 2 is prime while the rational 2 is not; the rational 2 is a unit while the integer 2 is not. The real 2 is a square while the rational or integer 2 is not, etc. etc.<br> <p> Often there are implicit embedding maps from, as in your example, the integers into the reals. As long as they are actual embeddings (i.e. injective and a homomorphism of the appropriate type) they are left implicit, but otherwise you need explicit maps to move between types. And in fact this type information can cause confusion; exponentiation might map from a group of numbers under addition to a group under multiplication --- and if these groups have the same (or nearly the same) underlying set, it can cause confusion and bad logical implications, for exactly the same reason that type conversions are a source of bugs in programming.<br> <p> So it is nothing new that 2 and 2.0 are different types in programming. (Though the truncating behaviour of '/' is pretty weird --- in mathematics the integers are not a division ring and division is not done on them in general.) And in programming there are dramatic differences: for one thing, there is no 'real' type since almost all reals cannot be described in finite information, while every integer can. With floating point types, all arithmetic operations are approximations (and their errors can compound in surprising ways) while integer operations are precise (everywhere that they are defined).<br> <p> <p> </div> Thu, 20 Mar 2014 16:16:33 +0000 A false midnight https://lwn.net/Articles/591224/ https://lwn.net/Articles/591224/ Wol <div class="FormattedComment"> MINYEAR could be 0? Why?<br> <p> Although the Western calendar has positive and negative years, AD and BC, it's interesting that it doesn't have a year 0. Although when you look at the history this is no surprise. The current numbering system from the (assumed) date of Jesus' birth was implemented at a time when there was no concept of 0.<br> <p> Actually, this would be a perfect rational for why year 0 should be false :-)<br> <p> There is no symbol in Roman Numerals for 0, and iirc, it was introduced to Western mathematicians round about 1000AD, some 600 years after the calendar was implemented.<br> <p> Cheers,<br> Wol<br> </div> Thu, 20 Mar 2014 15:54:06 +0000 A false midnight https://lwn.net/Articles/591223/ https://lwn.net/Articles/591223/ renox <div class="FormattedComment"> I think that the main reason why other language doesn't do this is that reals have several possible representations: float32, float64, float intervals, rationals,etc which make choosing the 'real' type for the division's result quite arbitrary..<br> <p> <p> </div> Thu, 20 Mar 2014 15:43:58 +0000 A false midnight https://lwn.net/Articles/591221/ https://lwn.net/Articles/591221/ Wol <div class="FormattedComment"> Given that, outside of programming, 3/4 DOES equal 0.75, then of course.<br> <p> While typing is a good way of getting the compiler to spot your mistakes, it is wholly unnatural from a maths p-o-v. Looking at things as a mathematician and not as a computer scientist, a number is a number is a number, and this categorisation into things like ints, longs, reals, double-precisions etc is abnormal. If I wanted 3/4 to give me 0 I'd use mod, not divide.<br> <p> Cheers,<br> Wol<br> </div> Thu, 20 Mar 2014 15:35:36 +0000 A false midnight https://lwn.net/Articles/591171/ https://lwn.net/Articles/591171/ zuki <div class="FormattedComment"> If I do a division, I *am* aware of the type... They are numbers, and specifically numbers.Real. In Python, both an int and and a float are subclasses of numbers.Real. For almost all intents and purposes, the difference between them is unimportant, but division is one them. Things might work when called with 5.0, but break if that argument changed to 6. I'd rather avoid that.<br> <p> <font class="QuotedText">&gt; It seems very counterintuitive to me that mathematical operators would change numeric types</font><br> <p> I don't understand that... In "real" math, integers are also reals, and 5 is exactly the same as 5.0, and 4.999..., and nothing should change if one is substituted with the other. And operations *do* change type, e.g. with division, raising to the power or logarithm with might get a (non-integer) real from integers, and on the other hand, floor and ceiling and division or multiplication, we might get an integer from reals... I like it when Python keeps up this illusion, whenever feasible.<br> </div> Thu, 20 Mar 2014 13:31:08 +0000 A false midnight https://lwn.net/Articles/591168/ https://lwn.net/Articles/591168/ apoelstra <div class="FormattedComment"> I think in general if you are doing a project of sufficient complexity that you need to be aware of the type of your objects (but are not), Python is the wrong language for you, and something where types are explicitly described and tracked would be better.<br> <p> It seems very counterintuitive to me that mathematical operators would change numeric types, I'd expect that adding extra magic type-conversion rules to a language in which everything type-related is already done magically will increase your potential for bugs.<br> </div> Thu, 20 Mar 2014 12:51:28 +0000 A false midnight https://lwn.net/Articles/591165/ https://lwn.net/Articles/591165/ zuki <div class="FormattedComment"> I've been using mixed Python 2/3 environments recently, and after getting accustomed to the new division behaviour, when I use Python 2, the old truncating behaviour is one of the bug "sources". I've had to add 'from __future__ import division' more than once in the last few weeks to fix actual bugs in code. Of course one can say that I should simply remember to do a cast to float here and there, but at least for me, it feels much easier and results in fewer bugs to do an explicit truncating division with // when necessary.<br> </div> Thu, 20 Mar 2014 12:34:15 +0000 A false midnight https://lwn.net/Articles/591149/ https://lwn.net/Articles/591149/ dakas <blockquote>and in all strongly-typed languages I know of the division operation doesn't change type.</blockquote> Algol and Pascal come to mind right away. Thu, 20 Mar 2014 08:58:56 +0000 A false midnight https://lwn.net/Articles/591006/ https://lwn.net/Articles/591006/ hummassa <div class="FormattedComment"> in C, "int/int -&gt; int";<br> <p> the whole "int/int -&gt; float" thing came from Pascal/Modula via Algol IIRC... they had "int DIV int -&gt; int" to compensate.<br> </div> Wed, 19 Mar 2014 00:29:49 +0000 A false midnight https://lwn.net/Articles/590994/ https://lwn.net/Articles/590994/ pboddie <div class="FormattedComment"> Yes, it's mostly something seen in C (and other languages) that became policy. Indeed, I imagine there's some group theory related elegance that appeals when defining such policy. Quite some time ago, of course, the decision to change this was made, but I can easily see people agitating for "int/int -&gt; decimal" and "int/int -&gt; fraction", and there are languages which have gone down those paths, too.<br> </div> Tue, 18 Mar 2014 20:23:01 +0000 A false midnight https://lwn.net/Articles/590993/ https://lwn.net/Articles/590993/ pboddie <p>I was explicitly responding to the assertion...</p> <blockquote>I think this is the same gotcha as the article shows.</blockquote> <p>...which, of course, it isn't.</p> <p>I'm very familiar with general complaints about Python - and more specifically, Python 2 - but most of those are regarded as concerning widely known and accepted, if not widely liked, behaviour. The topic of the article concerns something that divides the opinions even of those developing Python 3 as to whether the behaviour should be fixed or is even excusable.</p> Tue, 18 Mar 2014 20:19:17 +0000 This Is Why Booleans Must Be Booleans https://lwn.net/Articles/590954/ https://lwn.net/Articles/590954/ mathstuf <div class="FormattedComment"> I'm Haskell, you can also overload 'if' (with the -XExtensibleSyntax flag) for things like Maybe or Either. Luckily, flags can be set in a file so you don't have to chase the build file down to see what's going on.<br> </div> Tue, 18 Mar 2014 13:50:21 +0000 This Is Why Booleans Must Be Booleans https://lwn.net/Articles/590945/ https://lwn.net/Articles/590945/ ldo <P>This is why conditional expressions (as in if- and while- statements) <I>must be required</I> to be of Boolean type, and languages that don’t do this right are fundamentally flawed. <P>Languages that get this wrong, by allowing non-Boolean conditional expressions: C, C++, Perl, Python ... <P>Languages that got this right, with a sane treatment of Booleans as a subclass of enumerations as a subclass of discrete types: Pascal, Modula-2. <P>Language that gets this wrong, by its too-strict treatment of Booleans and enumerations generally: Java. Tue, 18 Mar 2014 04:49:51 +0000 A false midnight https://lwn.net/Articles/590943/ https://lwn.net/Articles/590943/ hummassa 3/4 has nothing to do with strong typing, but it is related to the type of <pre>operator/(int, int)</pre>... It's just like defining <pre>complex operator+(real r, imaginary i)</pre> and having <pre>auto c = 3 + im(4);</pre> yielding a complex "c". Tue, 18 Mar 2014 01:18:36 +0000 Affects Perl too https://lwn.net/Articles/590862/ https://lwn.net/Articles/590862/ mathstuf <div class="FormattedComment"> The only place I can think of for implicit str casts is Python2's print statement. The %s way warns at least IIRC.<br> <p> Casts for compound types makes sense since the internal type to parse out is very ambiguous. I would have thought bool would follow int since they're both POD-ish. It bit me in a config parser (it was our pre-existing format, so the stdlib module wasn't going to work) where I passed a function to use to cast the value out from the parse. You could use int, but anything else needed a wrapper function.<br> </div> Mon, 17 Mar 2014 13:13:03 +0000 A false midnight https://lwn.net/Articles/590861/ https://lwn.net/Articles/590861/ ikm <div class="FormattedComment"> <font class="QuotedText">&gt; Of course, the first example is C-like, while the second is what you'd expect from a non-typed language</font><br> <p> Python is strongly-typed. And I would actually expect 0 in the case of 3/4 since we're dividing two integers, not floats, and in all strongly-typed languages I know of the division operation doesn't change type.<br> </div> Mon, 17 Mar 2014 13:07:46 +0000 Affects Perl too https://lwn.net/Articles/590856/ https://lwn.net/Articles/590856/ intgr <div class="FormattedComment"> <font class="QuotedText">&gt; What contexts do?</font><br> <p> Actually I can't think of any from the top of my head. I just said "most" because I suspect there are a few edge cases in the standard library; Python's typing isn't always as strict as people make it out to be. Implicit casts to str are quite common, for example.<br> <p> <font class="QuotedText">&gt; bool('False') -&gt; True (ast.parse_literal is needed) whereas int('1') -&gt; 1</font><br> <p> Why do you think this should return False? It doesn't work this way for most other built-in types either, consider list('[1,2]'). The fact that it works for numeric types is a coincidence, because that's a useful way to represent numbers. It never was a goal for sometype(str(value_of_sometype)) return the original value again.<br> <p> I think using bool(x) to get the truth value of x makes lots of sense, just like list(iterable) does. <br> <p> <font class="QuotedText">&gt; there is no way to pass non-None arguments to str.split and get the no-arg behavior</font><br> <p> Agreed, that is inconsistent.<br> <p> </div> Mon, 17 Mar 2014 12:13:48 +0000 A false midnight https://lwn.net/Articles/590842/ https://lwn.net/Articles/590842/ kokada <div class="FormattedComment"> Well, OP asked for similar gotchas on Python 2.x language, not what is the reason of the problem (that is explained on the text anyway).<br> </div> Sun, 16 Mar 2014 15:31:16 +0000 Affects Perl too https://lwn.net/Articles/590829/ https://lwn.net/Articles/590829/ jtc <div class="FormattedComment"> "Therefore I consider saying anything along the lines of »0 is always/never supposed to be false« to be the wrong approach."<br> <p> I agree.<br> <p> "I fully agree that Boolean conversion for instances of a time-based classes ... is harmful. ..."<br> <p> We appear to be in 100% agreement. :-)<br> </div> Sun, 16 Mar 2014 05:43:02 +0000 Affects Perl too https://lwn.net/Articles/590814/ https://lwn.net/Articles/590814/ khim <p>My position is different: I'm Ok with multiple “false” values in statically-typed languages (if any single type can have exactly one “false” value) but to me it looks like crazy thing to do with dynamically typed languages!</p> <p>I mean: if I see something like <code>if (i/*int*/) …</code> or <code>if (p/*pointer*/) …</code> in C I <b>know</b> that there can be <b>exactly one</b> value which will be interepreted as false in this particular place. That is: <b>language</b> has many possible <code>false</code> values, but <b>each particular point</b> in a program can employ just one of them! I dislike tricks like <code>std::ios::operator bool</code> for that reason (yes, it's clever and sometimes it looks cool, but it erodes concept of “false” value).</p> <p>But with dynamically typed languages this justification flies right out of the window: you can pass around “real” “false” everywhere, why would you need surrogate ones? They will just complicate everything for no good reason!</p> <p>Perl, python, php - they all adopted C concept of “zero of any type is “false”” without thinking when they had no need for that kludge! This is a pity, really, but I'm afraid we are stuck with this decision: such change when applied to popular types will just break way too many programs.</p> Sat, 15 Mar 2014 15:03:24 +0000 A false midnight https://lwn.net/Articles/590809/ https://lwn.net/Articles/590809/ edomaur <div class="FormattedComment"> Well, you can use the six library, there is some tools for that very case :<br> <a href="http://pythonhosted.org/six/#six.with_metaclass">http://pythonhosted.org/six/#six.with_metaclass</a><br> </div> Sat, 15 Mar 2014 12:58:21 +0000 Affects Perl too https://lwn.net/Articles/590804/ https://lwn.net/Articles/590804/ peter-b <div class="FormattedComment"> I found myself thinking about this last night -- I quite like languages where there is one and only one "false" value. Like Scheme:<br> <p> <font class="QuotedText">&gt; Of all the standard Scheme values, only #f counts as false in conditional expressions. Except for #f, all standard Scheme values, including #t, pairs, the empty list, symbols, numbers, strings, vectors, and procedures, count as true.</font><br> <p> The reason I like this is that it removes all uncertainty about what, exactly, a conditional expression is testing on.<br> </div> Sat, 15 Mar 2014 10:35:40 +0000 Affects Perl too https://lwn.net/Articles/590803/ https://lwn.net/Articles/590803/ mbunkus <div class="FormattedComment"> Almost each and every language has its own rules which values it considers false in Boolean contexts. They're varied too much to approach remembering them with logic. You just have to learn them by heart.<br> <p> C: the value 0; C++: 0 / nullptr (C++11 and newer) or depending on the class if operator bool is overloaded; Perl: undef / () / 0 / "0" (but not "0E0" or other strings which evaluate to 0 if taken in a numeric context) or depending on the class if bool conversion is overloaded; Lisp: depending on the Lisp dialect in question, somethings nil and the empty list (), sometimes only nil, sometimes nil and the Boolean type false as in Clojure); Ruby: nil and the Boolean false…<br> <p> Therefore I consider saying anything along the lines of »0 is always/never supposed to be false« to be the wrong approach.<br> <p> I fully agree that Boolean conversion for instances of a time-based classes (no matter if it's just the time component or a date as well or even both of them) is harmful. Remembering special rules like this leads to mistakes, it always does. There are useful cases for this kind of overloading, but they're rare: e.g. a TriBool class representing True/False/Unknown.<br> </div> Sat, 15 Mar 2014 08:30:16 +0000 A false midnight https://lwn.net/Articles/590791/ https://lwn.net/Articles/590791/ fandingo <div class="FormattedComment"> I pretty much entirely agree with you, so don't take these comments as a vigorous rebuttal. <br> <p> <font class="QuotedText">&gt; But a date cannot really have a 0 value (since, as you implied, there is no 0th day of year 0 [disregarding whether there can actually be a year 0] and no 0th month - so you can never have a date [year/month/day] that evaluates to 0) and thus it's appropriate for a date to never evaluate to false. (This is not my argument, but one I think some people would make.)</font><br> <p> datetime.MINYEAR could be defined as 0, and I'm actually a little surprised that it is 1 because that seems incredibly arbitrary. As for having zero months and days, it's about about how you represent it. Months kind of naturally map this way if you have a list that represents the month names because 0-indexed makes that easier. Anyways, whether a month is zero-indexed or a time is tracked in a 12-hour AM/PM representation doesn't matter. That's the internal state of the object, which shouldn't leak out to users, but it does in the form of __bool__ for datetime.time.<br> <p> <font class="QuotedText">&gt; To address that last argument, let me bring in the Baby object from my earlier post. You might have Baby == 0 (AKA baby.age == 0) and you might think of that as false. But why?</font><br> <p> It's obvious that some people (like Tim Peters) think this sort of behavior makes sense, but I would never write a class that did something like that. As you say, it's horribly unintuitive. If I read the line<br> <p> if not my_baby:<br> <p> there is a 0% that I would ever think that my_baby would be anything other than True or None (well, False if used as a sentinel but never due to __bool__). (And, I know that many people get upset of not using the pedantic "if my_baby is not None," but there's no reason for that if the object has no business being falsey.)<br> <p> <font class="QuotedText">&gt; It exists [otherwise it would be null/void and not evaluate to anything :-)] - doesn't existence imply truth?</font><br> <p> I don't agree with this line of reasoning, which you go onto explain in more detail. The problem is that you're basically defining falsey behavior as NameError. That's actually an interesting thought where the sentinel None could be eliminated and a wider use of NameError used, but it would require substantial changes to Python and the development process. (You'd have to stop functions from implicitly returning None, get people to use exception handling far more, and so on.)<br> <p> <font class="QuotedText">&gt; Instead of if (not currenttime), the code should read, for example: if (currenttime.is_midnight). IMO, this is clearer and much less error-prone. It's less likely that someone changing the code will make a mistake because the intent of the if ... clause wasn't clear to him. (I suppose you could say this is a long-winded way of saying what someone else suggested earlier: Make the code readable.)</font><br> <p> I take it a step further and believe that stdlib classes have no business implementing this sort of specialized behavior.<br> <p> if currenttime == datetime.time(0, 0, 0):<br> <p> That seems like unambiguously the correct answer. There are no surprises for the author or any subsequent readers.<br> <p> <font class="QuotedText">&gt; For the [informal script] purpose it perhaps makes sense to allow, e.g., 0 =&gt; false; but for major projects I think it might not be a good idea.</font><br> <p> Yet, aren't the informal script writers the *least* likely to know about this behavior and also have the least tested code that is more likely to fall victim to unintentionally falsey behavior? Nick Coghlan said it best in the original article:<br> <p> <font class="QuotedText">&gt;&gt; [...]having a caveat in your documentation isn't going to help, because people aren't even going to think to ask the question.</font><br> <p> </div> Sat, 15 Mar 2014 00:22:16 +0000 Affects Perl too https://lwn.net/Articles/590781/ https://lwn.net/Articles/590781/ jtc <div class="FormattedComment"> "Therefore your comparison is a bit besides the point."<br> <p> The point of my post was simply to point out that bracher's example compared a DateTime in perl with a Time in python - two different classes with different semantics - and thus not a valid comparison. I wasn't addressing the article - at least directly.<br> <p> To make this point only my first sentence was needed ("The object you're testing ... not equivalent"). The rest was a - perhaps unnecessary - elaboration of the types involved with respect to DateTimes and Times in python vs perl (and yes, hour, minute, and second in perl evaluate to integers) and how, when it comes to Boolean evaluation, this leads to complexity and possible confusion. I'll grant that this is off-topic from the article.<br> <p> On the other hand, I think it might be relevant (to the article) to point out that such complexity and confusion that result from regarding some instances of zero-ness as 'false' and other instances as 'not false' can cause problems that lead to defects and that it's wise not to use this idiom, at least for large projects. (Obviously, this puts me on the side of those arguing for midnight not evaluating to false in python, although I go even further to say "don't allow such an idiom in the code") The best way to avoid the idiom is to not allow it in the language (as is the case in statically-typed languages like Java [though not the case in C or C++]), but that's probably not practical for perl or python (or ruby, where 0 is true), since much existing code, obviously, uses these idioms. In that case all you can do, I suppose, is follow a coding standard that outlaws such comparisons (and perhaps use a lint-like tool to find violations).<br> <p> (I elaborated on this point a bit more in another post:<br> <a href="http://lwn.net/Articles/590778/">http://lwn.net/Articles/590778/</a> )<br> <p> </div> Fri, 14 Mar 2014 22:44:51 +0000 A false midnight https://lwn.net/Articles/590778/ https://lwn.net/Articles/590778/ jtc <div class="FormattedComment"> Actually, I agree with your main point and wasn't meaning to argue against it. I didn't make it clear I was only disagreeing with the side issue that the start of something should evaluate to false. (And it was clear to me you weren't stating this proposition was your view.)<br> <p> As far as your main point, I think your example/argument of dates never evaluating to false while times sometimes do is valid. On the other hand, someone might argue that something that can have a 0 value (such as a time) should be false when it's 0. But a date cannot really have a 0 value (since, as you implied, there is no 0th day of year 0 [disregarding whether there can actually be a year 0] and no 0th month - so you can never have a date [year/month/day] that evaluates to 0) and thus it's appropriate for a date to never evaluate to false. (This is not my argument, but one I think some people would make.)<br> <p> To address that last argument, let me bring in the Baby object from my earlier post. You might have Baby == 0 (AKA baby.age == 0) and you might think of that as false. But why? What does false mean? It exists [otherwise it would be null/void and not evaluate to anything :-)] - doesn't existence imply truth?<br> <p> I suppose I'm actually generalizing the argument - partly because some people will object to your argument for the reason I gave. I suggest that for a system that will be around for years and will be modified and extended, Boolean checks should be explicit (i.e., there should be no auto-conversion of a type into Boolean) - Instead of if (not currenttime), the code should read, for example: if (currenttime.is_midnight). IMO, this is clearer and much less error-prone. It's less likely that someone changing the code will make a mistake because the intent of the if ... clause wasn't clear to him. (I suppose you could say this is a long-winded way of saying what someone else suggested earlier: Make the code readable.)<br> <p> I think part of the problem is the dual nature of languages such as perl and python (and, to some extent, ruby) - One purpose of these languages is to allow writing informal scripts (usually short and quick) that take care of an immediate need. The other is to develop applications, many of which will be quite large and will be around for a long time, and will be used by many people. For the first purpose it perhaps makes sense to allow, e.g., 0 =&gt; false; but for major projects I think it might not be a good idea.<br> <p> </div> Fri, 14 Mar 2014 21:24:31 +0000 Affects Perl too https://lwn.net/Articles/590775/ https://lwn.net/Articles/590775/ mathstuf <div class="FormattedComment"> <font class="QuotedText">&gt; most contexts there is no implicit casting from str to int.</font><br> <p> What contexts do?<br> <p> Anyways, while we're in Python's deeper, darker corners, some things I really dislike about Python:<br> <p> bool('False') -&gt; True (ast.parse_literal is needed) whereas int('1') -&gt; 1<br> str.split() is approximately filter(len, split(' ')) (there is no way to pass non-None arguments to str.split and get the no-arg behavior)<br> </div> Fri, 14 Mar 2014 19:21:36 +0000 A false midnight https://lwn.net/Articles/590774/ https://lwn.net/Articles/590774/ mathstuf <div class="FormattedComment"> How do you do metaclasses supporting both? Python3's way is a syntax error in Python2 and Python2's way is ignored in Python3.<br> </div> Fri, 14 Mar 2014 19:16:03 +0000