[net.bugs] e1?

throopw@dg_rtp.UUCP (Wayne Throop) (08/04/86)

> whp@cbnap.UUCP (W. H. Pollock x4575 3S235)
>> jcz@sas.UUCP (Carl Zeigler)

>>Scan again, Andrew, the (void) values are being thrown away.
>
> The void values are not thrown away!  Remember that (A?B:C) is an
> expression *returning a value*.

Uh, well, no actually.  I'll join in this tis-so/tis-not debate using
the radical approach of seeing what fairly-well-respected references
have to say on the subject.

First, note that K&R don't say anything about it, since they didn't have
(void) back then.

Second, Harbison and Steele say that ?: expressions come in four
flavors.  One flavor is interesting here (from page 183):

    3. They [the second and third subexpressions] may have identical
       types (structure, union, enumeration, or void).  The result is of
       this same type.

Third, the ANSI C draft standard, C.3.15.

    The first operand shall have scalar type.  Both the second and third
    operands shall have arithmetic type, or shall have the same
    structure, union, or pointer type, or shall be void expressions.  In
    addition, one may be an object pointer and the other a pointer to
    void, or one may be a pointer and the other a null pointer constant.
        ...
    If both the operands are void expressions, the result is a void
    expression.

All fairly clear and straightforward.  It is legal.  So, the objection:

> C is giving the error because it can't
> determine the type of the return value.

is incorrect.  The "type" returned from a ?: expression with void
trailing operands is void.

--
Any clod can have facts, but having opinions is an art.
                        --- Charles McCabe, San Francisco Chronicle
-- 
Wayne Throop      <the-known-world>!mcnc!rti-sel!dg_rtp!throopw

franka@mmintl.UUCP (08/07/86)

[Not food]

It seems clear that according to the ANSI draft, e1?e2:e3 is legal when e2
and e3 are both void.  The next question is, should it be?

It seems to me that there are two different paradigms for how to interpret
the ?: operator here.  One is as an ordinary operator, which returns one of
the values of e2 or e3, depending on the value of e1.  Under this
interpretation, it does not seem to me appropriate to permit e2 and e3 void,
since in that case they have no values.

The other paradigm is that e1?e2:e3 is precisely one of e2 or e3, depending
on the value of e1.  This is a very reasonable interpretation; but if it
were correct, there would be one other important consequence which is not in
fact legal.  This is that when e2 and e3 are lvalues, the compound
expression should also be an lvalue.  In particular, one could write

e1?e2:e3 = e4;

which would mean the same thing as

if (e1) then e2 = e4; else e3 = e4;

(This would be permitted only if e2 and e3 had exactly the same type, of
course; one could not do this if e2 was a short and e3 a long.)

This seems to me like a reasonable extension to the language.  But I believe
it should be one or the other -- the draft falls uncomfortably in the middle.

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

jsdy@hadron.UUCP (Joseph S. D. Yao) (08/10/86)

In article <499@dg_rtp.UUCP> throopw@dg_rtp.UUCP (Wayne Throop) writes:
>Any clod can have facts, but having opinions is an art.
>> whp@cbnap.UUCP (W. H. Pollock x4575 3S235)
>>> jcz@sas.UUCP (Carl Zeigler)
>>>Scan again, Andrew, the (void) values are being thrown away.
>> The void values are not thrown away!  Remember that (A?B:C) is an
>> expression *returning a value*.
	[paraphrase -j-]
>K&R don't say anything, since no (void) back then.
>Harbison and Steele say:
>    3. They [the second and third subexpressions] may have identical
>       types (structure, union, enumeration, or void).  The result is of
>       this same type.
>ANSI C draft standard, C.3.15.
>    The first operand shall have scalar type.  Both the second and third
>    operands shall have arithmetic type, or shall have the same
>    structure, union, or pointer type, or shall be void expressions.  In
>    addition, one may be an object pointer and the other a pointer to
>    void, or one may be a pointer and the other a null pointer constant.
>        ...
>    If both the operands are void expressions, the result is a void
>    expression.
>All fairly clear and straightforward.  It is legal.

