Hi Folks!
The following program compiles without warnings:
{ 2.1 (20020510), based on gcc-2.95.2 19991024 (release) } program bug;
var i: Integer = 1;
begin if i = 1 then WriteLn ('is 1') else if i = 2 then { do nothing } else { do nothing } end.
Eike
Eike Lange wrote:
The following program compiles without warnings:
{ 2.1 (20020510), based on gcc-2.95.2 19991024 (release) } program bug;
var i: Integer = 1;
begin if i = 1 then WriteLn ('is 1') else if i = 2 then { do nothing } else { do nothing } end.
Not a bug. Terrible program structure, leading to much confusion, but valid. The null statement is specifically permitted. You will often see such things as:
WHILE whatever DO (* nothing *);
With if/else if/else chains, a useful rule is to put the short clauses first (if possible) and make the final else the longest clause. i.e.:
IF something THEN BEGIN (* lots of code *) END ELSE BEGIN (* a few lines *) END;
is inferior to:
IF NOT something THEN BEGIN (* a few lines *) END ELSE BEGIN (* lots of code *) END;
for readability reasons. You can look up from any code and find the controlling statement easily. This applies to most languages. The compiler should normally be able to optimize away any extra code generated.
CBFalconer wrote:
Eike Lange wrote:
The following program compiles without warnings:
{ 2.1 (20020510), based on gcc-2.95.2 19991024 (release) } program bug;
var i: Integer = 1;
begin if i = 1 then WriteLn ('is 1') else if i = 2 then { do nothing } else { do nothing } end.
Not a bug. Terrible program structure, leading to much confusion, but valid. The null statement is specifically permitted. You will often see such things as:
Use `-W' if you want a warning.
Frank
Eike Lange wrote:
On Thu, Oct 31, 2002 at 06:01:15PM +0100, Frank Heckenbach wrote:
Use `-W' if you want a warning.
-Wall does not warn, but -W does.
That's as expected, and the same GCC does. See info: (gcc) Warning options:
: `-Wall' : [...] This enables all the : warnings about constructions that some users consider : questionable, and that are easy to avoid (or modify to prevent the : warning), even in conjunction with macros. : : [...] : : The following `-W...' options are not implied by `-Wall'. Some of : them warn about constructions that users generally do not consider : questionable, but which occasionally you might wish to check for; : others warn about constructions that are necessary or hard to avoid in : some cases, and there is no simple way to modify the code to suppress : the warning.
As has shown already in this thread, not all programms consider an empty `else' part a bug. Actually, there's one situation where I can imagine it to be useful, the dangling `else' problem:
if foo then if bar then baz else else qux
Though alternatively, one can use `begin'/`end' to avoid the empty `else' part:
if foo then begin if bar then baz end else qux
Frank
On Wed, Nov 06, 2002 at 01:57:34AM +0100, Frank Heckenbach wrote:
Eike Lange wrote: As has shown already in this thread, not all programms consider an empty `else' part a bug. Actually, there's one situation where I can imagine it to be useful, the dangling `else' problem: if foo then if bar then baz else else qux Though alternatively, one can use `begin'/`end' to avoid the empty `else' part: if foo then begin if bar then baz end else qux
The latter looks quite more natural to me (and is the way, the GPCS prefers). IMO using a comment instead of an empty `else' statement makes the first example more readable:
if foo then if bar then baz else { empty } else qux
Warnings and empty `else' might be a topic for "GNU Pascal Coding Standard (* Assorted Tips )" if you agree.
Eike
Eike Lange wrote:
On Wed, Nov 06, 2002 at 01:57:34AM +0100, Frank Heckenbach wrote:
As has shown already in this thread, not all programms consider an empty `else' part a bug. Actually, there's one situation where I can imagine it to be useful, the dangling `else' problem: if foo then if bar then baz else else qux Though alternatively, one can use `begin'/`end' to avoid the empty `else' part: if foo then begin if bar then baz end else qux
The latter looks quite more natural to me (and is the way, the GPCS prefers). IMO using a comment instead of an empty `else' statement makes the first example more readable:
if foo then if bar then baz else { empty } else qux
Warnings and empty `else' might be a topic for "GNU Pascal Coding Standard (* Assorted Tips )" if you agree.
This can be written, much more clearly and simply, as:
IF NOT foo THEN qux ELSE IF bar THEN baz;
There is NEVER any reason for an empty else.
On 6 Nov 2002 at 4:46, CBFalconer wrote:
There is NEVER any reason for an empty else.
Clarity, perhaps? What would be your preference for rewriting:
IF a THEN IF b THEN c ELSE { null } ELSE IF d THEN e;
...without the empty ELSE? This represents the logical conditions:
* c iff a and b * e iff not a and d
It could be written without an empty ELSE as two statements:
IF a AND b THEN c;
IF NOT a AND d THEN e;
...but that wouldn't be equivalent if "a" was a function with side-effects (e.g.). Alternatives might be a Boolean variable for the value of "a", or encapsulating the second IF statement in a BEGIN-END block. Whether those are clearer than the empty ELSE is problematic (although an empty ELSE surely should be commented).
-- Dave
"J. David Bryan" wrote:
On 6 Nov 2002 at 4:46, CBFalconer wrote:
There is NEVER any reason for an empty else.
Clarity, perhaps? What would be your preference for rewriting:
IF a THEN IF b THEN c ELSE { null } ELSE IF d THEN e;
...without the empty ELSE? This represents the logical conditions:
I think you will find that:
IF a AND b THEN c ELSE IF (NOT a) AND (NOT b) AND d THEN e; or IF a AND b THEN c ELSE IF (NOT (a OR b)) AND d THEN e;
with the parentheses for clarity, covers it exactly, including all do-nothing cases. I have no problems answering the question 'when is c executed' or 'when is e executed' with the above. With the original I do (have a problem).
A Karnaugh map is a very useful thing. It may show that the NOT b term is unnecessary in some applications. Or other economies. In some cases I could conceive of:
IF b THEN c ELSE IF d THEN e;
being satisfactory, even though it doesn't match the original logic, simply by mapping explicit do-nothings and don't cares into a Karnaugh map. This sort of thing can show the uselessness of a, and thus lead to major snippage in the original source. Which is an important form of optimization.
CBFalconer wrote:
I think you will find that:
IF a AND b THEN c ELSE IF (NOT a) AND (NOT b) AND d THEN e; or IF a AND b THEN c ELSE IF (NOT (a OR b)) AND d THEN e;
with the parentheses for clarity, covers it exactly, including all do-nothing cases.
But it duplicates a. That is a problem if it has side-effects as Dave pointed out, and if it's a longish expression, it's at least more error-prone.
Of course, you can use a temp variable. But then again, the assignment necessary is an additional statement, and might even require another `begin'/`end' (if otherwise the `if' statement was the only one within a loop or conditional).
I have no problems answering the question 'when is c executed' or 'when is e executed' with the above. With the original I do (have a problem).
Seems so, since you apparently misread the condition for e. It should be `if not a and d then e' (no mention of b), just like Dave said.
But I can't really understand why you find reading the original code harder. To me it clearly reads:
if a [...] else if d then e
(where the indentation makes it clear which `else' belongs to what) which is clearly the same as
if not a and d then e
A Karnaugh map is a very useful thing. It may show that the NOT b term is unnecessary in some applications. Or other economies. In some cases I could conceive of:
IF b THEN c ELSE IF d THEN e;
being satisfactory, even though it doesn't match the original logic, simply by mapping explicit do-nothings and don't cares into a Karnaugh map. This sort of thing can show the uselessness of a, and thus lead to major snippage in the original source. Which is an important form of optimization.
Well, I don't know much about Karnaugh maps, but in this example I assume that a is not useless (otherwise the example would be off). So, that doesn't really address the question at hand.
Frank
Frank Heckenbach wrote:
CBFalconer wrote:
I think you will find that:
IF a AND b THEN c ELSE IF (NOT a) AND (NOT b) AND d THEN e; or IF a AND b THEN c ELSE IF (NOT (a OR b)) AND d THEN e;
with the parentheses for clarity, covers it exactly, including all do-nothing cases.
But it duplicates a. That is a problem if it has side-effects as Dave pointed out, and if it's a longish expression, it's at least more error-prone.
Of course, you can use a temp variable. But then again, the assignment necessary is an additional statement, and might even require another `begin'/`end' (if otherwise the `if' statement was the only one within a loop or conditional).
I have no problems answering the question 'when is c executed' or 'when is e executed' with the above. With the original I do (have a problem).
Seems so, since you apparently misread the condition for e. It should be `if not a and d then e' (no mention of b), just like Dave said.
But I can't really understand why you find reading the original code harder. To me it clearly reads:
if a [...] else if d then e
(where the indentation makes it clear which `else' belongs to what) which is clearly the same as
if not a and d then e
A Karnaugh map is a very useful thing. It may show that the NOT b term is unnecessary in some applications. Or other economies. In some cases I could conceive of:
IF b THEN c ELSE IF d THEN e;
being satisfactory, even though it doesn't match the original logic, simply by mapping explicit do-nothings and don't cares into a Karnaugh map. This sort of thing can show the uselessness of a, and thus lead to major snippage in the original source. Which is an important form of optimization.
Well, I don't know much about Karnaugh maps, but in this example I assume that a is not useless (otherwise the example would be off). So, that doesn't really address the question at hand.
c and e are outcomes, blank is no action, X is don't care
This is the map that I (mis)filled for the original action:
.... a .... ------------------------- | | | c | | ------------------------- d | e | | c | | ------------------------- .... b ....
which should have been:
.... a .... ------------------------- | | | c | | ------------------------- d | e | e | c | | ------------------------- .... b .... giving: IF a AND b THEN c ELSE IF NOT a AND d THEN e;
They allow you to see the minimum conditions for any logical action quickly, and can easily be extended to 4 and 5 variables. Any more is not convenient. Don't care X marks can simplify the logic, because you have the option to include or not include such a location in an expression. X's usually result from input conditions that cannot arise, such as 1010 in a binary coded decimal counter. Then the map would look like:
.... 1 .... ------------------------- | 0 | 2 | 3 | 1 | ------------------------- . | 4 | 6 | 7 | 5 | 4 ------------------------- . | | | | | . ------------------------- 8 | 8 | | | 9 | . ------------------------- .... 2 ....
where the 1, 2, 4, 8 are the weights of the counter bits. The interior values are the state of the counter, in 0..9. In this case all the blank entries are don't cares. By combining desired states with don't cares it is obvious that the 8 and 9 states can be detected with 2 bits only, the 0 and 1 states require 4, and that all others require 3 bits. For example, combining the 4 state with an adjacent blank spans the 8 bit transition, which is thus NOT required in detecting that state.
Note the Gray coding style of the map. The state in each square is 1 bit different from each adjacent square. The map rolls around, both vertically and horizontally.
End of quick course in Karnaugh maps and logical reductions thereby :-)
CBFalconer wrote:
End of quick course in Karnaugh maps and logical reductions thereby :-)
Thanks. BTW, do you have a background in electrical circuit design or something like this? I can imagine that such diagrams are quite useful there, to minimize the number of logic elements required etc.
However, in programming, at least in my experience, I often start to break down cases into subcases etc., repeatedly, which leads quite naturally to a structure of nested `if's. Any rearrangement of them (whether to avoid dangling `else's, or for other reasons) makes the result usually look less natural to me because the original ideas that lead to the cases are hidden. More or less the same holds in complicated Boolean expressions.
Of course, sometimes it turns out that the case distinctions are wrong, and must be changed substantially. In such a situation, I can imagine that such a diagram makes it easy to identify in which cases the result is actually changed (which should be few, but including the ones where problems were discovered), as an affirmation that the rearrangment is useful. (For such purposes, I sometimes write tables, but more often work with De Morgan and distributive laws).
Frank
Frank Heckenbach wrote:
CBFalconer wrote:
End of quick course in Karnaugh maps and logical reductions thereby :-)
Thanks. BTW, do you have a background in electrical circuit design or something like this? I can imagine that such diagrams are quite useful there, to minimize the number of logic elements required etc.
Exactly. I claim I was born a physicist, metamorphed into an electrical engineer, and thence into a programmer :-)
On 6 Nov 2002 at 15:02, CBFalconer wrote:
I think you will find that:
IF a AND b THEN c ELSE IF (NOT a) AND (NOT b) AND d THEN e;
[...]
with the parentheses for clarity, covers it exactly....
Presuming that we discard the "AND NOT b" as noted in your followup, that still yields a different result if "a" has side-effects. If "a", for example, is a function to "get a character," then you see the problem, i.e., two characters are processed instead of the intended one.
It is not my intent to belabor the point, but rather simply to take exception to your original assertion that it is "NEVER" appropriate to use an empty ELSE. Style rules that contain absolute prohibitions against language features are "NEVER" correct. ;-) DeMorgan-izing a condition to avoid the empty ELSE may improve clarity or detract from it, depending on how hard it is for the reader to understand the transformed conditional (i.e., how convoluted it becomes). For instance:
IF not_received AND not_transmitted THEN a ELSE b
...is much easier for me to understand than:
IF NOT not_received OR NOT not_transmitted THEN b ELSE a
...even if statement "a" introduces potentially introduces an empty ELSE. Another example is a FOR loop that introduces otherwise unneeded Boolean variables to avoid a GOTO as a loop exit condition (because of a style rule that asserts that GOTOs are never appropriate).
I would agree with such style rules if "NEVER" were changed to "rarely."
-- Dave
Eike Lange wrote:
On Wed, Nov 06, 2002 at 01:57:34AM +0100, Frank Heckenbach wrote:
Eike Lange wrote: As has shown already in this thread, not all programms consider an empty `else' part a bug. Actually, there's one situation where I can imagine it to be useful, the dangling `else' problem: if foo then if bar then baz else else qux Though alternatively, one can use `begin'/`end' to avoid the empty `else' part: if foo then begin if bar then baz end else qux
The latter looks quite more natural to me (and is the way, the GPCS prefers).
Not strictly. It does mention the example with `begin'/`end', but more as an example for using `begin'/`end' around a single statement, not in contrast to the empty `else' case (which it doesn't mention at all).
IMO using a comment instead of an empty `else' statement makes the first example more readable:
if foo then if bar then baz else { empty } else qux
IMHO, both ways are a little dangerous (one might be tempted to remove the "superfluous" `begin'/`end' when not looking carefully), so both ways might deserve a comment -- in the empty `else' case, as you showed, in the `begin'/`end' case I'm not sure where to best place the comment ...
Of course, whenever easily possible, one should avoid the situation as Chuck said, but sometimes it's not easily possible (see Dave's example if I'm not missing anything).
Warnings and empty `else' might be a topic for "GNU Pascal Coding Standard (* Assorted Tips )" if you agree.
I agree. Could you write the text for the English and German versions?
Frank