?: as an lvalue

W

Willem

Richard Tobias wrote:
) In article <[email protected]>,
)>I think you have lost the track with all due respect. His original did
)>produce an lvalue but a value.
)
) I think the point was that * is an example of an operator that produces
) an lvalue, so it's not necessarily unreasonable for the ?: operator to.

Yes, but * _always_ produces lvalues.

If the ?: operator were to produce lvalues, it can only do so sometimes,
which makes it a lot more difficult to do so.

I think this argument has already been made crossthread, by the way.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
R

Richard

Andrey Tarasevich said:
Richard said:
Richard wrote:
...
I mean I'm OK personally with the way it works in C. I just like to
know what is it exactly in '(c?x:y)=v' that triggers a "I don't really
know what to say" reaction from some people.
because its not a macro? it returns a value. I dont know the legalise
words but it seems "obvious" enough to me, but again it might be because
I am tainted.
Well, unary '*' operator is also not a macro. Yet it evaluates to an
lvalue. Same for '[]' operator (by definition). Do you find this
strange as well?

I think you have lost the track with all due respect. His original did
produce an lvalue but a value.

The "*" made it then an lvalue in the other case.

I dont really know what we are aguing.

I'm not really arguing. The way I interpreted your responses, it
seemed that when someone said that in C++ '?:' would return an lvalue
in this case, you essentially made it clear that you find it unnatural
and/or illogical (again, the way I interpreted your responses). I just
want to know what is it exactly that you find unnatural and/or
illogical.

Firstly I wasnt aware of any C++ talk.

Secondly, I find it unnatural because it is a special operator which,
well, does not return an lvalue. Sure, I'm only arguing for "what it
is". When someone claims "this makes perfect" sense and it does not make
any sense at all in the context of the language being discussed then I
think thats a fair response.
 
L

lawrence.jones

Bartc said:
Exactly why a?b:c can't appear like that on the left-hand-side of an
assignment is a bit of a mystery; after all a, a.b, a->b, a and so on can
all appear on the lhs without the programmer having to insert explicit
address-of operators.


Because b and c are two distinct objects that can have different types,
which makes the type of any resulting lvalue somewhat problematic.

-Larry Jones

Please tell me I'm adopted. -- Calvin
 
R

Richard

Bartc said:
Exactly why a?b:c can't appear like that on the left-hand-side of an
assignment is a bit of a mystery; after all a, a.b, a->b, a and so on can
all appear on the lhs without the programmer having to insert explicit
address-of operators.


Because b and c are two distinct objects that can have different types,
which makes the type of any resulting lvalue somewhat problematic.

-Larry Jones


That should nail it ...
 
A

Andrey Tarasevich

...
Because b and c are two distinct objects that can have different types,
which makes the type of any resulting lvalue somewhat problematic.
...

Yes, it does. But when the second and the third operand have different
(more precisely: non-compatible) types, there are quite a few things
related to '?:' that are "problematic". The "lvalue" issue is just one
of them. I we approach all of these issues with the same degree of
pessimism, then we should probably prohibit '?:' operator entirely.

A more concrete example: in C language the '?:' operator can be applied
to structures and unions. Of course, it is required that the second and
the third operand have the same type (more precisely: compatible types).
Needless to say, even though the result is not an lvalue, the idea to
allow '?:' with structures immediately runs into the very same
type-compatibility issues you are referring to. Still, it is perfectly
legal in C to apply '?:' to structures. This illustrates the fact that
in the process of language evolution the type-compatibility issue in
'?:' has not been seen as a reason to discard a feature.
 
A

Andrey Tarasevich

Richard said:
Exactly why a?b:c can't appear like that on the left-hand-side of an
assignment is a bit of a mystery; after all a, a.b, a->b, a and so on can
all appear on the lhs without the programmer having to insert explicit
address-of operators.

Because b and c are two distinct objects that can have different types,
which makes the type of any resulting lvalue somewhat problematic.

That should nail it ...


No, that completely misses it. For example, what will happen if you try
to compile this

double* d;
int* i;

1 < 0 ? d : i;

Here's another example

struct A { int i; } a;
struct B { int i; } b;

1 < 0 ? a : b;

I'll answer it for you: in both cases the code is invalid. It won't
compile. Why? Because the existing type-compatibility requirements
imposed on the second and third parameter of '?:' have been violated.
Note, that this is normal C '?:', which returns a non-lvalue. Did that
little "non-lvalue" detail somehow help it to compile in the above
example? No, it didn't.

What it illustrates is that the type-compatibility requirements are
_already_ in the language. They are already there and there's no way
around them. The fact that '?:' returns a non-lvalue in C doesn't really
make things easier. And making '?:' return an lvalue wouldn't really
make things harder.