*sigh*  OK, let's get this straight.  PROPOSED ANSI standard
X3J11 describes a language (set of languages, over the past
few years) that has (and have) not yet been implemented any-
where by anyone (or if they have, word hasn't gotten to this
corner yet).  H&S, while a very good book, does take some
liberties at interpretation.  They are on the ANSI X3J11
committee, and could have been influenced in their interpre-
tations by the committees deliberations.  Most compilers
today follow K&R, which by declaring that the conditional
expression has (1) a result (2) with a data type predicated
on the types of the operands, seems to be prohibiting use
of void-type objects.  Until recently, Proposed X3J11
concurred with this, specifically allowing only arith types,
structures, unions, and pointers of the same type (remembering
that "0" can be construed as a pointer of any type).

Bottom line:  it's a mite early to be pointing to Proposed
X3J11 and saying something is "right" or "not right" based
on that.  Agreed, we should all follow and be aware (as I
was not, of this) of things affecting our good programming
practice.  As of now, the standards are K&R with s3 and s5
enhancements.  Anything that is not explicitly defined in
one of these is subject to interpretation.  As H&S points
out, the C language is what the C compiler accepts.
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}
			jsdy@hadron.COM (not yet domainised)

throopw@dg_rtp.UUCP (Wayne Throop) (08/11/86)

> franka@mmintl.UUCP (Frank Adams)

> It seems clear that according to the ANSI draft, e1?e2:e3 is legal when e2
> and e3 are both void.  The next question is, should it be?
> It seems to me that there are two different paradigms for how to interpret
> the ?: operator here.  One is as an ordinary operator, which returns one of
> the values of e2 or e3, depending on the value of e1.  Under this
> interpretation, it does not seem to me appropriate to permit e2 and e3 void,
> since in that case they have no values.

Well, not quite.  The standard takes the position that, while a void
expression has no value, it has something that is close enough for
government work.  A way to think of is that a void expression indicates
a "value" which requires no storage and has no legal operations (other
than selection operations).  Then specifically, the ?: operation chooses
which of these odd non-value values to "evaluate".

> The other paradigm is that e1?e2:e3 is precisely one of e2 or e3, depending
> on the value of e1.

Yes.  The standard doesn't go this way.  But I think it is reasonable
for the standard to go the way it does, making void expressions legal
wherever any other expressions are, except that their result is illegal
as input for any but selection operations, such as (?:) and (,).  Any
other operation implies an interpretation and transformation of a value,
and (void) cannot be interpreted or transformed, but these operations
only imply evaluation and selection.

So I agree that there are two reasonable interpretations of (?:), and
the standard has chosen the first.  But it has also chosen an
interpretation of "what it means to be (void)" which makes void
expressions to the right of a "?" reasonable.

--
If a listener nods his head when you're explaining your program,
wake him up.
                                --- Alan J. Perlis
-- 
Wayne Throop      <the-known-world>!mcnc!rti-sel!dg_rtp!throopw

geoff@desint.UUCP (Geoff Kuenning) (08/12/86)

While all of this discussion is very interesting and is important to
achieving a precise language definition, let us not forget that there
is *no* reason to ever write this particular expression.  Anywhere it's
useful, you can just write

	if (e1)
	    void_e2;
	else
	    void_e3;

This is better style anyway;  it makes use of a construct that
people are much more used to, and it makes it clearer that what you are
doing is picking one subroutine call over another, rather than something
more subtle.  If you really care about using precious lines, you can even
put it on one line.
-- 

	Geoff Kuenning
	{hplabs,ihnp4}!trwrb!desint!geoff

bright@dataio.UUCP (Walter Bright) (08/13/86)

In article <243@desint.UUCP> geoff@desint.UUCP (Geoff Kuenning) writes:
>While all of this discussion is very interesting and is important to
>achieving a precise language definition, let us not forget that there
>is *no* reason to ever write this particular expression.  Anywhere it's
>useful, you can just write
>
>	if (e1)
>	    void_e2;
>	else
>	    void_e3;

Not quite. This type of expression is very useful for macros which must
in themselves be expressions (to avoid peculiar {} and ; problems). Such
as:

#define biff(pow)	((pow) ? kayo() : oof())

Defining the macro as:

#define biff(pow)	if (pow) kayo(); else oof();

causes difficulties with constructs like:

	if (socko)
		biff(flez);
	else
		bang(glurp);

Similar problems exist for the other permutations of defining biff().

Now for the RIGHT (!) definition of when a void expressions is valid:

	A void expression is valid only under circumstances where the
	value of an expression is not used.

