Two expression variant of ()

Discussion in 'C Programming' started by mathog, Mar 30, 2012.

  1. mathog

    mathog Guest

    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
    mathog, Mar 30, 2012
    #1
    1. Advertising

  2. mathog

    Kaz Kylheku Guest

    On 2012-03-30, mathog <> wrote:
    > 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.
    Kaz Kylheku, Mar 30, 2012
    #2
    1. Advertising

  3. mathog

    Ben Pfaff Guest

    mathog <> writes:

    > 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 })
    --
    char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[]
    ={0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x7da6aa6a,0xa67f6aaa,0xaa9aa9f6,0x11f6},*p
    =b,i=24;for(;p+=!*p;*p/=4)switch(0[p]&3)case 0:{return 0;for(p--;i--;i--)case+
    2:{i++;if(i)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}
    Ben Pfaff, Mar 30, 2012
    #3
  4. mathog

    Tim Rentsch Guest

    mathog <> writes:

    > 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.)
    Tim Rentsch, Mar 30, 2012
    #4
  5. mathog

    Tim Rentsch Guest

    Tim Rentsch <> writes:

    > mathog <> writes:
    >
    >> 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++ ){
    Tim Rentsch, Mar 30, 2012
    #5
  6. Kaz Kylheku <> writes:

    > On 2012-03-30, mathog <> wrote:
    >> 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) ...


    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>
    --
    Ben.
    Ben Bacarisse, Mar 30, 2012
    #6
  7. mathog

    Paul N Guest

    On Mar 30, 6:37 pm, mathog <> wrote:
    > 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.
    Paul N, Mar 30, 2012
    #7
  8. mathog

    mathog Guest

    Tim Rentsch wrote:
    > 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.
    mathog, Mar 30, 2012
    #8
  9. mathog

    BartC Guest

    "Ben Bacarisse" <> wrote in message
    news:...

    > 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..

    --
    Bartc
    BartC, Mar 30, 2012
    #9
  10. mathog

    Kaz Kylheku Guest

    On 2012-03-30, mathog <> wrote:
    > Tim Rentsch wrote:
    >> 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.


    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.
    Kaz Kylheku, Mar 30, 2012
    #10
  11. mathog <> writes:
    > 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.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Mar 30, 2012
    #11
  12. "BartC" <> writes:

    > "Ben Bacarisse" <> wrote in message
    > news:...
    >
    >> 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..


    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>
    --
    Ben.
    Ben Bacarisse, Mar 31, 2012
    #12
  13. mathog <> writes:

    > Tim Rentsch wrote:
    >> 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.


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

    <snip>
    > 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!

    --
    Ben.
    Ben Bacarisse, Mar 31, 2012
    #13
  14. mathog

    BartC Guest

    "mathog" <> wrote in message
    news:jl5a0s$igo$...
    > Tim Rentsch wrote:
    >> 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.


    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.)

    --
    Bartc
    BartC, Mar 31, 2012
    #14
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Sparrow

    UDF Parameters always Variant - help!!

    John Sparrow, Jul 29, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    448
    John Sparrow
    Jul 29, 2003
  2. Guest

    variant

    Guest, Dec 17, 2003, in forum: ASP .Net
    Replies:
    4
    Views:
    2,236
    John Timney \(Microsoft MVP\)
    Dec 17, 2003
  3. Guest

    variant

    Guest, Dec 17, 2003, in forum: ASP .Net
    Replies:
    1
    Views:
    466
    Natty Gur
    Dec 18, 2003
  4. Guest

    variant issue

    Guest, Dec 17, 2003, in forum: ASP .Net
    Replies:
    1
    Views:
    426
    Chris Jackson
    Dec 17, 2003
  5. GenxLogic
    Replies:
    3
    Views:
    1,263
    andrewmcdonagh
    Dec 6, 2006
Loading...

Share This Page