(And, once again, this is a purely academic argument for me. I'm not
trying to campaign for lvalue-returning '?:')
 
F

Flash Gordon

Andrey Tarasevich wrote, On 31/03/08 21:44:
Richard said:
Exactly why a?b:c can't appear like that on the left-hand-side of an
assignment is a bit of a mystery; after all a, a.b, a->b, a and
so on can all appear on the lhs without the programmer having to
insert explicit address-of operators.
Because b and c are two distinct objects that can have different types,
which makes the type of any resulting lvalue somewhat problematic.

That should nail it ...


No, that completely misses it. For example, what will happen if you try
to compile this


What it illustrates is that the type-compatibility requirements are
_already_ in the language. They are already there and there's no way
around them. The fact that '?:' returns a non-lvalue in C doesn't really
make things easier. And making '?:' return an lvalue wouldn't really
make things harder.

What really nails it is that the operands do not need to be objects.
int i=5;
(i<5)?4:i;

If course, it could be defined as returning an lvalue only if both the
2nd and 3rd operands are lvalues.
(And, once again, this is a purely academic argument for me. I'm not
trying to campaign for lvalue-returning '?:')

Same here.
 
B

Ben Bacarisse

Richard said:
Huh? I must be missing something here or I will be first to
apologise.

I just wanted you to say why it seemed so obvious to you that C
outlaws the construct. I thought that maybe you knew a good reason
why. Lots of languages allow such things.
We already know that

*(c?x:y)=v;

is ok where x and y are pointers.

But (c?x:y)=v;

I dont really know what to say.

OK, that's fine. Your degree of certainty (that the prohibition was
not mysterious) suggested you might have something to say about it.

It is another areas in which C and C++ have diverged. I thought there
was a desire that differences be minimised in what might loosely be
called the "common areas" unless there is a compelling reason to keep
C different. I thought maybe you knew that reason.
 
R

Richard

Andrey Tarasevich said:
Richard said:
Exactly why a?b:c can't appear like that on the left-hand-side of
an assignment is a bit of a mystery; after all a, a.b, a->b, a
and so on can all appear on the lhs without the programmer having
to insert explicit address-of operators.
Because b and c are two distinct objects that can have different types,
which makes the type of any resulting lvalue somewhat problematic.

That should nail it ...


No, that completely misses it. For example, what will happen if you
try to compile this

double* d;
int* i;

1 < 0 ? d : i;

Here's another example

struct A { int i; } a;
struct B { int i; } b;

1 < 0 ? a : b;

I'll answer it for you: in both cases the code is invalid. It won't
compile. Why? Because the existing type-compatibility requirements
imposed on the second and third parameter of '?:' have been
violated. Note, that this is normal C '?:', which returns a


Exactly.
 
B

Bartc

Flash said:
Bartc wrote, On 31/03/08 18:45:
Exactly why a?b:c can't appear like that on the left-hand-side of
an assignment is a bit of a mystery;
There is no mystery about it.

after all a, a.b, a->b, a and so on can
all appear on the lhs without the programmer having to insert
explicit address-of operators.
And that has to do with ?: how?


a: You can write a = x without writing *(&a) = x


You can't do 3 = x


That's true. But when a is a variable, it can appear on the lhs without any
special syntax.
You can't do 5.b or a.5

Then it won't work on the rhs either.
You can't do 5->b or b->5

Nor this.
a: You can write a = x without writing *(a+b) = x


Unless b is a pointer or array name you can't do 5
a?b:c: You CAN'T write a?b:c = x without writing *(a ? &b : &c) = x

You can do a?1:2


On rhs yes. On lhs? I don't think so.
I think you are wrong. Look at the fact that all of the other
operators you mention *require* at least one of the operands to be an
object but neither + nor ?: require and operand to be an object. Then
you should see why it is natural for a?b:c = x to be wrong.

That's true. And probably the reason it was disallowed in C.

But when both selections of ?: /are/ legal lvalues there doesn't seem to be
a particular problem. After all the lhs of an assigment must be an lvalue,
so why not insist on both values of an ?: on the lhs being lvalues?

For example if someone tries to write:

a ? b : c+d = x;

then clearly there's an error. But that's no different from the equally
incorrect:

if (a)
b = x;
else
c+d = x;

I suppose I should put my cards on the table here: I have written compilers
for C-class languages where such an expression on lhs of an assignment is
valid (in fact anything can appear on the lhs provided it yields an lvalue).
So the following nested ?: operation is possible:

(a | b | (c | d | e)) := 100 /* syntax is (a|b|c) not a?b:c */

This assigns 100 to either b, d or e depending on a and c. Not that such a
construct, even the simpler a?b:c form, is used that often! :)

But it's clearly controversial in C.
 
