string literal is an lvalue; other literals are rvalues.

string literal is an lvalue; other literals are rvalues.

Post by Steven T. » Tue, 13 Apr 2004 14:25:29


This is from the draft of the previous version of the Standard:

http://www.yqcomputer.com/ :8086/docs/isocpp/expr.html

2- A literal is a primary expression. Its type depends on its form
(lex.literal). A string literal is an *lvalue*; all other literals are
*rvalues*.

-4- The operator :: followed by an identifier, a qualified-id, or an
operator-function-id is a primary-expression. Its type is specified by the
declaration of the identifier, qualified-id, or operator-function-id. The
result is the entity denoted by the identifier, qualified-id, or
operator-function-id. The result is an *lvalue* if the entity is a function
or variable. The identifier, qualified-id, or operator-function-id shall
have global namespace scope or be visible in global scope because of a
using-directive (namespace.udir). [Note: the use of :: allows a type, an
object, a function, an enumerator, or a namespace declared in the global
namespace to be referred to even if its identifier has been hidden
(basic.lookup.qual). ]

As I understand the distinction between rvalue and lvalue, an lvalue *can*
appear on the left side of an expression, whereas an rvalue can *only*
appear on the right side. What I don't fully understand is

1) who cares? What I mean to ask is, why is it so important to specify?

I assume it's a way of defining the syntax rules by specifying that lvalues
can go here, but not rvalues, etc. But this seems like the chicken and the
egg almost. There is talk of lvalue to rvalue conversion in 4.1. Is that
just a conceptual artifice, or something the compiler actually does?

2) I'm not sure why a function or a string literal would be considered an
lvalue.

In the case of a function is it because it can be a standalone statement? Or
is it because it can appear in a pure virtual declaration on the lefthand
side of the '='?

--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.yqcomputer.com/ SuSE: http://www.yqcomputer.com/
Mozilla: http://www.yqcomputer.com/
 
 
 

string literal is an lvalue; other literals are rvalues.

Post by alfp » Tue, 13 Apr 2004 19:54:51

* "Steven T. Hatton" < XXXX@XXXXX.COM > schriebt:

If they're not part of expressions.

Another more useful difference is that you can take the address of an lvalue,
but not of an rvalue.

An lvalue denotes a storage location, an rvalue denotes a value sans location,
such as the int value 5.

Thus, an rvalue cannot by itself appear on the left hand side in an
assignment, and that's the basis of the terminology.

But the terminology is a bit misleading: a const lvalue can't appear on the
left hand side of an assignment, either (although what's there must be an
lvalue).




A program that modified the value of 5, say, would be difficult to debug.



I think it's your job to quote the relevant passage in 4.1.

Converting an lvalue to rvalue is often necessary. E.g. you can use an int
variable wherever you can use an int value such as 5. The opposite conversion
is of course not allowed; e.g. you cannot assign to the value 5.




Function: because you must be able to take its address in order to use
function pointers.

String literal: because early C did not have 'const', and so old C functions
that take 'char*' as argument could not be called with literal strings as
actual arguments if string literals were considered rvalues. However, that
may still change. It's just an old compatibility feature on its way out.



No, see above.

--
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

 
 
 

string literal is an lvalue; other literals are rvalues.

Post by Howar » Tue, 13 Apr 2004 20:49:24

"Steven T. Hatton" < XXXX@XXXXX.COM > wrote in message
news: XXXX@XXXXX.COM ...
E.g.,
be
drastically
text-based
find

You're misunderstanding basic data storage concepts here. Having the
constant value 5 in your source code may lead to also having that value in
the compiled machine code, but it's in the *code*, not in a data location.
It becomes just a part of the arguments to a machine code instruction.
Variables, however, are given specific storage space, and the address of
that space is then used as an argument to machine code instructions. (Of
course, sometimes the storage is temporary, like a register, and in those
cases the register name is used instead of an address.) Look at the
assemble language generated by defining, initializing, and assigning
variables in your program, and you'll get the picture. (But turn off
optimizations, because a very small program may have too much of what you
want to see optimized into register data.)

-Howard







 
 
 

string literal is an lvalue; other literals are rvalues.

