[net.lang] null statements

colonel@sunybcs.UUCP (Col. G. L. Sicherman) (07/18/86)

> So to get the effect equivalent to "zero" out of the null statement, do we
> invent some sort of "positional notation" for statements?!?!

Fine with me!  I'd rather be able to write

	while ('\n' != getchar()) nothing;

than

	while ('\n' != getchar()) /* do nothing */ ;
-- 
Col. G. L. Sicherman
UU: ...{rocksvax|decvax}!sunybcs!colonel
CS: colonel@buffalo-cs
BI: csdsicher@sunyabva

franka@mmintl.UUCP (Frank Adams) (07/22/86)

>> So to get the effect equivalent to "zero" out of the null statement, do we
>> invent some sort of "positional notation" for statements?!?!

I find the use of the word "invent" somewhat objectionable here.  Perhaps
you have heard of FORTRAN, the oldest high level language of them all?[1]
Perhaps you have heard of the CONTINUE statement therein, which does nothing?

I see nothing wrong with the idea of a an explicit null statement, but let's
not pretend it's a new idea.

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Multimate International    52 Oakland Ave North    E. Hartford, CT 06108

[1] I believe FORTRAN is somewhat older than either ALGOL or LISP, which are
of the same general vintage.  If I'm wrong, don't bother to correct me.

paulsc@orca.UUCP (Paul Scherf) (07/22/86)

In article <442@sunybcs.UUCP> colonel@sunybcs.UUCP (Col. G. L. Sicherman) writes:
>> So to get the effect equivalent to "zero" out of the null statement, do we
>> invent some sort of "positional notation" for statements?!?!
>
>Fine with me!  I'd rather be able to write
>
>	while ('\n' != getchar()) nothing;
>
>than
>
>	while ('\n' != getchar()) /* do nothing */ ;

You already can.  Well, almost.

	while ('\n' != getchar()) continue;

It works for do-while and for loops too.

Paul Scherf, Tektronix, Box 1000, MS 61-028, Wilsonville, OR, USA
tektronix!orca!paulsc

sbs@valid.UUCP (Steven Brian McKechnie Sargent) (07/23/86)

> > So to get the effect equivalent to "zero" out of the null statement, do we
> > invent some sort of "positional notation" for statements?!?!
> Fine with me!  I'd rather be able to write
> 	while ('\n' != getchar()) nothing;
> than
> 	while ('\n' != getchar()) /* do nothing */ ;
> -- 
> Col. G. L. Sicherman
> UU: ...{rocksvax|decvax}!sunybcs!colonel
> CS: colonel@buffalo-cs
> BI: csdsicher@sunyabva


Only a barbarian or Obfuscated C Contest winner would champion the use of
	#define nothing	/* do nothing */
but I figured I'd mention it anyway.

I format null-body loops so:
	while (getchar() != '\n')
		;
which fixes most of the "eyeball ambiguity."

The null statement problem is much worse in Pascal because there is no
explicit statement termination, only separation.  So

 1	IF complicated predicate involving several dozen apparently randomly
 2	   selected expressions THEN
 3		{Attempt to do nothing innocuously};
 4	ELSE BEGIN
 5		writeln('Read the code to find out what happened here.');
 6		i := i/0;
 7	END;

is a lose, lose, lose.  That ; character on line 3 makes Mr. Pascal very sick.
You can replace it with the sequence BEGIN END, which looks a little stoopid
but gets the job done.  In Berkeley Pascal we had an explicit "null" statement
that did what you want with no muss & no fuss: it worked anywhere that the
sequence BEGIN ... END did.

I sort of like the Modula-2 convention of tagging everything with an END.
It makes programs chattier than they need to be but it seems to get the
point across.  Actually, the Algol/UNIX Shell convention of if...endif,
do...done, case...esac is best of all, because you can read the code forwards
OR backwards...

S.

chris@umcp-cs.UUCP (Chris Torek) (07/23/86)

In article <484@valid.UUCP> sbs@valid.UUCP (Steven Brian McKechnie
Sargent) writes:
>Only a barbarian or Obfuscated C Contest winner would champion the use of
>	#define nothing	/* do nothing */
>but I figured I'd mention it anyway.

Actually, I came up with a use for something very like this recently.
In C one can define a macro that `looks' like a function or procedure:

	/* successor function, mod 5 */
	#define	succ(i)	(((i) + 1) % 5)

In many cases the function is more complex:

	#define	get_node() \
		(freenodes ? \
		    (temp = freenodes, freenodes = freenodes->next, temp) : \
		    allocate_more_nodes())

If the macro is emulating a procedure, it need not even be an expression:

	#define proc(exp) \
		if (exp) \
			a(); \
		else \
			b()

Note the lack of a semicolon.  Instances of the macro include the
semicolon, and it would not do to include it twice:

	v = e;
	proc(v);
	other(v);

Sometimes, however, there is nothing to do in the `else' clause:

	#define SaveB(b) \
		if ((b)->b_AfterGroupRst == NULL || \
		    (b)->b_AfterGroupRst->sv_level != CurrentGroup) \
			DoSave(b); \
		else \
			/* do nothing */

This is fine in normal contexts:

	v = e;
	SaveB(v);
	other(v);

However, now a missing semicolon can wreak silent havoc:

	v = e;
	SaveB(v)
	other(v);

This expands to `if (v->b_...) DoSave(v); else other(v);'---not at
all what was meant, but syntactically valid.

One solution is to invert the `if':

	#define SaveB(b) \
		if ((b)->b_AfterGroupRst != NULL && \
		    (b)->b_AfterGroupRst->sv_level == CurrentGroup) \
			/* do nothing */ ; \
		else \
			DoSave(b)

