www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - why are Assign Expressions r-values?

reply BCS <ao pathlink.com> writes:
Why is this not allowed

foo(inout int a);

int a;

foo(a=1);

The reason the compiler objects seems to be that the "semantic value" of 
an assign expression is the value that was assigned. However if the "semantic 
value" were the LHS (the variable assigned to) then in most cases the effect 
would be exactly the same, however the expression could be used as an l-value. 
Mostly this would be useful with functions that take inout args but some 
other uses might exist.
Apr 27 2007
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
BCS wrote

 however the expression could be used as an l-value

Because one can overload the assignment, your question has a generalization: given a function with exactly one "ref" or "out" parameter, why is this function an r-value? example: int f( int i, ref int j){ } now the semantics of an assignment like f( a, f( b, c))= d; should be clear. -manfred
Apr 27 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Manfred,

 BCS wrote
 
 however the expression could be used as an l-value
 


Even so the semantics would work, do the assignment as normal (function call or otherwise) and then take the symbol in the LHS and use it as the "value" of the expression.
 your question has a
 generalization:
 
 given a function with exactly one "ref" or "out" parameter, why is
 this function an r-value?
 
 example:
 int f( int i, ref int j){ }
 now the semantics of an assignment like
 
 f( a, f( b, c))= d;
 
 should be clear.
 
 -manfred
 

In that case there is no named symbol to use for the outer call. In the assign case (even when opAssign is overloaded) there is always a LHS symbol that is an l-value that can be used.
Apr 27 2007
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
BCS wrote

 In that case there is no named symbol to use for the outer call.

-manfred
Apr 28 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Manfred,

 BCS wrote
 
 In that case there is no named symbol to use for the outer call.
 

-manfred

Their isn't really, It just seemed to be a good way to separate them from temporaries. The real distinction is that it is something that will persist (and be accessible) after the expression/function call. That also brings up a point that has been floated a time or two before. What would be a good way to call a function with an out arg and say "stuff something here and discard it when your done", the same goes for inout but with the added "give it an initial value of ---" void fo(out int i, inout int j); fo(void, 1); // call fo with a temporary variable for i and a temp initialized to 1 for i.
Apr 28 2007
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
BCS wrote:
 Reply to Manfred,
 
 BCS wrote

 In that case there is no named symbol to use for the outer call.

-manfred

Their isn't really, It just seemed to be a good way to separate them from temporaries. The real distinction is that it is something that will persist (and be accessible) after the expression/function call. That also brings up a point that has been floated a time or two before. What would be a good way to call a function with an out arg and say "stuff something here and discard it when your done", the same goes for inout but with the added "give it an initial value of ---" void fo(out int i, inout int j); fo(void, 1); // call fo with a temporary variable for i and a temp initialized to 1 for i.

I'd be tempted to just use foo(0, 1); Since the first argument's going to be re-initialised anyway. That said, having a way to specify "I don't care what goes here" would be nice. The problem with using void would be functions like this: void ba(out int* i, inout int j); If you specify the first argument as void, what are you actually saying? Create temporary storage for the first argument, or actually pass void? There was a thread a while back about being able to pass an argument's default without having to look it up like so: void baz(int i = 42); baz(default); Maybe that would be more useful. AFAIK, you can't have an inout or out argument that also has a default value, so they wouldn't conflict. On a related note... I've always been bemused that the only compiled language I've *ever* used that had reference arguments and actually allowed you to pass an immediate or temporary into them was... Visual Basic. It seems incongruous that such a widely panned language like VB does something so obvious that neither C++ nor D does. I remember learning C++ and being dumbfounded that it didn't work. Take my vector library for example. Because functions with inline assembler can't be inlined, and we don't have vector intrinsics, all the functions that use SSE take inout arguments to avoid having to do a redundant stack copy. The problem is that code like this: distToInter = (origin + (interT*ray)).normSq; that works with in parameters won't work because (interT*ray) is a temporary. I mean, the result has to be stored somewhere *anyway*, so why can't I pass it by reference? Even more confusing is that the call to normSq works, and since struct member functions get passed a this *pointer*, which means they're technically inout arguments. Guess I still need to pick between efficiency and ease-of-use :P -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
Apr 28 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Daniel,

 BCS wrote:
 
 fo(void, 1);  // call fo with a temporary variable for i and a temp

I'd be tempted to just use foo(0, 1); Since the first argument's going to be re-initialised anyway. That said, having a way to specify "I don't care what goes here" would be nice. The problem with using void would be functions like this: void ba(out int* i, inout int j); If you specify the first argument as void, what are you actually saying? Create temporary storage for the first argument, or actually pass void?

void has no value. Might you be thinking of null?
Apr 29 2007
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
BCS wrote:
 Reply to Daniel,
 
 BCS wrote:

 fo(void, 1);  // call fo with a temporary variable for i and a temp

I'd be tempted to just use foo(0, 1); Since the first argument's going to be re-initialised anyway. That said, having a way to specify "I don't care what goes here" would be nice. The problem with using void would be functions like this: void ba(out int* i, inout int j); If you specify the first argument as void, what are you actually saying? Create temporary storage for the first argument, or actually pass void?

void has no value. Might you be thinking of null?

I could be... I could be. It's certainly a possibility. I would like to think I know what I'm talking about, but clearly that's not true. :P My excuse is that void *should* be a literal (equal to void.init), and hence why I was confused. Not stupid. Nope. -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
Apr 29 2007