- 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
And I've always wondered why C, C++, and Java only allow constant expressions in their case labels... thanks. Now I know why.
Admin
The logic here is wrong - if either of foo and bar is true (not equal to false), the whole first case is false, which means that the result should be 'Foo | Bar' (or something like that). This also means that the code will never reach the last case.
Admin
This should never have not occurred. The inverted logic is not contrarian to how design patterns are never not implemented.
Admin
And DeMorgan would be so proud!
Admin
I remember seeing a feature request to add support for this sort of thing, and the considered response “No. Freaking. Way.”
Admin
No, that is correct.
Admin
Someone (lots of someones?) hasn't read Brooks, I guess. "Adding people to a late software project makes it later."
This, I'd say, is the core WTF in this article.
Admin
Back in the Olden Dayes of assembler you'd often see negative logic in the "if" part so you could branch on false around the code to be executed if true and fall through into the true-case code if true. So if now was then I'd bet we're seeing an assembler dev writing assembler logic in C#, JS, or whatever this is. But here in 2020 that's vanishingly unlikely.
Must just be goober WTFery then.
Another late thought: maybe they translated this directly from the requirements which are expressed in equally bass-ackwards logic.
Admin
Should have switched on FILE_NOT_FOUND
Admin
Agreed. And I'd add sneering at code produced by inadequately trained/supervised juniors is an admission of liability ... present and future.
Admin
No, that's not code, that's a bit of text. It's probably being shown to the user preceded by something like "Methods available:".
This code is correct. It's just wrong.
Admin
The mythical man month. From those days project efforts was measured in month of work times people. Today its number of points and sprints. "Adding points to sprints on a late project makes it even later" someone?
Admin
It is definitely true that the text and the code are not saying the same thing, so either the text is as intended, then the code is incorrect or the code is as intended, but then the text is incorrect. If the code is as intended, then it would be: if foo or bar -> "Foo|Bar" (fixed text) else if not foo -> "neither Foo nor Bar" (was "Bar", which is wrong, as this case can only happen if foo and bar are false) else if not bar -> "Foo" (this case can never happen, as "foo=bar=false" is already handled by the second case).
Therefore even if the text is wrong, the code is also incorrect, because there is no valid intention to have an unreachable case.
Admin
Points and sprints are still measuring work*people, it's just dressing it up in more jargon to make the bigwigs think you're doing something new and different. You've still got the same problem - you've got so much work to do, and you can only do so much in a sprint with the "resources" you have. So when your burn-down charts inevitably burn down slower than the backlog is piling up, you still have the same old options - push your schedule or add more "resources". Or as Steve said, usually both.
Admin
"if it’s false (that “foo” is false and “bar” is false), then obviously they’re all true"
Oops! No, it means that at least one of them is true (I added the parens to clarify). But your mistake still illustrates the inevitable confusion produced by such coding.
Admin
Actually, that's more of a happy side-effect! The actual reason is that those switches can compile to either an if-else chain or a jump table, whichever the optimizer thinks is more performant. In other words, an if-else chain is O(N) where N is the number of cases, but a switch with constant labels is O(1).
...well, except that turning if-else chains into switches is a common optimization these days, so they're probably both O(1) in practice. Ho hum.
Admin
With the "kitchen sink" philosophy that C++ has had for many years, it's kind of telling that they haven't expanded the rules on switch.
Admin
It must have been a guy with his eyes bleeding from having seen that kind of switch who designed the FizzBuzz test.
Admin
Can someone give a legitimate use of switch(true) or switch(false)? It looks like a clever-dick way of writing an if expression or ternary stack, but much less readable. Obviously the coder in question here didn't understand it as their cases don't seem to match their intent (whatever that was).
Admin
The "true" version is just an if-elseif-elseif-elseif-else chain in disguise. It's an idiom (not necessarily a universal one) in some languages, especially VB, which slightly reduces the WTF factor, but ...
The "false" version is an abomination.
Admin
No one said the project was late.
Admin
He would be disappointed that people think not(not(A) ^ not(B)) = A ^ B
Admin
COBOL has called and talks about EVALUATE TRUE. (But even that allows for more readable code than this monstrosity.)
Admin
The only advantage I can see to not requiring constant expressions and allowing switch(true) as an alternative to if-else if's is if you use fall through (if it's allowed by the language). I think the nicest way of doing that logic with if-else's would be a chain of if's on some previously defined boolean variables (e.g. bool isA = condition A, bool isB = A || condition B, ...). Which isn't horrible, just not as clean. But perhaps more readable?
Switch(false) is horrible, unless you have one of those circumstances where it makes it more readable to use the negative (i.e. instead of using ! operations on every case). That's very much not the case here, and both causes and hides the error as described above.
Admin
I've done a lot of assembler programming for 8-bit Microchip PIC's. The primary decision-making instructions for these is BTFSC and BTFSS: Bit Test File And Skip if Clear/Set. That is, check a specified bit, and skip the next instruction if it is 0/1. That requires thinking in inverted logic. E.g., to go to foo if bit 0 of bar is set: BTFSC bar,0 GOTO foo ... not foo code ... GOTO after_foo foo: ... foo code ... after_foo:
I can think that one through, but when the logic is more complex, pretty soon I learned to not spend too much time trying to figure out all the logic inversions and just fix it in test.
But the real puzzle is Microchip's c compiler (XC8), which I am using now: it follows every BTFSC or BTFSS with 3 GOTO's, no code between. The first one jumps to the third one. In many ways, this compiler optimizes so thoroughly that I can't follow the assembly code at all, but for every "if" it generates two extra instructions. Of course, it also misses things that I could do better in assembly just because I understood what the whole function better than any AI could. And so a program that I expected to fit in 4K words has almost filled 16K.
Admin
The first one jumps to the third one. It is to handle far jumps, which work differently on PICs. BTFSC can only do near jumps, so it does a near jump to or over a (jump which may be a far jump).
It should be fixed up by a smart linker, but Microchip has never produced a smart linker for the PIC family.
Admin
It seems the intent is to list unconfigured components, so the options are "Foo" (is unconfigured), "Bar" (is unconfigured) and "Foo & Bar" (i.e. both are unconfigured), thus the attempt to use
switch (false)
to find an unconfigured component. I agree that his logical expression is wrong; it probably tried to use&&
to combine the unconfigured status, then moved on to inverting (using anotherfalse
antipattern) the status before combining it, but then forgot to compensate for the switch onfalse
, so it needs another inversion otherwise this branch is hit whenever either component is configured. (Properly written inversions might make this almost readable as compared with applying DeMorgan, which would probably only cause further confusion.)