Post by Steven T. » Tue, 13 Apr 2004 23:58:47

lf P. Steinbach wrote:


If I have a literal 5 in my source code it begins life as an ascii
character. That is translated and used by the compiler. It is either
consumed to produce a result that somehow makes its way into the runtime
instance of the program, or it is directly inserted into the runtime. E.g.,

const int x = 5 * 125; // 5 is consumed and forgotten

const int y = 5; // 5 lives a long and significant life

int f(const int& n){
return 5 * n; // 5 has to stick around in the shadows somewhere
}


I guess some of the difficulty is that we are talking about two drastically
different models of the same abstract problem space. One is the text-based
source code, the other is the runtime representation of the program in
storage. When I read your statement that const lvalue can't appear on the
lefthand side of an assignment I thought I understood and agreed with it.
Then I wrote the two examples above. Does this mean that x and y only
become const lvalues after they are initialized (defined)?

I will grant that I know of no way to specify the location of 5 in the
functon f above, but it has to have some kind of representaton in runtime
storage. I'm not sure if it would be categorize as an rvalue. I'm just
using it to try to get an undstanding of what parts of the source code find
their way into the runtime image, and how they are represented there.

I believe I undstood this stuff about ten years ago.


Agreed. But I knew that before I knew it was called an rvalue.



This is a better link than the one I posted previously in this thread:
http://www.itga.com.au/~gnb/wp/cd2/

4.1 Lvalue-to-rvalue conversion [conv.lval]

1 An lvalue (_basic.lval_) of a non-function, non-array type T can be
converted to an rvalue. If T is an incomplete type, a program that
necessitates this conversion is ill-formed. If the object to which
the lvalue refers is not an object of type T and is not an object of a
type derived from T, or if the object is uninitialized, a program that
necessitates this conversion has undefined behavior. If T is a non-
class type, the type of the rvalue is the cv-unqualified version of T.
Otherwise, the type of the rvalue is T. 1)

2 The value contained in the object indicated by the lvalue is the
rvalue result. When an lvalue-to-rvalue conversion occurs within the
operand of sizeof (_expr.sizeof_) the value contained in the refer-
enced object is not accessed, since that operator does not evaluate
its operand.


But to say an lvalue is converted to an rvalue doesn't mean much to me.
Does something actually happen in the CPU to change the representation of
the object? Also, if the rvalue /is/ an object, it has a storage location
doesn't it?


There's something I'm missing here. What is the difference in how the
program represents and process the same object as an rvalue or an lvalue?

--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
 
 
 

string literal is an lvalue; other literals are rvalues.

Post by alfp » Wed, 14 Apr 2004 00:32:06

"Steven T. Hatton" < XXXX@XXXXX.COM > schriebt:

Oops, that was not general enough. The function


std::string foo(){ return "Hey"; }


returns an rvalue because a temporary object is an rvalue. You cannot take
its address because conceptually it has no storage location. But in terms of
machine code it really has, in this particular case, and if you then define


void bar( std::string const& s ){ std::cout << &s << std::endl; }


and call it like


bar( foo() );


that location may be used directly, and if so then 'bar' will display it
(also the object may itself have a function that gives its address).

No, one does not need to be stupid in order not to think of that.

The exact rules for this are _very_ complicated & hazy, e.g. causing a problem
in Andrei Alexandrescu's original Mojo design (which was reviewed by hundreds
of people before one really smart fellow spotted the problem).

On the other hand in ordinary programming the conceptual model is very simple
and suffices.

Think of an rvalue as the integer value 5, and that's all you need.



Yes. They do not exist before their initializations. And initialization is
not assignment, in spite of having nearly the same syntax.

The reason for initialization not being assignment (in C++) is that
initialization may have to construct an object from raw memory, whereas
assignment must change an existing object, e.g. deallocate stuff.



It might. In the case of 'a = b + 1;' the lvalue 'b' may be converted to
rvalue by loading the contents of &b into a processor register. For example.



See above. It may. But you cannot directly take the address of an rvalue,
and you cannot for sure obtain that address unless it's an object that has
a function that returns the address, and especially in the case of built-in
types it may not really have a storage location except in the sense of perhaps
being embedded in a machine code instruction, and for a typical optimizing
compiler even that may not exist; the rvalue might exist only conceptually,
which is much of the point.