This means that:

	(a ? voidexp : voidexp),(a=b)

is valid. But a=a?voidexp:voidexp isn't valid, as the value is used. Apply
the rule above to all the cases and you have the RIGHT (!) answer. Note that
by implication, if the value of the ?: expression is not used, the operands
of the : need not be of compatible types, and need not be brought to a
common type.

I would like to see the ANSI C spec clarified on this point.

brett@wjvax.UUCP (Brett Galloway) (08/14/86)

In article <243@desint.UUCP> geoff@desint.UUCP (Geoff Kuenning) writes:
>While all of this discussion is very interesting and is important to
>achieving a precise language definition, let us not forget that there
>is *no* reason to ever write this particular expression.  Anywhere it's
>useful, you can just write
>
>	if (e1)
>	    void_e2;
>	else
>	    void_e3;
>

You are correct, but this is true of ALL uses of '?:`.  In fact, '?:` is
VERY useful, especially when you want to embed conditionals in a macro.
Using the if() {} else {} form restricts the contexts in which the macro
may appear.

-- 
-------------
Brett Galloway
{pesnta,twg,ios,qubix,turtlevax,tymix,vecpyr,certes,isi}!wjvax!brett

davidsen@steinmetz.UUCP (Davidsen) (08/15/86)

In article <1701@mmintl.UUCP> franka@mmintl.UUCP (Frank Adams) writes:
>The other paradigm is that e1?e2:e3 is precisely one of e2 or e3, depending
>on the value of e1.  This is a very reasonable interpretation; but if it
>were correct, there would be one other important consequence which is not in
>fact legal.  This is that when e2 and e3 are lvalues, the compound
>expression should also be an lvalue.  In particular, one could write
>
>e1?e2:e3 = e4;
>
>which would mean the same thing as
>
>if (e1) then e2 = e4; else e3 = e4;
>

This kicked off an interesting thought:
  *(e1 ? <ptr expr> : <ptr expr>) = expr;

Lo and behold it does what the quoted expression indicates. In an
actual example:
  *(a < b : &b : &a) = 70;

I'm not sure it *good* for anything, but if I do it with macros using
cute names, I can enter it in the obfuscated C contest...
-- 
	-bill davidsen

  ihnp4!seismo!rochester!steinmetz!--\
                                       \
                    unirot ------------->---> crdos1!davidsen
                          chinet ------/
         sixhub ---------------------/        (davidsen@ge-crd.ARPA)

"Stupidity, like virtue, is its own reward"

levy@ttrdc.UUCP (Daniel R. Levy) (08/16/86)

In article <1061@dataio.UUCP>, bright@dataio.UUCP (Walter Bright) writes:
>#define biff(pow)	((pow) ? kayo() : oof())
>
>Defining the macro as:
>
>#define biff(pow)	if (pow) kayo(); else oof();
>
>causes difficulties with constructs like:
>
>	if (socko)
>		biff(flez);
>	else
>		bang(glurp);
>
>Similar problems exist for the other permutations of defining biff().

Presuming that

	void kayo(), oof();

is intended, whatsa matter with

#define biff(pow)	{ if (pow) kayo(); else oof(); }

This combines the if-else into one single statement.

There is a slight handicap that this doesn't work too well as the first
operand of the comma operator ("syntax error") but at least some common
modern C compilers (as on the SV 3B20) don't like Bright's macro either in
this context or for that matter in any other context
("operands of : have incompatible types").  O.K., Bright (and others) have
been saying "change the definition of C to allow this."  Well I say the same
thing about my suggestion, so THERE!  :-)
-- 
 -------------------------------    Disclaimer:  The views contained herein are
|       dan levy | yvel nad      |  my own and are not at all those of my em-
|         an engihacker @        |  ployer or the administrator of any computer
| at&t computer systems division |  upon which I may hack.
|        skokie, illinois        |
 --------------------------------   Path: ..!{akgua,homxb,ihnp4,ltuxa,mvuxa,
	   go for it!  			allegra,ulysses,vax135}!ttrdc!levy

geoff@desint.UUCP (Geoff Kuenning) (08/16/86)

In article <745@wjvax.wjvax.UUCP> brett@wjvax.UUCP (Brett Galloway) writes:

> In article <243@desint.UUCP> geoff@desint.UUCP (Geoff Kuenning) writes:

>>let us not forget that there
>>is *no* reason to ever write this particular expression.

> You are correct, but this is true of ALL uses of '?:`.  In fact, '?:` is
> VERY useful, especially when you want to embed conditionals in a macro.
> Using the if() {} else {} form restricts the contexts in which the macro
> may appear.

