5 ms·
Cool to see De Morgan's Laws used at a high level. But the real takeaway: rewrite your conditional until it makes sense.
by glifchits 13y ago
Cool to see De Morgan's Laws used at a high level. But the real takeaway: rewrite your conditional until it makes sense.
- ChuckMcM 13y agoOr conversely that it is better to write affirmative conditionals rather than negative conditionals. I always find reading the affirmative ones much easier, as I have always found working in positive logic easier than work with negative logic circuits.
- VBprogrammer 13y agoExcept where writing negative conditionals are clearer. For example turning: if(a) { if(b) { if (c) { // Do something. } } } Into: if(!a) { } elseif(!b) { } elseif(!c) { } else { // Do something. }
- meatcar 13y agoOr if (a && b && c) { // Do something. }
- jhaywood 13y agoUnless they actually are a VB programmer and And doesn't short circuit.
- joeframbach 13y ago`AndAlso` short circuits.
- jhaywood 13y agoFantastic! If only I could write Excel macros in vb.net
- VBprogrammer 13y agoYes, the that was a very simple example.
- Double_Cast 13y agoiirc, robotics commonly uses something similar called ladder logic.
- ChuckMcM 13y agoInterestingly I've been going back and forth on this lately. I have been playing around with SD cards on the STM32F4 and a typical SD Card transaction consists of 3 to 10 commands which, if any one fails, the transaction fails. I'm currently using negative conditionals of the form "Not Error" (the Error test is an affirmative, and so that seems ok to me) A typical sequence is like the one to set the bus width. err = sdio_select(rca); if (! err) { err = sdio_command(55, rca << 16); if (! err) { err = sdio_command(6, 2); } } sdio_deslect(); return err; I had originally done it the other way err = sdio_select(rca); if (err) { return err; } err = sdio_command(55, rca << 16); if (err) { sdio_deselect(); return err; } err = sdio_command(6, 2); sdio_deselect(); return err; I find the first form more readable. It also generates fewer branches in the generated code. The sample code I first looked at was doing Goto's to the exit code (deselect/return error) which was unacceptable :-). In the original article the confusion arose around negative test cases and then testing for them negatively (double negatives) which I think are always bad from a readability point of view.
- krzysz00 13y agoNot to drag the thread off topic, but this seems like the kind of situation where a version of Haskell's Maybe or Either monads might come in handy, so you could write: do command1 command2 ... and have the failures propagate automatically.
- nitrogen 13y agoWhat I've found myself doing in such cases is adding a function that processes multiple commands and indicates an error if any one of the commands failed (sdio_batch could be a varargs function): struct sdio_cmd { enum { SDIO_SELECT, SDIO_COMMAND } cmd; int reg; // Guesses at suitable names without int val; // knowing anything about SDIO } int sdio_batch(int count, ...); err = sdio_batch(3, &(struct sdio_cmd){ SDIO_SELECT, .val = rca }, &(struct sdio_cmd){ SDIO_COMMAND, 55, rca << 16 }, &(struct sdio_cmd){ SDIO_COMMAND, 6, 2 }, ); I've been doing it in Ruby with network remote procedure calls, where it's not quite as ugly to use inline lists and variable argument counts as it is in C, and where branch count isn't quite as important. The sample code I first looked at was doing Goto's to the exit code (deselect/return error) which was unacceptable :-). What's so bad about a little goto between friends?