Saturday, January 31, 2009

lvalue/rvalue

I've always wondered what lvalue and rvalue really meant - and why they were different from 'left operand' and 'right operand'.  It's probably because I know more Java than C++, and Java has lvalue and rvalue, but doesn't allow you to do silly things like '++++i;'.

Definitions:
rvalue: static, read only value, generally a number.  Example: 2,  (2+2), (i+2), i++. Similar to 'const' in C++.
lvalue: Can be assigned to but also has a value, generally a variable or an expression that returns a variable.  Examples:  i, (++i), (i += 3), etc.

The distinction comes in when  you look at the type of a value in an expression, for example:
a = 2 + 3;

In this example, a is an lvalue, 2 and 3 are rvalues, and the sum 5 is also a (hidden) rvalue.

a = ++i;

Here, a is an lvalue because it's being assigned to, and i is an lvalue because it is a variable, but critically, (++i) is also an lvalue because the operator '++' returns the variable it's operating on after the incrementation operation, rather than just the resulting value.  This allows expressions like ++++i to compile and have meaning, because they're effectively (++(++i)).

This begs the question: what does a = (++i = i) do?  No idea. 

Why is this more important to C++ programmers than C programmers?  C programmers have to deal with this rvalue/lvalue distinction only if they're writing expressions that have multiple assignments in them, which you generally shouldn't do because it's confusing to read and understand.   C++ programmers have the same problems, but they also have to understand the rules when they use an advanced C++ feature called operator overloading.  This allows objects to respond to operators like '++' with behaviors specific to that object.  For example, an iterator could move to the next object in the list when ++ is called.  

However, there's a big difference between the preincrement form '++i' and the postincrement form 'i++'.  Preincrement returns the lvalue variable i after it performs the 'increment' operation, and postincrement returns the lvalue variable i before it performs the operation. When a C++ programmer implements postincrement, they have to copy the object that is being incremented, and return the old version after incrementing the new one.