Jump to page: 1 2
Thread overview
[Issue 3378] New: [tdpl] ++x should be an lvalue
Oct 09, 2009
Don
Nov 21, 2009
Walter Bright
Mar 04, 2010
Walter Bright
Mar 06, 2010
Walter Bright
Mar 06, 2010
Walter Bright
Mar 09, 2010
Walter Bright
October 08, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3378

           Summary: [tdpl] ++x should be an lvalue
           Product: D
           Version: unspecified
          Platform: Other
        OS/Version: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: andrei@metalanguage.com


--- Comment #0 from Andrei Alexandrescu <andrei@metalanguage.com> 2009-10-08 14:12:33 PDT ---
This doesn't compile:

ref int bump(ref int x) { return ++x; }

The error message reveals two other issues:

Error: x += 1 is not an lvalue

1. The increment is rewritten as x += 1, but it shouldn't as it's a fundamentally different operation

2. x += 1 is not a value itself. Indeed this doesn't compile either:

ref int bump(ref int x) { return x += 1; }

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 09, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3378


Don <clugdbug@yahoo.com.au> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |clugdbug@yahoo.com.au


--- Comment #1 from Don <clugdbug@yahoo.com.au> 2009-10-09 06:37:38 PDT ---
(In reply to comment #0)
> 1. The increment is rewritten as x += 1, but it shouldn't as it's a fundamentally different operation

From the spec: "
Overloading ++e and --e
Since ++e is defined to be semantically equivalent to (e += 1), the expression
++e is rewritten as (e += 1), and then checking for operator overloading is
done. "

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 09, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3378



--- Comment #2 from Andrei Alexandrescu <andrei@metalanguage.com> 2009-10-09 09:09:03 PDT ---
(In reply to comment #1)
> (In reply to comment #0)
> > 1. The increment is rewritten as x += 1, but it shouldn't as it's a fundamentally different operation
> 
> From the spec: "
> Overloading ++e and --e
> Since ++e is defined to be semantically equivalent to (e += 1), the expression
> ++e is rewritten as (e += 1), and then checking for operator overloading is
> done. "

I know, I know! That spec must be definitely changed.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
November 21, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3378


Walter Bright <bugzilla@digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bugzilla@digitalmars.com


--- Comment #3 from Walter Bright <bugzilla@digitalmars.com> 2009-11-21 02:16:15 PST ---
I guess, why? Why does ++x need to be an lvalue?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
November 23, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3378



--- Comment #4 from Andrei Alexandrescu <andrei@metalanguage.com> 2009-11-22 17:32:49 PST ---
(In reply to comment #3)
> I guess, why? Why does ++x need to be an lvalue?

1. It's a departure from C. If we do make that departure, we need a good reason, which I don't know of. (Before you reply with that, I do remember you mentioned that dmc yields an rvalue and no client every filed a bug.)

2. For most user-defined types returning a value is considerably more expensive than returning a reference and nontrivial to remove for the compiler when unused (requires context sensitivity). If built-ins return an rvalue and user-defined return a reference, generic code will be gratuitously incompatible across such types.

For me reason #2 is the more important.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 04, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=3378



--- Comment #5 from Walter Bright <bugzilla@digitalmars.com> 2010-03-04 02:40:29 PST ---
C99 says this about ++x:

-------6.5.3.1-------------
The operand of the prefix increment or decrement operator shall have qualified or unqualified real or pointer type and shall be a modifiable lvalue.

Semantics

The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation. The expression ++E is equivalent to (E+=1). See the discussions of additive operators and compound assignment for information on constraints, types, side effects, and conversions and the effects of operations on pointers. The prefix -- operator is analogous to the prefix ++ operator, except that the value of the operand is decremented.
--------6.5.16-------------------
An assignment expression has the value of the left operand after the assignment, but is not an lvalue.
---------------------------------

It is equivalent to x+=1, and therefore not an lvalue.

The C++98 spec also says that ++x is equivalent to x+=1, but says that the result of x+=1 is an lvalue.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 04, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=3378



--- Comment #6 from Andrei Alexandrescu <andrei@metalanguage.com> 2010-03-04 04:17:15 PST ---
(In reply to comment #5)
> C99 says this about ++x:
> 
> -------6.5.3.1-------------
> The operand of the prefix increment or decrement operator shall have qualified or unqualified real or pointer type and shall be a modifiable lvalue.
> 
> Semantics
> 
> The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation. The expression ++E is equivalent to (E+=1). See the discussions of additive operators and compound assignment for information on constraints, types, side effects, and conversions and the effects of operations on pointers. The prefix -- operator is analogous to the prefix ++ operator, except that the value of the operand is decremented.
> --------6.5.16-------------------
> An assignment expression has the value of the left operand after the assignment, but is not an lvalue.
> ---------------------------------
> 
> It is equivalent to x+=1, and therefore not an lvalue.
> 
> The C++98 spec also says that ++x is equivalent to x+=1, but says that the result of x+=1 is an lvalue.

(Still scantily connected.) Wait, I'm confused. C and C++ do not define ++x as x+=1, right? We shouldn't either, for reasons that we've discussed at length before (i.e. there are UDTs for which increment makes sense but addition does not.)

So:

(a) x+=1 is not a part of the discussion about ++x.

(b) Keeping ++x an rvalue is a gratuitous incompatibility with C and C++

(c) Keeping ++x an rvalue requires extensive rework of TDPL (the bump example
is taken from there)

There isn't much reason to debate. It's a trivial change that has only benefits (albeit minor), I suggest we simply make it and move on.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 04, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=3378


Steven Schveighoffer <schveiguy@yahoo.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |schveiguy@yahoo.com


--- Comment #7 from Steven Schveighoffer <schveiguy@yahoo.com> 2010-03-04 04:33:04 PST ---
testing:

[steves@steveslaptop ~]$ cat testit.c
int x;
int * foo()
{
    return &(++x);
}
[steves@steveslaptop ~]$ gcc -c testit.c
testit.c: In function ‘foo’:
testit.c:4: error: lvalue required as unary ‘&’ operand
[steves@steveslaptop ~]$ g++ -c testit.c
[steves@steveslaptop ~]$

So, C (at least in gcc) does not consider ++x an lvalue, C++ (g++) does.

This is consistent with what Walter says.  Choosing one or the other is arbitrarily right or wrong depending on what compatibility you wish to have.

I agree that defining ++x to be equivalent x+=1 for all types of x is bad, but defining it that way for builtins is fine.

I don't see a huge benefit to having ++x return an lvalue.  Why can't you rewrite bump like so?

ref int bump(ref int x) { ++x; return x;}

This should work for all types of x.

In practice, I don't think using ++x as an lvalue comes up much.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 04, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=3378



--- Comment #8 from Andrei Alexandrescu <andrei@metalanguage.com> 2010-03-04 05:12:28 PST ---
(In reply to comment #7)
> testing:
> 
> [steves@steveslaptop ~]$ cat testit.c
> int x;
> int * foo()
> {
>     return &(++x);
> }
> [steves@steveslaptop ~]$ gcc -c testit.c
> testit.c: In function ‘foo’:
> testit.c:4: error: lvalue required as unary ‘&’ operand
> [steves@steveslaptop ~]$ g++ -c testit.c
> [steves@steveslaptop ~]$
> 
> So, C (at least in gcc) does not consider ++x an lvalue, C++ (g++) does.
> 
> This is consistent with what Walter says.  Choosing one or the other is arbitrarily right or wrong depending on what compatibility you wish to have.
> 
> I agree that defining ++x to be equivalent x+=1 for all types of x is bad, but defining it that way for builtins is fine.
> 
> I don't see a huge benefit to having ++x return an lvalue.  Why can't you rewrite bump like so?
> 
> ref int bump(ref int x) { ++x; return x;}
> 
> This should work for all types of x.
> 
> In practice, I don't think using ++x as an lvalue comes up much.

I can't rewrite bump because it's part of a large example illustrating ref. The book is in copyediting now and I must limit changes as much as possible. All other things equal, lvalue is better because there's less rewrite needed.

One extra point to keep in mind: making ++x an lvalue makes compatible implementations for UDTs' ++ cheaper.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 04, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=3378



--- Comment #9 from Steven Schveighoffer <schveiguy@yahoo.com> 2010-03-04 06:09:51 PST ---
(In reply to comment #8)
> 
> I can't rewrite bump because it's part of a large example illustrating ref.

I don't wish to have a largeish debate about this, but this is not a good reason.  My rewritten version illustrates ref just as well.  The only difference between mine and yours is that yours illustrates that ++x is an lvalue.

> The
> book is in copyediting now and I must limit changes as much as possible. All
> other things equal, lvalue is better because there's less rewrite needed.

Less rewrite of the book, more rewrite of the compiler.  It's a shame we have to make a decision based on this.  That being said, you stated before there would be more changes needed in the book.  Can we get an idea of how much of a rewrite we are talking about?

> One extra point to keep in mind: making ++x an lvalue makes compatible implementations for UDTs' ++ cheaper.

Making ++x an lvalue would still be possible with UDTs, you can return whatever you wish from a custom operator.  Even if ++x is an lvalue for builtins it still will be possible to make ++x an rvalue for UDTs.  Returning an lvalue from a UDT is most likely not because it should be used as an lvalue, but more likely because returning an lvalue performs better.  This consideration has little or no bearing on ++x for builtins.  In other words, the fact that UDTs return an lvalue is a side effect that maybe shouldn't really be exploited in generic code.

Superficially, all operators that return classes return lvalues, i.e. for a class A that returns an A on addition and supports assignment from an int will support something like:

a + a = 5;

which doesn't make any sense for value types, but should we make addition of two integers return an lvalue for the sake of generic programming so such statements always compile?  I think we should stop debating about the generic term ++x being an lvalue and focus on whether ++x should be an lvalue for builtin types, simply because the compiler does not control the lvalueness of ++x for UDTs.  When you look at it that way, it's simply a judgement call.

I'm not saying I'm against changing the behavior, it just seems like an insignificant change to me.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
« First   ‹ Prev
1 2