The difference is in what the program text is allowed to do. E.g. you cannot
change the value 5. And you cannot call non-const functions on rvalues.

--
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
 
 

string literal is an lvalue; other literals are rvalues.

Post by David Harm » Wed, 14 Apr 2004 04:03:52

On Mon, 12 Apr 2004 10:58:47 -0400 in comp.lang.c++, "Steven T. Hatton"
< XXXX@XXXXX.COM > wrote,

That may be, but there is no requirement in C++ that the source
character set in which your program is written is ASCII. The C++
standard turns backflips to ensure that it does not specify more than is
necessary for a proper implementation of C++, and thereby impose
unnecessary restrictions on portability and efficiency. If you wish to
think about standard portable C++, you must likewise abandon many
assumptions about implementation.

A good one to start with is guesswork about what things do or do not
occupy what memory. Especially consts and temporaries.


5 is neither consumed nor forgotten. 5 is eternal and unchanging.
The 5 you know is the same one Euclid knew.

But, C++ requires that the above has the same effect as
const int x = 625;


No, you are thinking of the lifetime of y. y is "alive" in whatever
part of your program that declaration is visible. But y might never
occupy run-time memory, if the generated code has no need to make it do
so, ie. if you never take the address of y.


This might possibly for instance be implemented by something resembling
return (n << 2) + n;


I suppose the representation of 5 in runtime storage in ((n << 2) + n)
is implicit in the sequence of some machine instructions in the
generated code. It certainly does not _have to_ correspond to a
location in memory with the value 5 in it, it is a rvalue.
Is that what you are trying to say?
 
 
 

string literal is an lvalue; other literals are rvalues.

Post by Steven T. » Wed, 14 Apr 2004 05:15:18

avid Harmon wrote:


Just to be pedantic, the Standard /does/ specify that the basic source
character set is a subset of the ASCII character set:

15) The glyphs for the members of the basic source character set are
intended to identify characters from the subset of ISO/IEC 10646 which
corresponds to the ASCII character set.


I don't believe it is really possible to comprehend the intent of the
standard at that level of abstraction.


Euclid knew about integer literals?


"5) This provision is sometimes called the as-if rule, because an
implementation is free to disregard any requirement of this International
Standard as long as the result is as if the requirement had been obeyed, as
far as can be determined from the observable behavior of the program. For
instance, an actual implementation need not evaluate part of an expression
if it can deduce that its value is not used and that no side effects
affecting the observable behavior of the program are produced."

So, technically, I cannot speak in terms of what the implementation actually
does and express the full intention of the Standard.


But, in some sense 5 is recoverable, whereas in the first example, it is
not. I had implicitly assumed y was used.


Yes, I had considered that possibility.


No. " I'm not sure if it would be categorize as an rvalue. I'm just
using it to try to get an understanding of what parts of the source code
find their way into the runtime image, and how they are represented there."

Please read the portions of the Standard I quoted above so you are aware of
what I already know. That should help you in determining what parts of my
posts are informally making assumptions such as, 'virtual functions are
implemented using vtbls', or, 'excessive inclusion of unnecessary headers
leads to slower compile times'.

If it's not clear what assumptions I have made, please ask for
clarification.
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
 
 
 

string literal is an lvalue; other literals are rvalues.

Post by Steven T. » Wed, 14 Apr 2004 05:22:28


One man's data is another man's instruction. ;-)


Actually, I thought I was making the point, not missing it. I will admit I
was not sure how exactly to express it.


That is very good advice. Thank you.
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.yqcomputer.com/ SuSE: http://www.yqcomputer.com/
Mozilla: http://www.yqcomputer.com/
 
 
 

string literal is an lvalue; other literals are rvalues.

Post by Steven T. » Wed, 14 Apr 2004 22:30:42


I looked this up in Sebesta's _Concepts of Programming Languages_, and found
that he rather bluntly says: "The address of a variable is sometimes called
its l-value, and the value is sometimes called its r-value."

