www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 3378] New: [tdpl] ++x should be an lvalue

reply d-bugmail puremagic.com writes:
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: -------
Oct 08 2009
next sibling parent d-bugmail puremagic.com writes:
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: -------
Oct 09 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Oct 09 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Nov 21 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Nov 22 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Mar 04 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Mar 04 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Mar 04 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Mar 04 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
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: -------
Mar 04 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3378



--- Comment #10 from Andrei Alexandrescu <andrei metalanguage.com> 2010-03-04
08:03:40 PST ---
(In reply to comment #9)
 (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.

There's no need to get worried about this, particularly on Walter's behalf (e.g. the cost of implementing the change etc.). We're already past the point where debate is pointless. If there were any advantage in making things an rvalue, keeping TDPL as it is would never be an issue so there's no need to worry about making shady compromises either. Please no generalizations. Clearly this is a minor issue, and clearly there is a marginal gain for making the blessed thing an lvalue. So let's make it an lvalue and worry about larger issues. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Mar 04 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3378



--- Comment #11 from Walter Bright <bugzilla digitalmars.com> 2010-03-05
22:31:41 PST ---
changeset 409

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 05 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3378



--- Comment #12 from Walter Bright <bugzilla digitalmars.com> 2010-03-06
01:40:56 PST ---
changeset 409

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 06 2010
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=3378


Walter Bright <bugzilla digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |FIXED


--- Comment #13 from Walter Bright <bugzilla digitalmars.com> 2010-03-08
22:25:03 PST ---
Fixed dmd 2.041

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 08 2010