- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
This form of ternaries is not unique to Python, VHDL has a similar construct
Admin
The language was named after the Monty Python Flying Circus who specialize in satirical WTF comedy. Is it really that surprising when the code produced in it resembles the same?
Admin
"Each rule is identified by a number, which does a wonderful job making the code more cryptic. Are there at least 241 rules, or is the numbering sparse? What does rule 241 represent? Absolutely no idea."
Every good Ferengi knows the rules and numbers by heart (https://memory-beta.fandom.com/wiki/Ferengi_Rules_of_Acquisition). Hmm, number 241 is missing on that page, but now we see it must be about illusion of choice in marketing or such.
Admin
So python thinks that the
true
condition is the more likely one? I prefer clarity of the condition over having to guess which outcome is more likely such that I can formulate the condition accordingly.It could also be that the
get
call has a side effect, but that leads to more WTFery.Final nitpick: why is this not "Representative Line"?
Admin
This has already been a feature in Algol. (Compare the Revised Report on the Algorithmic Language Algol 60, 4.5 Conditional statements.)
Admin
Correction: it's actually defined in "3.3. Arithmetic expressions", which may include a Boolean expression.
And, if you thought Python was bad, have a look at this Algol beauty provided in the Revised Report ("3.4. Boolean expressions"):
(Any if-else pair evaluates to a value, and you can nest them, as deep as you want.)
Admin
There's one advantage to the current code: letting
get
raise (throw) an error (exception). If "dead code removal" were applied here to collapse the ternary toFalse
, the error would never get raised. Of course, no programmer should be expecting that error that would prevent dead code removal, but this website never fails to prove us wrong.Admin
Pythonic way is synonymous with "write semi-crazy crap on purpose".
No thanks.
Admin
Fun fact: there exists a language with "no" reserved words: IBM's PL/I from the mid-60s. The idea was that new keywords could be added to the language in the future without invalidating old programs. This has the "neat" benefit that this monstrosity is valid syntax (correct me if the
ELIF
/ENDIF
keywords are wrong):That should be read as (in C# where the "at sign" allows using keywords as variable names):
Admin
*fumes in one-way-to-do-it*
Python's ternary expression is one of the weird choices of python that keep me annoyed over what is otherwise my least disliked language for actually getting things done.
Throughout python, you usually have a pattern of “evaluate in order written”. You have
or with loops
i.e.
A
is evaluated beforeB
. But when you go to expressions, it is suddenly reversed.This reversal becomes even more obnoxious, when you want to do more complex things.
so far clear, but what if you use the same order in a generator or list expression?
Okay, nice so far. And what, if it is a nested list?
Due to this, the "flat" generator expression is always trial-and-error for me.
Additionally, it undermines intellisense features of IDEs; In loop expressions you write the item before the source, so by the time you have written
the IDE cannot yet decide what type i will be.
I would much have preferred if Python had opted for expressions of the form
but history is strange.
I've recently also learned that (mostly for historical reasons, see PEP 285 – Adding a bool type (Python 2.3)) Python draws a surprisingly fuzzy line between booleans and integers.
Admin
I guess, this is one of the Wittgensteinian influences on PL/I. (The Vienna group did engage in some Wittgenstein studies, and this is pretty much a language game, AKA Sprachspiel, where meaning is derived from use.)
Admin
There is another one. The following is valid Fortran:
In Fortran, keywords are not keywords, unless they are in places, where they are expected. Otherwise they just ‘degrade’ to an identifier. Curiously though, this is not entirely consistent; The following would be incorrect syntax:
with error messages from as
Addendum 2023-05-04 07:51: ~~from as~~ such as
Admin
Oh, don't forget about Smalltalk. Theoretically it doesn't have any reserved words; practically the compiler optimizes "nil" and "==", but the rest can be redefined. Even true and false are just global constants.
So you can write: true become: false
... and your whole system will stop working immediately.
Admin
Lisp is the same way. 1 is not really the integer 1, it's a function that returns the integer 1. And Lisp lets you redefine functions.
Admin
I've been writing Python for quite a while now, and I've never seen anyone do this.
Admin
I have. And a lot of other things. This includes an unfortunate developer who got squished by a giant foot.
Admin
Not in any Lisp dialect I've ever used (MacLisp, Common Lisp, Scheme, Emacs Lisp to name a few).
Functions are named by symbols. While it's possible to create a symbol whose name is a number, you have to use escaping to refer to it, by writing either
|1|
or\1
. If you just write1
by itself, it's parsed as an integer and you can't use it as a function name.is not valid code.
Admin
get()
doesn't raise an exception when the key isn't found, it returns a default value (the second argument, which defaults toNone
). The exception is raised when you use subscript notation,rules[241]
.The author of the code made a classic beginner WTF, writing
something != X or Y
when they meansomething not in (X ,Y)
Admin
Well, sure, stupid programmers do stupid things. That still doesn't make it the thing you're supposed to do.
I definitely agree that the order in Python's ternary is weird, though.
Admin
Ref
What does likelihood of being true or false have to do with the structure of the statement? Construct your condition for clarity and put the true and false results in the syntactically required locations. Anything else is paying foolish attention to low-level concerns from within a high level language. Don't do that.
Admin
Yes and it uses the sane ordering of condition and values, so that the expression would be written:
welcome_mt := (rules get: 241) ~= 'yes' ifTrue: [ false ] ifFalse: [ false ]
and it would be immediately obvious how stupid and redundant it is.
Smalltalk is the only language I've seen that doesn't do things in an ass-backwards way, and yet no one uses it.
Admin
The real WTF here is the assumption that just because the rule ID happens to contain digit, all rules IDs are numbers.
Clearly, this is a shopping cart system, and this rule is the “2 items for the price of 1” rule, aka “2-4-1”, or just “241” to avoid looking like maths.
Other rules in the system probably include “BOGOF”, “342” and “1/2OFF”
Admin
Python is way more problematic than most languages though. I mean, look at its main "feature", significant whitespace. It is literally a violation of the principal of separation of concerns built into the language.
Admin
Python's ternary is not the real WTF.
The Real WTF is that Python's ternary is a NEW thing since version 3. Before, the author had flatly refused to add one, which led folks to write this Pythonic monstrous workaround:
a and b or c
Which reads as (a ? b : c). And a lot of subtle "hilarity ensues" edge cases. Ironically this thing has the right order.
Admin
This is a very narrow view of python. Have you actually done any working in the language of python? Here is a non-pythonic way to write a loop.
for i in range(10): print(i)
Here is the same loop, but in a pythonic way.
print([i for i in range(10)])
Clearly we are all opinionated python programmers.
Admin
Sorry, but the spacing is making it easier to reading.
Admin
Uhm... what? Those are two different loops with different outputs, and both look perfectly pythonic to me.
Code formatters fulfill the same job though. Just because there are beginners and (for whatever reason) lecturers that do bad code formatting doesn't make it a good idea to make it compulsory.
It's also not like it is a complete solution. Python prescribes indenting for block syntax, which essentially only solves the
vs
choice. I haven't really seen anything else in the wild, except as a joke or outlier. But just as you could quarrel about
{\n
vs\n{
, you can quarrel about whether to put an empty line at the end of a block (to make it more visually distinct) or not, and when.It also doesn't do anything to help with formatting of multi-line expressions (e.g. nested function calls or (nested) list/dict literals, or just long expressions/statements.
It also sabotages some useful syntax. For instance, an equivalent of Javascript's
is more limited, because it doesn't allow for fully functional code blocks, but only for lambda expressions, where neither raising exceptions nor logging statements work well. Instead you have to do something more awkward like
That assumes having some sort of "piping" library involved though. With pure python it would be
<!-- to be continued -->
Admin
which I consider significantly less clear, even after years of using Python. Note that my JavaScript expertise is rather basic, I've never used it nearly on the scale I've used Python.
Additionally, this dichotomy of lambda vs makes refactoring often more painful then necessary, when you have to switch from a lambda expression to a named (local?) function, which often requires rewriting the structure of the code, rather than just the implementation details. Also makes for less clear diffs.
Speaking of diffs, another point where significant whitespace can be a pain :/