My edition is older than this one:
http://www.yqcomputer.com/ ,4096,0321193628,00.html


Then we have K&R: "An object is a manipulatable region of storage; an lvalue
is an expression referring to an object....The name 'lvalue' comes from the
assignment expression E1 = E2 in which the left operand E1 must be an
lvalue expression."

http://www.yqcomputer.com/


That seems worth considering. But, if we have an lvalue and its contents
are loaded into a register, but its existing storage is not released, then
it didn't /become/ an rvalue, it spawned an rvalue. I think?

--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.yqcomputer.com/ SuSE: http://www.yqcomputer.com/
Mozilla: http://www.yqcomputer.com/
 
 
 

string literal is an lvalue; other literals are rvalues.

Post by alfp » Wed, 14 Apr 2004 22:36:21

* "Steven T. Hatton" < XXXX@XXXXX.COM > schriebt:

Right.

Perhaps you've been bitten by a misunderstanding I once had about
"conversion".

Saying "A is converted to B" is often just a way of saying "form B is computed
from form A", and does not necessarily imply a replacement of A with B.

--
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
 
 

string literal is an lvalue; other literals are rvalues.

Post by Steven T. » Mon, 19 Apr 2004 01:29:18


Actually, I'm usually pretty aware of that notion. It's the whole
philosophy of information verses material posession. I can give a person
an idea, and still have it. Of course there are issues of relative
advantage of not sharing you ideas or knowledge in order to maintain some
kind of advantage. For the most part, that is simply contrary to my
nature. But I digress...


And when you do that a few million times, you end up with a whole bunch of
wasted storage. Actually, as I understand things, destroying A on every
calculation, is exactly what Mathematica does. The entire expression is
transformed according to the rules it expresses, and it is placed in new
storage. I really don't know the details, but that's what I understood
fromm one knowlegible person's explanation. Interestingly, Mathematica is
very much a form of self-referential metaprogramming.

I just found this:

"We can allocate and use "variables" that do not have names, and it is
possible to assign to strange-looking expressions (e.g., *p[a+10]=7).
Consequently, there is a need for a name for "something in memory." This is
the simplest and most fundamental notion of an object. That is, an /object/
is a contiguous region of storage; an /lvalue/ is an expression that refers
to an object" - Bjarne Stroustrup TC++PL(SE)

--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.yqcomputer.com/ SuSE: http://www.yqcomputer.com/
Mozilla: http://www.yqcomputer.com/
 
 
 

string literal is an lvalue; other literals are rvalues.

Post by alfp » Wed, 21 Apr 2004 10:38:46

* XXXX@XXXXX.COM (Alf P. Steinbach) schriebt:

Boink! That was the sound of hand against empty skull. Reading another
thread it finally filtered up from my unconsciousness that what I wrote
many days ago had to be (perhaps subtly) W R O N G.


#include <iostream>

struct X
{
int my;
X(): my( 0 ) {};
X& set( int x ){ my = x; return *this; }
};

X foo(){ return X(); }

int main()
{
std::cout << foo().set( 1234 ).my << std::endl;
}


I think it's _best_ to not do such things, but that's far cry from 'cannot'.

But before leaving this, perhaps best to check with the standard that foo()
is really an rvalue. Let's see. Yep,


?.10/5 The result of calling a function that does not return a reference
is an rvalue.


Perhaps also best to check whether the result is well-defined. But that's not
nearly as clear in the standard. It states


?.10/10 An lvalue for an object is necessary in order to modify the
object except that an rvalue of class type can be used to modify
its referent under certain circumstances. [Example: a member
function called for an object (9.3) can modify the object]


seemingly without further specifying the "certain circumstances", and


?.10/14 If an expression can be used to modify the object to which it
refers, the expression is called modifiable. A program that
attempts to modify an object through a nonmodifiable lvalue or
rvalue expression is ill-formed.


seemingly without defining "modifiable" -- two earlier paragraphs define
pointers to functions and pointers to incomplete types as modifiable, but that
does not include class types, and not other pointer types.

I'm glad I'm not a lawyer.

(E-mailed copy to Stephen in case he doesn't follow this thread anymore.
Sorry for the mis-information.)

--
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?