Why can't I do ++i++ in C-like languages?
Asked Answered
P

8

29

Half jokingly half serious : Why can't I do ++i++ in C-like languages, specifically in C#?

I'd expect it to increment the value, use that in my expression, then increment again.

Peppergrass answered 2/10, 2009 at 18:20 Comment(11)
Even if it did work, you shouldn't because you shouldn't hate life :(. Seeing ++i++ would make me sad in any context, regardless of the explanation.Fernyak
I didn't know there was the "stupid-operator-tricks" tag, thanks John!Peppergrass
@zvolkov: there wasn't... John created this tag just for your question ;)Blubberhead
while we're at it, how about i++++ and i++++++ and i++++++++...Giliana
Can you imagine if i++++++ really was legal? There goes readability!Discontented
I once used ++i-- to mean "i + 1" in a case where inc/dec were defined but not the + operator. It was accompanied by a comment to explain, but the mix of operators did have a practical use.Marlinemarlinespike
This was a pretty interesting read. And @sean what language was that in? Based on all the answers here... that shouldn't have compiled (awesome as it may be).Spherics
Looks like analog-literals time eh :)Macklin
Jon Seigel: "i++--++--" looks like you're programming in brain f*ck :pRocher
It was C++, sorry about the lack of parens - I couldn't remember which side they ended up onMarlinemarlinespike
Read: Why C program giving "L-value required error"?Beauty
P
59

Short answer: i++ is not an "lvalue", so can't be the subject of an assignment.

Parvis answered 2/10, 2009 at 18:22 Comment(10)
post-increment has precedence over pre-increment; you want to say that i++ isn't an lvalue, not ++i. (Though it doesn't work either way)Tracee
++i is an lvalue, so (++i)++ would be valid but for the fact that it writes to i twice without an intervening sequence point. The problem is that the grammar specifies that ++i++ is equivalent to` ++(i++)`.Montane
@Charles Bailey: ++i is an lvalue in C and C++, but IIRC not in C#.Coughlin
++i is not an lvalue in C. Try assigning to it and see what your compiler says.Tracee
Good point, well made. What I was trying to highlight, though, was more along the lines of "the question says specifically C#", rather than "I can't remember the awkward differences between C and C++".Coughlin
OK, my previous argument definitely applies to C++. In any case, with respect to the original question, it is irrelevant whether ++i is an lvalue, because i++ definitely isn't and that's the way the grammar works for ++i++ for all C-like languages.Montane
@stephentyrone: yes, you're right. Answer edited accordingly.Parvis
In C++ ++i or i++ might or might not be an lvalue. It all depends on whether or not operator overloading is in effect for that particular expressions and whether or not the return type of the operator++(/*which one?*/) is an lvalue. Remember that the overloaded operator could return whatever it likes, even if it wouldn't make sense in the 'classic' use of the operator. Usually that would be a bad, bad thing to do. But take a look at operator<<() for streams - it returns an lvalue where the built-in operator << returns an rvalue.Sueannsuede
If you call a variable "i" and it has a user-defined type, then you deserve for people to fail to realise you've overloaded operators.Coughlin
What if the variable is called 'status' or 'curValue'?Sueannsuede
A
86

Though the short answer "it's not an lvalue" is correct, that's perhaps just begging the question. Why isn't it an lvalue? Or, as we say in C#, a variable.

The reason is because you cannot have your cake and eat it too. Work it out logically:

First off, the meaning of a ++ operator in C#, whether postfix or prefix, is "take the value of this variable, increment the value, assign the new value to the variable, and produce a value as a result". The value produced as the result is either the original value or the incremented value, depending on whether it was a postfix or a prefix. But either way, you produce a value.

Second, the value of a variable is always the current contents of that variable. (Modulo certain bizarre threading scenarios that would take us far afield.)

I hope you agree that these are perfectly sensible rules.

Now it should be clear why the result of i++ cannot be a variable, but in case it isn't, let me make it clear:

Suppose i is 10. The meaning of i++ should be "get the value of i — 10 — increment it — 11 — store it — i is now 11 — and give the original value as the result — 10". So when you say print(i++) it should print 10, and 11 should be stored in i.

Now suppose the meaning of i++ is to return the variable, not the value. You say print(i++) and what happens? You get the value of i — 10 — increment it — 11 — store it — i is now 11 — and give the variable back as a result. What's the current value of the variable? 11! Which is exactly what you DON'T want to print.

In short, if i++ returned a variable then it would be doing exactly the opposite of the intended meaning of the operator! Your proposal is logically inconsistent, which is why no language does it that way.

Age answered 2/10, 2009 at 18:47 Comment(3)
Actually the pre increment is supposed to increment the value and return a reference to the original object not a value.Ninnette
Martin, my explanation is both precise and accurate; I'm talking about the C# semantics, not the C or C++ semantics, because that is what the original poster specifically asked for. I'll make that more clear in the text.Age
@Martin York: Yes, and that's why (in those languages) (++i)++ is still valid. However, ++i++ is actually equivalent to ++(i++), as postincrement has higher precedence than preincrement.Axiomatic
P
59

Short answer: i++ is not an "lvalue", so can't be the subject of an assignment.

