4 ms·
It's not just a tweak to the parser, and it does have to do with the type system, but you're right that it's not about static typing. The issue is that there a
by azernik 12y ago
It's not just a tweak to the parser, and it does have to do with the type system, but you're right that it's not about static typing.
The issue is that there are languages (like C) where typing is static but weak, so e.g. booleans are also integers and can have integer operations like '>' applied to them. In other words, the problem is that in C True == 1 and 1 > 2 is a valid expression. In Python, which has strong(er) types, this expression can have an unambiguous meaning if you want to add the feature to your parser.
- dllthomas 12y agoYou can implement it entirely in the parser if you can avoid name capture - it may or may not be implemented entirely as a tweak to the parser in practice, but it's fundamentally a syntactic thing. Your discussion of types here is all wrong - it's true that C treats booleans as if they were integers, but Python does, too: >>> (3 > 4) < 2 True >>> 3 > 4 < 2 False >>> 3 > (4 < 2) True It has nothing to do with types.
- myg204 12y agoI think the comparison is more readable as (here with the >>> of the python shell): >>> 0 < x < 1 as opposed to >>> 1 > x > 0 Following the number line and placing x there is nicer IMHO. Other than that, very nice trick.
- dllthomas 12y agoIn terms of coding style, I agree with you that following the number line is usually going to be clearest. I think there might be some situations where descending is better than ascending, but certainly both are radically better than what I did above (low > high < lower). As an example for what I was specifically trying to show here, though, that doesn't let me distinguish things quite as clearly. I believe that (a < x < b) gives the same value as at least one of (a < x) and (x < b) for any value of x. x < a: a < x gives false a < x < b gives false a < x < b: everything gives true b < x: x < b gives false a < x < b gives false So there's no way to get both of the parenthesized versions to disagree with the unparenthesized version in a single example.
- azernik 12y agoOh fun. That is not a nice associativity weirdness to have to deal with.
- filmor 12y agoIn fact, Python just has a non-binary AST with regard to operators, i.e. the expression "a < b < c" is not parsed as CompOp([CompOp([a, b], <), c], <) but instead as CompOp([a, b, c], [<, <]). The same holds by the way for Boolean operators, "a and b and c" is represented as BoolOp([a, b, c], [and, and]). See https://docs.python.org/3/library/ast.html#abstract-grammar https://docs.python.org/3/library/ast.html#abstract-grammar for details.
- TorKlingberg 12y agoBooleans are integers in Python too: >>> True + 0 1
- AlexandrB 12y agoIt would be more correct to say that the "bool" type implements an "__int__" method for conversion to an integer, but the types are actually distinct: >>> type(True) <type 'bool'> >>> type(1) <type 'int'> Edit: oops, I'm wrong. "bool" also inherits from "int": http://stackoverflow.com/questions/8169001/why-is-bool-a-subclass-of-int http://stackoverflow.com/questions/8169001/why-is-bool-a-sub...
- colanderman 12y agoYes, you really can just tweak the parser; just (a) don't have a rule allowing comparisons to appear as children of other comparisons, and (b) add a rule that permits chains of comparisons. Types have zilch to do with this. It's 100% a tweak to the parser.
- dllthomas 12y agoYou are absolutely correct that it could be implemented as 100% a tweak to the parser. Assuming filmor is correct, in practice as it happens to be implemented in the Python code base it is not 100% a tweak to the parser - changing the structure of the produced AST means tweaks down the line. I think the change to the parser is still the most meaningful piece, though, even there.
- dllthomas 12y agoInterestingly, you can do it with types and no parser help: https://gist.github.com/dlthomas/d18d475068f23584d473#file-chained-hs https://gist.github.com/dlthomas/d18d475068f23584d473#file-c... Obviously, that's not what's going on in Python... It could be smoother and more generic if Haskell permitted specifying defaulting for non-numeric types. But it does support things like: *Main> 2 < 3 < 4 < 4 :: Bool False *Main> 2 < 3 < 4 <= 4 :: Bool True *Main> 2 <= 3 < 4 <= 4 :: Bool True *Main> 2 <= 3 > 4 <= 4 :: Bool False *Main> 2 <= 6 > 4 <= 4 :: Bool True