B

Ben Bacarisse

Richard said:
Andrey Tarasevich said:
Richard said:
Exactly why a?b:c can't appear like that on the left-hand-side of
an assignment is a bit of a mystery; after all a, a.b, a->b, a
and so on can all appear on the lhs without the programmer having
to insert explicit address-of operators.
Because b and c are two distinct objects that can have different types,
which makes the type of any resulting lvalue somewhat problematic.

That should nail it ...


No, that completely misses it. For example, what will happen if you
try to compile this

double* d;
int* i;

1 < 0 ? d : i;

Here's another example

struct A { int i; } a;
struct B { int i; } b;

1 < 0 ? a : b;

I'll answer it for you: in both cases the code is invalid. It won't
compile. Why? Because the existing type-compatibility requirements
imposed on the second and third parameter of '?:' have been
violated. Note, that this is normal C '?:', which returns a


Exactly.


That is too terse. It seems unlikely that you agree with Andrey
Tarasevitch since he is explaining why your "that should nail it"
comment was a bit premature.

If you disagree, you would need to have commented on the bit you
clipped:

| What it illustrates is that the type-compatibility requirements are
| _already_ in the language. They are already there and there's no way
| around them. The fact that '?:' returns a non-lvalue in C doesn't
| really make things easier. And making '?:' return an lvalue wouldn't
| really make things harder.

Type-checking (c ? a : b) = v; is not obviously any harder than
type-checking v = (c ? a : b);.
 
F

Flash Gordon

Bartc wrote, On 31/03/08 22:24:
Flash Gordon wrote:


That's true. And probably the reason it was disallowed in C.

But when both selections of ?: /are/ legal lvalues there doesn't seem to be
a particular problem. After all the lhs of an assigment must be an lvalue,
so why not insist on both values of an ?: on the lhs being lvalues?

I didn't say it could not be so defined, merely suggest why it might not
have been defined since the question was asked.

But it's clearly controversial in C.

It would not bother me in the least if the standard was changed to allow it.
 
B

Ben Bacarisse

Flash Gordon said:
Andrey Tarasevich wrote, On 31/03/08 21:44:
Richard said:
Exactly why a?b:c can't appear like that on the left-hand-side of
an assignment is a bit of a mystery; after all a, a.b, a->b, a
and so on can all appear on the lhs without the programmer having
to insert explicit address-of operators.
Because b and c are two distinct objects that can have different types,
which makes the type of any resulting lvalue somewhat problematic.

That should nail it ...


No, that completely misses it. For example, what will happen if you
try to compile this


What it illustrates is that the type-compatibility requirements are
_already_ in the language. They are already there and there's no way
around them. The fact that '?:' returns a non-lvalue in C doesn't
really make things easier. And making '?:' return an lvalue wouldn't
really make things harder.

What really nails it is that the operands do not need to be objects.
int i=5;
(i<5)?4:i;

If course, it could be defined as returning an lvalue only if both the
2nd and 3rd operands are lvalues.


....as indeed it is in that other related language. I don't see why
you think this argument against the construct is so strong. It seems
unlikely that the committee considered the type-checking required to
be too onerous.

I suspect it is more likely to have been a case of there being no
strong reason to alter existing practice, rather than there being some
killer technical reason why it is too hard or does not fit with C's
view of the world.
 
F

Flash Gordon

Ben Bacarisse wrote, On 31/03/08 23:40:
Flash Gordon said:
Andrey Tarasevich wrote, On 31/03/08 21:44:
Richard wrote:
Exactly why a?b:c can't appear like that on the left-hand-side of
an assignment is a bit of a mystery; after all a, a.b, a->b, a
and so on can all appear on the lhs without the programmer having
to insert explicit address-of operators.
Because b and c are two distinct objects that can have different types,
which makes the type of any resulting lvalue somewhat problematic.

That should nail it ...
No, that completely misses it. For example, what will happen if you
try to compile this

What it illustrates is that the type-compatibility requirements are
_already_ in the language. They are already there and there's no way
around them. The fact that '?:' returns a non-lvalue in C doesn't
really make things easier. And making '?:' return an lvalue wouldn't
really make things harder.
What really nails it is that the operands do not need to be objects.
int i=5;
(i<5)?4:i;

If course, it could be defined as returning an lvalue only if both the
2nd and 3rd operands are lvalues.


...as indeed it is in that other related language. I don't see why
you think this argument against the construct is so strong.


I have not been saying it is necessarily strong. I've been giving my
opinion as to why it might not have been allowed.
It seems
unlikely that the committee considered the type-checking required to
be too onerous.

I suspect it is more likely to have been a case of there being no
strong reason to alter existing practice, rather than there being some
killer technical reason why it is too hard or does not fit with C's
view of the world.