Parvis answered 2/10, 2009 at 18:22 Comment(10)
post-increment has precedence over pre-increment; you want to say that i++ isn't an lvalue, not ++i. (Though it doesn't work either way)Tracee
++i is an lvalue, so (++i)++ would be valid but for the fact that it writes to i twice without an intervening sequence point. The problem is that the grammar specifies that ++i++ is equivalent to` ++(i++)`.Montane
@Charles Bailey: ++i is an lvalue in C and C++, but IIRC not in C#.Coughlin
++i is not an lvalue in C. Try assigning to it and see what your compiler says.Tracee
Good point, well made. What I was trying to highlight, though, was more along the lines of "the question says specifically C#", rather than "I can't remember the awkward differences between C and C++".Coughlin
OK, my previous argument definitely applies to C++. In any case, with respect to the original question, it is irrelevant whether ++i is an lvalue, because i++ definitely isn't and that's the way the grammar works for ++i++ for all C-like languages.Montane
@stephentyrone: yes, you're right. Answer edited accordingly.Parvis
In C++ ++i or i++ might or might not be an lvalue. It all depends on whether or not operator overloading is in effect for that particular expressions and whether or not the return type of the operator++(/*which one?*/) is an lvalue. Remember that the overloaded operator could return whatever it likes, even if it wouldn't make sense in the 'classic' use of the operator. Usually that would be a bad, bad thing to do. But take a look at operator<<() for streams - it returns an lvalue where the built-in operator << returns an rvalue.Sueannsuede
If you call a variable "i" and it has a user-defined type, then you deserve for people to fail to realise you've overloaded operators.Coughlin
What if the variable is called 'status' or 'curValue'?Sueannsuede
G
18

Because you care about a next programmer maintaining (or trying to re-write)your code, long after you're fired for defying popular conventions.

Ghislainegholston answered 2/10, 2009 at 18:22 Comment(3)
This is why it's "immoral", but in fact it's illegal as well as immoral.Parvis
unfortunately lots of c++ (hopefully to be fixed in the next standard) are immoral and politically incorrect to use, yet legal...Ghislainegholston
that's a comment relating to the design of a program, more than relating to the design of a language...Fonteyn
K
9

I tested (++i,i++) as a workaround:

#include <stdio.h> 

int main(){
  int i=0;

  printf(" i:         %i\n", i         );
  printf(" (++i,i++): %i\n", (++i,i++) );
  printf(" i:         %i\n", i         );
}

Result:


i:         0
(++i,i++): 1
i:         2
Krispin answered 2/10, 2009 at 19:6 Comment(1)
Looks like some kind of emoticon. The Spruce Goose flying upside-down?Caltanissetta
T
6

Because the result of i++ isn't an lvalue.

Tracee answered 2/10, 2009 at 18:26 Comment(2)
++i would be evaluated first.Dealer
post-increment has precedence, actually.Tracee
P
3

I believe that the increment(or decrement) operator needs an lvalue to assign to. However ++i is not an lvalue, it's an expression. Someone better versed in compilers might be able to clarify if there is any technical reason for this constraint.

Part answered 2/10, 2009 at 18:23 Comment(7)
The type of ++i is an lvalue in C.Montane
Could you clarify this a bit? I tried to compile "++i = 4;" and get an error saying that an lvalue is required on the left hand of the operand. Maybe my misunderstanding is in the definition of lvalue? I understood it to be something that could be assigned to.Part
Section 5.3.2 of the standard, paragraph 1: "The value is the new value of the operand; it is an lvalue." (This is of course the paragraph on "prefix ++".) Of course, "++i = 4;" is also an attempt to change the value of i twice without an intervening sequence point, and therefore undefined behavior. "f(++i)" with "int f(int &)" would involve a sequence point, and should be legal.Fairfield
OK, it's definitely an lvalue in C++, I now can't find a definitive answer for C.Montane
Either way, it's not relevant to the question as ++i++ would be equivalent to ++(i++) so it only matters whether the "not an lvalue" issue applies to i++ (which it does).Montane
You should clear your wording: An lvalue is an expression. What it isn't traditionally is a value, because a value is the interpretation of the object's contents (in C and C++ at least). In the most recent draft, 5.3.2 reads "The result is the updated operand; it is an lvalue" - no mentioning of "value" anymore.Macklin
.. Unless of course your answer is about C, in which case ++i is in fact not an lvalue. In the C99 draft n1256, you find this: "An assignment expression has the value of the left operand after the assignment, but is not an lvalue", while it says that ++i is equivalent to i+=1. In addition, any lvalue is automatically converted to a non-lvalue (rvalue) in most contexts in C.Macklin
T
3

From section 7.5.9 of the C# 3.0 specification:

The operand of a postfix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. The result of the operation is a value of the same type as the operand. If the operand of a postfix increment or decrement operation is a property or indexer access, the property or indexer must have both a get and a set accessor. If this is not the case, a compile-time error occurs.

Additionally, the post-increment expression (i++) would be evaluated first because it has a higher precedence than the pre-increment (++i) operator.

Titustityus answered 2/10, 2009 at 18:35 Comment(0)
H
0

From C# specification:

The operand of a postfix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. The result of the operation is a value of the same type as the operand.

An increment operator can only be applied to a variable (and ㏇) and it returns a value (not a variable). You cannot apply increment to a value (simply because there is no variable to assign the result to) so in C# you can increment a variable only once.

The situation is actually different for C++. According to C++ specification:

prefix increment or decrement is an lvalue expression

which means that in C++ you can call increment on the result of prefix increment or decrement. I.g. the following C++ code is actually valid:

#include <iostream>

using namespace std;

int main()
{
    int i = 13;

    (--i)++;
    cout<<i<<endl;

    (++i)--;
    cout<<i<<endl;

    return 0;
}

NB: The term lvalue is used in C and C++ only. And for the sake of diversity in C the result of prefix increment is actually rvalue so you can't increment increment in C.
C# language uses term variable_reference for a similar concept:

A variable_reference is an expression that is classified as a variable. A variable_reference denotes a storage location that can be accessed both to fetch the current value and to store a new value.

Harner answered 14/7, 2021 at 11:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.