Unfortunately, Brett is incorrect here.  You can't use if/then/else to write:

	for (i = up ? 0 : 99;  up ? (i < 100) : (i >= 0);  up ? i++ : i--)
	    {
	    /* complex loop body */
	    }

without duplicating code.  On the other hand, anywhere you want do
if/then/else (or any other complex statement, such as loops and switches)
inside a macro without restricting where the code can be used, you can
just write:

	#define abc(x)	do { \
			/* anything you want goes here, even declarations */ \
			} while (0)

and almost all compilers will optimize the loop out completely
(something that very few optimizers could do with the "complex loop
body" above, especially because it trades time off for space and few
compiler writers are willing to make that decision).  I learned this
method from in net.lang.c.
-- 

	Geoff Kuenning
	{hplabs,ihnp4}!trwrb!desint!geoff

brett@wjvax.UUCP (Brett Galloway) (08/19/86)

In article <248@desint.UUCP> geoff@desint.UUCP (Geoff Kuenning) writes:
>In article <745@wjvax.wjvax.UUCP> brett@wjvax.UUCP (Brett Galloway) writes:
>
>> You are correct, but this is true of ALL uses of '?:`.  In fact, '?:` is
>> VERY useful, especially when you want to embed conditionals in a macro.
>> Using the if() {} else {} form restricts the contexts in which the macro
>> may appear.
>
>Unfortunately, Brett is incorrect here.  You can't use if/then/else to write:
>
>	for (i = up ? 0 : 99;  up ? (i < 100) : (i >= 0);  up ? i++ : i--)
>	    {
>	    /* complex loop body */
>	    }
>

I thought I said the same thing -- '?:` is useful in some cases where
if/then/else isn't.

>without duplicating code.  On the other hand, anywhere you want do
>if/then/else (or any other complex statement, such as loops and switches)
>inside a macro without restricting where the code can be used, you can
>just write:
>
>	#define abc(x)	do { \
>			/* anything you want goes here, even declarations */ \
>			} while (0)

I don't think this method is general.  For example, your macro abc() cannot be
used inside a for() construct.

-- 
-------------
Brett Galloway
{pesnta,twg,ios,qubix,turtlevax,tymix,vecpyr,certes,isi}!wjvax!brett

cary@methods.UUCP (Cary Timar ) (08/26/86)

In article <248@desint.UUCP> geoff@desint.UUCP (Geoff Kuenning) writes:
>
>Unfortunately, Brett is incorrect here.  You can't use if/then/else to write:
>
>	for (i = up ? 0 : 99;  up ? (i < 100) : (i >= 0);  up ? i++ : i--)
>	    {
>	    /* complex loop body */
>	    }
>
>without duplicating code.  On the other hand, anywhere you want do

What about:

	if (up)
		{
		i = 0;
		step = 1;
		}
	else
		{
		i = 99;
		step = -1;
		}
	for (; i < 100 && i >= 0; i += step)
		{
		/* complex loop body */
		}
	
????

			-- Cary Timar /* NOT REACHABLE */
			< Generic Disclaimer >

brett@wjvax.UUCP (Brett Galloway) (09/02/86)

In article <114@methods.UUCP> cary@methods.UUCP (Cary Timar (U of W co-op)) writes:
>In article <248@desint.UUCP> geoff@desint.UUCP (Geoff Kuenning) writes:
>>
>>Unfortunately, Brett is incorrect here.  You can't use if/then/else to write:
>>
>>	for (i = up ? 0 : 99;  up ? (i < 100) : (i >= 0);  up ? i++ : i--)
>>	    {
>>	    /* complex loop body */
>>	    }
I don't know what I originally said.  What I MEANT to say was that the
'?:` operator is useful.  There are cases (such as within macros) where
if/then/else is not appropriate.  That's all.
-- 
-------------
Brett Galloway
{pesnta,twg,ios,qubix,turtlevax,tymix,vecpyr,certes,isi}!wjvax!brett