That it also possible. Alternatively it might simply be that allowing it
did not occur to them.
 
P

Philip Potter

Flash said:
Bartc wrote, On 31/03/08 18:45:
[discussion of ?: as an lvalue compared to other lvalue expressions]
You can't do 3 = x


You can't do 5.b or a.5

But you can do f().b
E1.E2 is only an lvalue if E1 is an lvalue.
I think you are wrong. Look at the fact that all of the other operators
you mention *require* at least one of the operands to be an object but
neither + nor ?: require and operand to be an object. Then you should
see why it is natural for a?b:c = x to be wrong.

The member access operator . does not require either operand to be an
lvalue; if its first operand is not an lvalue, then the resultant
expression is not an lvalue. This is very similar to the C++ behaviour
of ?: - if both result expressions are lvalues, the overall expression
is an lvalue, otherwise it is not.

I'm not advocating the C++ way, just showing that it is reasonable. I
couldn't care less whether ?: was allowed to be an lvalue or not, but
I'd probably never use it in my code.

Philip
 
B

Bartc

Philip Potter said:
Flash said:
Bartc wrote, On 31/03/08 18:45:
[discussion of ?: as an lvalue compared to other lvalue expressions]
You can't do 3 = x


You can't do 5.b or a.5

But you can do f().b
E1.E2 is only an lvalue if E1 is an lvalue.

Well f().b = x would be an error too. I was pointing out that where a.b=x is
legal, you can write it without all this *(&a+offsetof business, because
compiler magic is being applied.
The member access operator . does not require either operand to be an
lvalue; if its first operand is not an lvalue, then the resultant
expression is not an lvalue. This is very similar to the C++ behaviour of
?: - if both result expressions are lvalues, the overall expression is an
lvalue, otherwise it is not.

I'm not advocating the C++ way, just showing that it is reasonable. I
couldn't care less whether ?: was allowed to be an lvalue or not, but I'd
probably never use it in my code.

I don't think it's that difficult to find uses; the following code uses it
with ++. C does allow this, but the expression needs 'decorating' with
*(&&), although the brackets are advisable here:

#include <stdio.h>
#include <stdlib.h>

int main()
{
int odd=0,even=0;
int i;

for (i=0;i<10000000;++i)
++*(rand()&1 ? &odd : &even);

printf("Odd ratio = %f%%\n",100.0*(double)odd/(double)(odd+even));
}
 
P

Philip Potter

Bartc said:
Philip Potter said:
Flash said:
Bartc wrote, On 31/03/08 18:45:
[discussion of ?: as an lvalue compared to other lvalue expressions]
a: You can write a = x without writing *(&a) = x
You can't do 3 = x

a.b: You can write a.b = x without writing *(&a + offsetof b) = x
You can't do 5.b or a.5
But you can do f().b
E1.E2 is only an lvalue if E1 is an lvalue.

Well f().b = x would be an error too. I was pointing out that where a.b=x is
legal, you can write it without all this *(&a+offsetof business, because
compiler magic is being applied.

That's exactly the point I was making too. I was saying that a.b is
conditionally an lvalue based on a, so why not have a?b:c conditionally
an lvalue based on b and c?
I don't think it's that difficult to find uses; the following code uses it
with ++.
[snip code]

I don't argue that it's impossible to find situations in which case it
could be used, but I wouldn't ever consider it the preferred construct.
It's a style thing.
 
W

Willem

Philip wrote:
) That's exactly the point I was making too. I was saying that a.b is
) conditionally an lvalue based on a, so why not have a?b:c conditionally
) an lvalue based on b and c?

Correct me if I'm wrong, but isn't a.b *always* an lvalue in C ?


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
R

Richard

Willem said:
Philip wrote:
) That's exactly the point I was making too. I was saying that a.b is
) conditionally an lvalue based on a, so why not have a?b:c conditionally
) an lvalue based on b and c?

Correct me if I'm wrong, but isn't a.b *always* an lvalue in C ?

No. Not always :-;

e.g

c = a.b;

Here it is an rvalue ....
 
B

Ben Bacarisse

Richard said:
No. Not always :-;

e.g

c = a.b;

Here it is an rvalue ....

That is not very helpful. If I asked "is 1+2 always an int" would
you reply "no in, float x = 1+2; it is a float"? lvalues often get their
contents taken in order to be turned into rvalues, but that is not
what Willem is asking.

To Willem: no. Section 6.5.2.3 "Structure and union members" para. 3
says of the . operator: "The value is that of the named member, and is
an lvalue if the first expression is an lvalue." This last part has
change bars so it is a recent addition to the text.

Presumably, in:

struct example { int a; };
...
((struct example){42}).a

the result is not an lvalue.
 

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

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top