- Feature Articles
- CodeSOD
-
Error'd
- Most Recent Articles
- Secret Horror
- Not Impossible
- Monkeys
- Killing Time
- Hypersensitive
- Infallabella
- Doubled Daniel
- It Figures
- 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
There are a few keywords in the loose sense R3D3 describes:
self
super
currentContext
more surprising to me, when I started, was the fact that you can even re-define elements which are often regarded syntax: +,-,*,/,<,<< and many more, yes even "==". Most compilers implement some heuristics when to bypass the optimizations.
Some things you cannot override without patching the compiler are:
:=,;,[,],#
But even patching the complier would not be out-of-the question. It was done for Squeak upon my request for "isNil" to be optimized the same way "ifTrue" was, i.e. performing the same as "== nil".
Admin
And there's 'match' now? Which is surely just admitting defeat and adding a switch case but pretending it's something else
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
The important thing here is that "get" is an overloaded method on the "rules" object, which when presented with "241" causes a database restart.
Admin
Python does have a switch statement since 3.10, it is called match case.
And the example you showed? I don't think anyone would ever think of that as pythonic.
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
Along the lines of code smells, can we talk about punctuation smells? In many, many articles on this site, including multiple times in this one, there is poor usage of what should be a dash, and it limps along with limited legibility but it stinks. (As with many bad coding practices, I used to be guilty of it too, and then I graduated high school.) And there's a better, more legible, traditional way (plus a few better compromises). It makes sense that this site and its authors should want to learn it. Reasonable analogy, huh?
A single hyphen after a word and then a space is not a dash. It looks silly and unbalanced and it does not help guide the reader. (A single hyphen with no spaces is even worse, of course, but you don't seem to do that much.) For the usage typical to these articles, setting off a parenthetical remark or abruptly switching topic, an em dash (—) with no spaces, or in typesetting very thin spaces, is best. There's an HTML entity for it, too. But if one wants to stay within a basic character set, a -- (usually without spaces), or even a - spaced on both sides, will do, and will be much more readable. Sometimes, the half-spaced hyphens seen here would work better as colons, with the same spacing, usually after a phrase introducing a longer explanation.
Admin
My point being, if a human reads the python line, they would probably assume that the true case is the most important bit. Then they read the condition and have to rearrange their mental model to patch in the condition.
But of course, real python programmers do not have that problem. /s
Admin
| (correct me if the ELIF/ENDIF keywords are wrong):
Here is the syntactically correct PL/I code that corresponds to the C code exhibited:
DECLARE (IF, THEN, ELIF, ELSE, ENDIF) BINARY FIXED(31); IF IF = THEN THEN THEN = ELIF; ELSE IF ELIF = THEN THEN THEN = ELSE; ELSE ELSE = ENDIF;
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
Well, I've done that, but with the experience of a Senile Software Engineer, I now think of it as a lazy ad-hoc command factory pattern and not a kludge for a missing switch statement.
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
I suspect this is a misunderstanding on the writer's part of how "or" works.
I think they intended "if [expr] != 'yes' or None" to mean "if expr is not either 'yes' or None".
So they were thinking "if [expr] != ('yes' or None)", unaware that Python would read this as "(expr != yes) or None".
Admin
No it does not. What forced spacing does is force you to write programs that are completely unreadable. Anyone who has had to work with actual real production code and not quick scripts and hobby code will attest to that.
In order for code to be readable and understandable thew engineer writing it needs to be able to insert whitespace, new lines, indentation and other forms of formatting freely so as to create a properly flowing and visually comprehensible form.
Sadly I can't give you examples as this place does not allow code formatting.
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 :/
Admin
And of course there is the simple issue of long lines of code.
We all know that expressive function and variable names which are the cornerstone of all good self documenting code. You know, AbstractWidgetMakerFactory.MakeWidgetMaker().MakeWidget(widgetTemplateName). That sort of stuff.
Try writing code like that without being able to break it into lines at will for readability and see where that takes you.
Furthermore even without good naming practices just regular code can, if you are unable to freely format it pose a serous usability issue to a lot of people. I know plenty of developers, who thanks to spending years or decades in front of a monitor (who would have imagined) have less than perfect eyesight. These people need to zoom their font size up to 12, 14 or some times even more in order to read.
And for them the ability to freely split code into lines freely is the difference between being forced to constantly scroll sideways and being able to work freely.
Pythons use of whitespace as a syntactic element in its grammar is the programming equivalent of one of those training walkers you can buy for babies. Great if you are just learning to walk. But constraining and painful if you want to actually get anywhere.
Admin
I have seen some C programmers write python code returning 0 or -1 from functions and effectively don't test the return value either. So we don't know whether the function succeeded or failed in what it originally meant to do.
Another gem
Admin
My God: I actually programmed in PL/1 on IBM Series 60. How old am I?!? I didn't know about this feature. I remember the 20 minutes to compile 100 lines of code, the keyboard's relay and its loud "click", and the velociraptors biting my feet...