Two expression variant of ()

M

mathog

C has two () constructs which return a value:

( expr1 ? expr2 : expr3)
( expr )

As far as I can tell the language does not define a two expression
variant. Is there some way to concoct a two expression variant that
acts like this (whatever the solution is, it has to go within () ):

( expr1 ?? expr2 ) // ?? isn't legal. used to show approx. syntax

Where
the value returned is expr1
expr2 is always evaluated
expr2 is evaluated after expr1
The value of expr2 is not used for the () logic, it is just
evaluated for side effects.

Or described another way:

in any if() or while(), within the parens
val=expression1
do some other stuff (at least one expression, more would be better)
the test is applied to val

Here is a simple example of its use with the approx. syntax in a while loop:

while( *ptr ?? {ptr+=1;val--;} ){

Notice that at the moment there seems to be no place to put the val--,
other than with a lot of extra logic, and the +=1 is only possible
because of the way ++ works:

didval=0;
while(*ptr++){
val--;
/* code */
if(whatever){didval=1; break;}
/* more code */
}
if(!didval)val--;

If we give up on putting everything within the while parens the logic is
at least easier to understand:

while(1){
tval=*ptr;
ptr+=1;
val--;
if(!tval)break;
/* code */
}

This can be accomplished by calling a function within the parens.

Can it be done without calling a function and with all implementing code
within the parens???

Thanks,

David Mathog
 
K

Kaz Kylheku

C has two () constructs which return a value:

( expr1 ? expr2 : expr3)
( expr )

This is not a () construct. It's just

expr1 ? expr2 : expr3

that you added parentheses around.
while( *ptr ?? {ptr+=1;val--;} ){

Comma operator:

while (ptr += 1, val --, *ptr) ...

You really should read a C tutorial and reference manual.
 
B

Ben Pfaff

mathog said:
As far as I can tell the language does not define a two expression
variant. Is there some way to concoct a two expression variant that
acts like this (whatever the solution is, it has to go within () ):

( expr1 ?? expr2 ) // ?? isn't legal. used to show approx. syntax

Where
the value returned is expr1
expr2 is always evaluated
expr2 is evaluated after expr1
The value of expr2 is not used for the () logic, it is just
evaluated for side effects.

I don't think so.

I think that you can come close, at least, with the GCC ({})
extension:
({ typeof(expr1) e1 = expr1; expr2; e1 })
 
T

Tim Rentsch

mathog said:
C has two () constructs which return a value:

( expr1 ? expr2 : expr3)
( expr )

As far as I can tell the language does not define a two expression
variant. Is there some way to concoct a two expression variant that
acts like this (whatever the solution is, it has to go within () ):

( expr1 ?? expr2 ) // ?? isn't legal. used to show approx. syntax

Where
the value returned is expr1
expr2 is always evaluated
expr2 is evaluated after expr1
The value of expr2 is not used for the () logic, it is just
evaluated for side effects.

Or described another way:

in any if() or while(), within the parens
val=expression1
do some other stuff (at least one expression, more would be better)
the test is applied to val

Here is a simple example of its use with the approx. syntax in a while loop:

while( *ptr ?? {ptr+=1;val--;} ){

[snip elaboration]

This use case isn't very compelling, because it has
been doable easily in standard C since K&R, to wit:

while( *ptr && (ptr++, val--, 1) ){ ... }

(This assumes of course that writing such code has
been judged acceptable style, as to which I am
expressing no opinion; I'm just pointing out that
it's possible.)
 
T

Tim Rentsch

Tim Rentsch said:
mathog said:
C has two () constructs which return a value:

( expr1 ? expr2 : expr3)
( expr )

As far as I can tell the language does not define a two expression
variant. Is there some way to concoct a two expression variant that
acts like this (whatever the solution is, it has to go within () ):

( expr1 ?? expr2 ) // ?? isn't legal. used to show approx. syntax

Where
the value returned is expr1
expr2 is always evaluated
expr2 is evaluated after expr1
The value of expr2 is not used for the () logic, it is just
evaluated for side effects.

Or described another way:

in any if() or while(), within the parens
val=expression1
do some other stuff (at least one expression, more would be better)
the test is applied to val

Here is a simple example of its use with the approx. syntax in a while loop:

while( *ptr ?? {ptr+=1;val--;} ){

[snip elaboration]

This use case isn't very compelling, because it has
been doable easily in standard C since K&R, to wit:

while( *ptr && (ptr++, val--, 1) ){ ... }

(This assumes of course that writing such code has
been judged acceptable style, as to which I am
expressing no opinion; I'm just pointing out that
it's possible.)

What was I thinking??? This isn't the same as your
proposed construct at all. In fact now I don't see the
point of your example; presumably 'val' and 'ptr' are
independent, so this example could be written just as

while( val--, *ptr++ ){
 
B

Ben Bacarisse

Kaz Kylheku said:
This is not a () construct. It's just

expr1 ? expr2 : expr3

that you added parentheses around.


Comma operator:

while (ptr += 1, val --, *ptr) ...

The result was intended to be the value of the first expression.
Following the rules as they were specified, the literal translation
would seem to be

while (*ptr, ptr += 1, val--, ptr[-1]) ...

from which we can get

while (ptr += 1, val--, ptr[-1]) ...

and finally

while (val--, *ptr++) ...

which is Tim's translation.

FWIW, Algol 68C had "displacement operators" that are to assignment
operators what x++ is to ++x. E.g. x :=:= y assigns y to x but returns
the prior value. This can be combined with an operator, so that
x +:=:= 1 is the same as x++ in C. (I may be misremembering the syntax.)

<snip>
 
P

Paul N

Is there some way to concoct a two expression variant that
acts like this (whatever the solution is, it has to go within () ):

   ( expr1 ?? expr2 )  // ?? isn't legal. used to show approx. syntax

Where
   the value returned is expr1
   expr2 is always evaluated
   expr2 is evaluated after expr1
   The value of expr2 is not used for the () logic, it is just
      evaluated for side effects.

Funnily enough, I suggested this a bit ago. See my thread of August
10, 2009 entitled "Reverse comma operator?" at
http://groups.google.com/group/comp...719938?hl=en&lnk=gst&q=gw7rib+comma+operator#
.. It wasn't popular.

Regards.
Paul.
 
M

mathog

Tim said:
This use case isn't very compelling, because it has
been doable easily in standard C since K&R, to wit:

while( *ptr && (ptr++, val--, 1) ){ ... }

No cigar - if *ptr is false expr2 is not evaluated.

Hard to see how to make this work with logic statements because
the outcome of () must only depend on expr1, and if it does expr2
will not be evaluated in some instances, but the requirement was that
expr2 must always be evaluated.

A comma list will work if a temporary variable is allowed:

while (tmp=*ptr, ptr++, val--, tmp)

Can it be done without an explicit temporary variable? I'm thinking no,
unless there is some way to coerce the compiler into creating one
implicitly.

Ben Bacarisse gave this:

while (ptr += 1, val--, ptr[-1]) ...

which does not use a temporary variable, and works for the toy example,
but isn't a general solution since it depends on the value of expr1 not
being changed by evaluating expr2. That isn't guaranteed.
 
B

BartC

FWIW, Algol 68C had "displacement operators" that are to assignment
operators what x++ is to ++x. E.g. x :=:= y assigns y to x but returns
the prior value. This can be combined with an operator, so that
x +:=:= 1 is the same as x++ in C. (I may be misremembering the syntax.)

It sounds a useful construct, although I've never come across it before. And
it sounds like it can be implemented efficiently too, using machine exchange
instructions, at least for the plain assignment version.

That's a hell of a syntax though..

But applied to the OP's problem, I don't think it can help avoid using a
temporary variable:

(t=expr1, t:=expr2)

where ":=" represents the displacement operator. In this case it doesn't buy
much.

Although if we're using imaginary operators, then we might as well go with
the OP's ?? operator, which ticks all the boxes..
 
K

Kaz Kylheku

No cigar - if *ptr is false expr2 is not evaluated.

What you're after is similar to the Lisp PROG1 operator: evaluate
some forms left to right, and then return the value that the leftmost one
returned:

(prog1 x (incf x)) ;; simulate x++, but two evaluations of x

I posed a similar question in another newsgroup. Lisp has an (or ...)
which returns the first argument which is true, and does not evaluate
the rest. This is useful for choosing a default value:

(let ((ice-cream (or (have? :chocolate) ;; prefer chocolate
(have? :strawberry) ;; not available, try strawberry
:vanilla))) ;; fall back on vanilla
...)

There is no clean way to write an OR macro in C even just with two arguments.

I.e.: or(a, b): evaluate a, and return a if it is non-zero, otherwise
evaluate b and return that value.

But you can do this with some temporary variables.

In the program I was working on, all values are of type "val", so no
GCC-specific typeof required. A hidden temporary of type val
covers all uses.

I hacked it with a declarator:

{
uses_or2;

/* ... */

foo(or2(a, b), ...)
}

To use or2, you have to put a uses_or2 somewhere in the lexical scope.

This allows or2 to expand into an expression (not a block that declares
local variables, which cannot return a value, without GCC-specific features).

It's only practical because of the generic typing; otherwise the hack
would have to be even uglier.

uses_or2(int); /* pass in type specifier for the temporary */

Ideally, we could script the compiler so that it realizes that or2 is being
used and adds the equivalent of users_or2 to the lexical scope via an
abstract syntax tree manipulation.
Hard to see how to make this work with logic statements because
the outcome of () must only depend on expr1, and if it does expr2
will not be evaluated in some instances, but the requirement was that
expr2 must always be evaluated.

PROG1 is impossible in C without temporary variables. There is no evaluation
control construct that evaluates two expressions left to right (with or without
a sequence point) but then yields the remembered value of the left one.
A comma list will work if a temporary variable is allowed:

while (tmp=*ptr, ptr++, val--, tmp)

Can it be done without an explicit temporary variable? I'm thinking no,
unless there is some way to coerce the compiler into creating one
implicitly.

Your only tools there are preprocessor macros.

#define uses_prog1(type) \
type prog1_TeMp_stack[8]; \
int prog1_TeMp_ptr = 0

#define prog1(A, B) (prog1_TeMp_stack[prog1_TeMp_ptr++] = (A), \
(B), \
prog1_TeMp_stack[--prog1_TeMp_ptr])

{
uses_prog1(int); /* declare support necessary for prog1 */

while (prog1(*ptr, (ptr++, val--))) {

}
}

The stack allows for to eight levels of safe nesting (with no overrun check).
left-associative nesting (the kind you would usually have) is no problem even
with just a single temporary variable, but this won't work:

prog1(a, prog1(b, c))

With the stack mechanism, the inner prog1(b, c) will use its the [1] stack
location for the temporary and not disturb the saved value of a at the at the
[0] location.
 
K

Keith Thompson

mathog said:
C has two () constructs which return a value:

( expr1 ? expr2 : expr3)
( expr )

I think you've misunderstood the use of parentheses in these examples.

Any expression can be enclosed in parentheses. The result has the same
type, value, and side effects as the unparenthesized expression, but
since it's a primary expression it can be used to specify the
association of operators with operands, as in ``(x + y) * z''.

Both constructs you show are simply parenthesized expressions. The only
difference is what the unparenthesized expression looks like.
As far as I can tell the language does not define a two expression
variant.

So far, you haven't said what such a "two expression variant" would do.
You do describe it below; my point is that there's no obvious meaning
for a "two expression variant".
Is there some way to concoct a two expression variant that
acts like this (whatever the solution is, it has to go within () ):

( expr1 ?? expr2 ) // ?? isn't legal. used to show approx. syntax

Where
the value returned is expr1
expr2 is always evaluated
expr2 is evaluated after expr1
The value of expr2 is not used for the () logic, it is just
evaluated for side effects.

What you're describing is just like the existing comma operator, except
that the result is the value of the *first* operand rather than the
second.

You're not the first person to suggest such a thing:

http://groups.google.com/group/comp.lang.c++/browse_thread/thread/3d3babd460162cac?pli=1

But since you can achieve the same thing with a temporary of the
appropriate type:

( tmp = expr1, expr2, tmp )

and since there doesn't seem to be a great deal of demand for this
functionality, I don't think it's worth adding to the language.
 
B

Ben Bacarisse

BartC said:
It sounds a useful construct, although I've never come across it
before. And it sounds like it can be implemented efficiently too,
using machine exchange instructions, at least for the plain assignment
version.

That's a hell of a syntax though..

Yes though I may have it wrong. It might be :=: and +:=: etc. The only
search results I can find are me talking about them on Usenet so that's
rather unreliable as confirmation!

<snip>
 
B

Ben Bacarisse

mathog said:
No cigar - if *ptr is false expr2 is not evaluated.

Quite, but did you not see Tim's correction? It arrived here over three
hours before this post.

Ben Bacarisse gave this:

while (ptr += 1, val--, ptr[-1]) ...

My post also included his:

while (--val, *ptr++) ...
which does not use a temporary variable, and works for the toy
example, but isn't a general solution since it depends on the value of
expr1 not being changed by evaluating expr2. That isn't guaranteed.

Neither really depends on the value of expr1 not being changed by expr2.
Mine relies on being able to compensate for any change, and Tim's relies
on being able to re-order the changes. I agree that neither offers a
general pattern, but it shows that a compelling use case has yet to be
produced!
 
B

BartC

mathog said:
No cigar - if *ptr is false expr2 is not evaluated.

Hard to see how to make this work with logic statements because
the outcome of () must only depend on expr1, and if it does expr2
will not be evaluated in some instances, but the requirement was that
expr2 must always be evaluated.

Is there any programming language** where you've already seen this
construct? That at least might might show that someone else considers it
useful!

(**Not including Lisp, which can obviously solve any conceivable programming
problem thrown at it. And the construct needs to be already present, not
created by language extension.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top