This is, however, confusing, at best.  What is needed is an
explicit `nothing'.  In fact, this works:

	#define SaveB(b) \
		if ((b)->b_AfterGroupRst == NULL || \
		    (b)->b_AfterGroupRst->sv_level != CurrentGroup) \
			DoSave(b); \
		else \
			0

since a constant is an expression, and an expression is a statement.
This will make the case of the missing semicolon produce a syntax
error.  Unfortunately, it also makes `lint' complain (at least when
used with `-h').  The solution below avoids both of these problems,
but is hardly pretty:

	#ifdef lint
	#define do_nothing	rand()
	#else
	#define do_nothing	0
	#endif

	/*
	 * Save a binding.
	 */
	#define SaveB(b) \
		if ((b)->b_AfterGroupRst == NULL || \
		    (b)->b_AfterGroupRst->sv_level != CurrentGroup) \
			DoSave(b); \
		else \
			do_nothing

	/*
	 * Undo a save.
	 */
	#define UnSaveB(b) \
		if ((b)->b_AfterGroupRst != NULL) \
			DoUnsave(b); \
		else \
			do_nothing

I think this also argues for an explicit `null statement'.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu

sjoerd@botter.UUCP (sjoerd) (07/25/86)

In article <2565@umcp-cs.UUCP> chris@maryland.UUCP (Chris Torek) writes:
[ About null statements in #defines ]
>In many cases the function is more complex:
>
>	#define	SaveB(b) \
>		if ((b)->b_AfterGroupRst == NULL || \
>		    (b)->b_AfterGroupRst->sv_level != CurrentGroup) \
>			DoSave(b); \
>		else \
>			/* do nothing */
>
And continues to suggest a few solutions since the above will wreak havoc
if you forget a semicolon in the call.
Another solution (which does not require a null statement) is:
#define SaveB(b) \
	(/* if */ ((b)->b_AfterGroupRst == NULL || \
	 (b)->b_AfterGroupRst->sv_level != CurrentGroup) /* then */ && \
		DoSave(b))
I agree that this may be bit confusing, but this has the great advantage
that you can use it everywhere where you can use an expression (like in a
for statement).
Another use for this construct is the assert macro:
#define assert(e)	(!(e) && printf("Assertion failed ..."))
You can write this differently:
#define assert(e)	((e) || printf("Assertion failed ..."))
I like this much better than the if statement that is usually used.
>In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
>UUCP:	seismo!umcp-cs!chris
>CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu

greg@utcsri.UUCP (Gregory Smith) (07/29/86)

In article <484@valid.UUCP> sbs@valid.UUCP (Steven Brian McKechnie Sargent) writes:

>> Fine with me!  I'd rather be able to write
>> 	while ('\n' != getchar()) nothing;
>> than
>> 	while ('\n' != getchar()) /* do nothing */ ;
>
>I format null-body loops so:
>	while (getchar() != '\n')
>		;
>which fixes most of the "eyeball ambiguity."
>
Good stuff, I plan to decide on one of these practices and follow it.
C has a danger inherent in the do..while loop, some people indent them
as below:

	do{
		/* a whole lotta stuff, many lines */
	}
	while( foo_bar(*x++) != BLETCH );

Thus making it look like the last line is a null-bodied 'while'.
I ( like most ) circumvent this by writing }while(...) at the end, and
making the body a compound statement whether it needs it or not ( A loose
'do' is *scary*.... could get lost in there... bolt it to a '{' )

>The null statement problem is much worse in Pascal because there is no
>explicit statement termination, only separation.  So
>
> 1	IF complicated predicate involving several dozen apparently randomly
> 2	   selected expressions THEN
> 3		{Attempt to do nothing innocuously};
> 4	ELSE BEGIN
> 5		writeln('Read the code to find out what happened here.');
> 6		i := i/0;
> 7	END;
>
>is a lose, lose, lose.  That ; character on line 3 makes Mr. Pascal very sick.
>You can replace it with the sequence BEGIN END, which looks a little stoopid

Isn't there a null statement ""? I.e., can't you say

	IF .... THEN ELSE BEGIN ... END

??? ( i.e. just delete the ; on line 3. Sorry, can't find a reference ).
PS: a Pascal teaching compiler I once used could come up with the
message 'semicolon is never legal before ELSE'. Neat, huh?

-- 
"You'll need more than a Tylenol if you don't tell me where my father is!"
						- The Ice Pirates
----------------------------------------------------------------------
Greg Smith     University of Toronto      UUCP: ..utzoo!utcsri!greg

sommar@enea.UUCP (Erland Sommarskog) (07/30/86)

In article <3188@utcsri.UUCP> greg@utcsri.UUCP (Gregory Smith) writes:
>Isn't there a null statement ""? I.e., can't you say
>
>	IF .... THEN ELSE BEGIN ... END
>
>??? ( i.e. just delete the ; on line 3. Sorry, can't find a reference ).
IF <expression> THEN ELSE <statement> 
is legal Pascal. Look e.g. in Wirth's report only book of Pascal that
contains the syntax graphs.
  You can express it that in Pascal the empty statement is written with
an empty string. 

>PS: a Pascal teaching compiler I once used could come up with the
>message 'semicolon is never legal before ELSE'. Neat, huh?
So does DEC's Pascal compiler for VMS:
"; ELSE is not valid Pascal"
But most compilers says    ELSE
                           ^6
And at the end of list explains: "Illegal symbol". It takes some until
you react normally and directly start to look for an illegal semicolon.