9 ms·
One of the comments lays out why I probably never use things like this: And this is exactly why I tend to wrap compound logical comparisons in parens, I simply
by stinos 7y ago
One of the comments lays out why I probably never use things like this:
And this is exactly why I tend to wrap compound logical comparisons in parens, I simply can't remember the syntax across all the languages I use, and it's not worth the risk of leaving them off and having unexpected behavior
Apart from unexpected behavior it is also about readability: with parentheses in place you can just read left-to-right and the parsing overhead is minimal. Without them though, you have to read almost everything first, parse what is there, figure out what comes first (and hope you remembred it correctly), then read again to get a mental image of what is actually going on.
- userbinator 7y agoOn the other hand, Python is the only language I've used which has this special-case parsing. In all others, a < b < c would be parsed as ((a < b) < c) which may or may not be a type error, but it's consistent with the other binary operators.
- stinos 7y agoThat actually proves my point. I'm not really good in learning certain facts by heart so if I see a < b < c it is going to take multiple seconds, likely followed by an internet search so add a couple of minutes to that, before I can be 100% sure what it does. I mean, I know what precedence is and I'd probably assume it would be (a < b) < c but that's not going to cut it.
- aktuel 7y agoJust program in assembler then. Honestly, Python's way is the only sane way to parse this. This is how a human who never programmed before with some knowledge of math would understand it. Everyone's else mind is just corrupted by broken legacy languages.
- xyproto 7y agoMath notation is just one of many possible notations, though. And math notation is not static throughout history.
- aktuel 7y agoTrue. But the syntax of almost all other languages are derived from the same basic math syntax we use commonly for at least since programming languages are a thing.
- maest 7y agoEven if Python's way was the only sane way of doing it (view which, btw, denotes having narrow experience with programming languages), that's irrelevant. GP's point was that different languages use different rules so, unless you use brackets, you won't easily know which precedence rules get applied.
- Retric 7y agoPython’s edge cases are just as odd as every other language >>> a=16 >>> a*a is a*a True >>> a=17 >>> a*a is a*a False “is”, “==“, and “=“ are all very different and none of them match their mathematical equivalents very well.
- dhosek 7y agoNot really familiar with Python. Do you know why the second statement evaluates as false?
- mkl 7y agoSmall integer caching: https://wsvincent.com/python-wat-integer-cache/ https://wsvincent.com/python-wat-integer-cache/ The objects for small integers are built-in and static, but 17^2 is too big, and so new integer objects are created when the expressions are evaluated. "is" checks if two expressions represent the same object in memory. "==" checks for equality of values.
- xen0 7y agoCPython keeps an array for "small value" integers (I think in the range [-5, 256]). So when Python wants 256, it'll give you a reference to the existing object. Larger numbers require a brand new object.
- h8hawk 7y ago`is` is identity comparison and in python everything is "object". It check if two variable refer to same object (location in memory) or not. So you should not expect that `a is b` for `a=1.2 , b=1.2` be true. In this case actually first expression returned True is weird. because 0-256 objects are cached and every instance of them refer to same object.
- apricot 7y agoI sometimes teach programming to beginners who have some knowledge of math. A common mistake they make is to write compound conditionals like this: if a == 2 or 3: do stuff because that's how they would write it in math. Does that mean Python is broken and should support that construct as well?
- edflsafoiewq 7y agoI believe COBOL supports this.
- shkkmo 7y agoWhen you use a tricky language feature to improve readability, you can just add a comment to the link some piece of documentation for that behavior. It is still a trade-off, but it saves a bit of time and whenever I come across a place where past me did this, I am always appreciative.
- stinos 7y agoDepends. For obscure behavior features, ok, for 'language features' I'm probably still going to pass. Because in this example case that would come down do # See stackoverflow/highlyupvoted/wtf/does/python/do/here # This is the same as (a < b) < c. x = a < b < c whih is not clearer, not easier to parse and not faster to read and harder to maintain (leads to rot easily when variable names change) than the non-ambiguous other choice.
- shkkmo 7y agoI would have skipped that second line and just left the line with the documentation link. If you are going to provide the equivalent code in a comment, you might as well just use the equivalent code.
- geocar 7y ago> In all others, a < b < c would be parsed as ((a < b) < c) which may or may not be a type error, but it's consistent with the other binary operators. In APLish languages, it's (a<(b<c)).
- mFixman 7y agoThe only correct way to parse `a < b < c` for numbers is throwing a type error. Python comes second for source code niceness, allowing you to compare numbers to booleans is common and shouldn't be.
- sushimako 7y agoIn Clojure, and I assume other lisps as well, you can use the < operator in the same fashion. By merit of prefix notation it's also unambiguous regarding precedence. user=> (< 1 2 3) true
- tfigment 7y agoI'll be honest that I'm not a Clojure user, even with context I have no idea read that. Like every other language you have to be trained to read it correctly and is not intuitively obvious to everyone.
- bjoli 7y agoAll maths functions where it makes sense take arbitrarily many arguments. (+ 1 2 3) = 6. (< 1 2 3) = true. Everything in function position (directly after an opening paren) is either a function you want to apply or a macro you want to expand, except in a select few forms, such as binding forms and conditionals. The syntax of scheme is remarkably simple once you know the basics. I have programmed python for about 20 years, and I still do stupid mistakes. I grooked all the r6rs scheme syntax in 20 minutes, except for (do ...) which somehow never sticks. It is also rarely used. I have tried to evangelize scheme enough to know some people just don't like it, but for me it instantly clicked.
- edflsafoiewq 7y ago+ and = are pretty obvious but it can still be confusing. Take not=. Does (not= x y z) mean adjacent numbers are disequal (x≠y≠z, by analogy to + and =)? Or that no two numbers are equal? Or that at least two numbers are disequal? Different lisps pick different meanings.
- bjoli 6y agoWhich lisps? I think I have only ever seen that in clojure (thinking it was a bad idea), and clojure seems scared of parentheses. (not (equal? x y z)) is clearer, but suffers from the same drawback as your question. The problem I think is that not= returns true as long as any elements are non-equal, which means it is not analogous to +. I can't speak for clojure, but this is in line with all equality predicates in scheme, negated or not. A predicate that checked if any neighbours are not equal would in true scheme spirit probably be called not-any-neighbour-equal? :)
- h8hawk 7y agoJulia also do this: julia> 2<3<4 true
- tomp 7y agoPython follows math. Other languages made up something weird.
- arcticbull 7y agoSounds like “is” is lower precedence than ==. Nothing to see here folks, move along?
- tromp 7y agoNo; it's not about precedence at all. It's about semantics of chained comparisons, which is not what you'd expect in Python.
- aktuel 7y agoThe syntax works exactly like it's supposed to. "is" is an alias for "==". This kind of chained comparison makes code much more readable. This contrived example which I never encountered as a practical issue not withstanding.
- wrboyce 7y ago“==“ is not an alias of “is”, they behave quite differently.
- scaredginger 7y agoI think you need to brush up on Python... >>> x = 25 * 37 >>> y = 25 * 37 >>> x is y False >>> x == y True From my understanding, '==' checks for equality and 'is' checks that the variables reference the same address.
- aktuel 7y agoOK this is truly weird: >>> a=16 >>> a*a is a*a True >>> a=17 >>> a*a is a*a False WTF
- chrismorgan 7y agoCPython interns the integers between -5 and 256. See https://stackoverflow.com/questions/306313/is-operator-behaves-unexpectedly-with-integers https://stackoverflow.com/questions/306313/is-operator-behav... for some discussion and further related links.
- dec0dedab0de 7y agoWhen I have very complex logic I like to give each step its own variable. It makes it read like English. To be honest I only actually only do this when Im working on old code and find myself trying to remember how something works.
- paulryanrogers 7y agoIME the improvement to readability is worth the cost of a few extra assignments.
- Avamander 7y agoIn the cases where they aren't worth it, you're hopefully also using a language that gets compiled and they're just optimized out.
- ghaff 7y agoWhether it's computer languages or human ones, as soon as you get into a discussion about the correct parsing of a statement, you've lost and need to rewrite in a way that's unambiguous. Too many people pride themselves on knowing more or less obscure rules and, honestly, no one else cares.
- collyw 7y agoThis. I got asked an interview question that involved writing two list comprehensions in python in an interview. The guy then asked if I could do the same without the intermediate variable - basically nesting them. I had a mental block for a bit before I realised how simple the task was. It just that I would never think to nest list comprehensions because I find it horribly unreadble.
- rohan1024 7y agoI was a Java developer for more than 4 years at the beginning of my career. I was more of application developer than language expert so I did not know about nooks and crannies of the language. But that is exactly what was being asked in interviews and was never able to crack those interviews. I liked Go and used to work on it in my personal time. Go's way of doing things is usually one way so there are not many things you have to remember about language. I applied for a job of Go and I landed that one. Of course, at that time very few Go developers were there in market so that could be a good reason for me landing that job as well.
- kwhitefoot 7y ago> if I could do the same without the intermediate variable I'm glad I never had to go through such ridiculous hoops to get a job. If I had I might have been inclined to say "Yes I could but I wouldn't do it because it would be unmaintainable." Real application programming isn't about being concise it's about being cost effective. Sometimes conciseness achieves that end often it does not. Having a well named intermediate variable can help document what is happening so that the poor sod who has to fix a bug in or extend your code two years later doesn't have to spend an hour deciphering your code to apply a two minute fix. That poor sod might be the very same person who wrote it.
- ulucs 7y agoSomething I really like in k/q is that operators have no precedence and everything is executed right to left. To take a "fast" 8th power you can just do c*c:s*s:x*x with no ambiguity of parsing whatsoever.