.NET Framework - Applying ++ and += to properties

Asked By Harlan Messinger
15-Dec-09 01:29 PM
If I had

public int Count { get; set; }
int x, y;
...

Count = 0;
Count++;
x = Count;
Count += 1;
y = Count;

what would be the values of x and y? Are both operations treated as
though they were

Count = Count + 1;

or are the semantics different from that?
System.Int32
(1)
Holder.Mutable
(1)
Andersson
(1)
Implament
(1)
Pertains
(1)
Indexers
(1)
Operand
(1)
Extends
(1)
  Patrice replied to Harlan Messinger
15-Dec-09 01:38 PM
Hello,


And if you just try, do you see something unexpected ?


--
Patrice
  Patrice replied to Patrice
15-Dec-09 01:51 PM
Sorry I was surprised as you seemed to know the response and it is very easy
to run this code by yourself. My understanding is now that you perhaps saw
how they perform by running the code but that you never saw them described
(??)

You'll find a description of those operators (and all others you could find)
at :
http://msdn.microsoft.com/en-us/library/6a71f45d.aspx

or are you bothered by something when they are applied specifically to a
property ?

--
Patrice
  Harlan Messinger replied to Patrice
15-Dec-09 01:51 PM
Since the idea came to mind while I was here, and since the idea of "why
or why not" went along with it, I thought I'd just ask.
  Harlan Messinger replied to Patrice
15-Dec-09 02:58 PM
I was following up on another thread I read here in which the semantic
differences between using a member value variable and using an automatic
value property in various contexts was being discussed, and I wondered
how that analysis extends to the semantics of the ++ and += operators.
  Peter Duniho replied to Harlan Messinger
15-Dec-09 04:17 PM
Note that as that previous discussion pertains to properties, it is to
all properties, not just automatic ones.

As far as the semantics of the ++ and += operators goes, hopefully the
C# programming guide on MSDN can help you understand them better.  But
generally:

-- The += is the same as the + operator.  In fact, it uses the +
operator.  When you write x += y, that is the same as x = x + y, with the
caveat that if "x" is evaluated only once (which could be significant if
the "x" is actually a complex expression)

-- The ++ operator may be overloaded, but has the same semantics
regardless (i.e. the overloading may affect the exact modification that
happens, but not the semantics related to what the operator acts on)

Even with a property that is a value type, the use of the ++ and +=
operators should not be an issue.  That's because the expression the
operator affects is still the property.  In the case of the += operator,
that is a consequence of the fact that the expression is equivalent to
using the + operator followed by the = operator.  In the case of the ++
operator, the C# specification (see 7.5.9 in the 3.0 spec) specifically
calls out properties (and indexers) to use the setter after the
operation to copy the result back to the original location.

This is different from the previous example, because methods are _not_
treated this way.

Methods do not have any particular "modify this" syntax, and so there is
not really a way to treat that kind of access of properties in a clear,
predictable-yet-efficient way.  Because of their nature, a programmer
knows (or should know) that ++ and += always modify the operand, but
there are lots of examples where a method invocation would not and/or
should not modify the instance of the invocation, so that is not
implicitly part of a method invocation off something retrieved from a
property accessor.

Pete
  Harlan Messinger replied to Peter Duniho
15-Dec-09 04:49 PM
Thanks, this is what I just wanted to make sure of. I was picturing a
situation where you would  wind up incrementing a *copy* of the value
underlying the property, to no avail.
  Peter Duniho replied to Harlan Messinger
15-Dec-09 05:14 PM
I believe that this is not possible.  I admit, it is been awhile since I
thought about it, and I may be overlooking something.  But, when the
compiler knows the intended semantics, as is the case with the ++
operator, or when using "ref" or "out" arguments to a method, it will
detect the improper use of a value type with something with those

For example, consider this code:

struct Mutable
{
public int i;
}

class Holder
{
public Mutable Mutable { get; set; }
}

class Test
{
void Method()
{
Holder holder = new Holder();

holder.Mutable.i++;
}
}

The compiler will emit an error at the last statement, because
field "i" in it (basically, the modification is known for sure to be not
visible after the statement, so it is not allowed).

Even so, as you have seen in the previous example (in the other thread),
there are still situations where the compiler cannot know that the change
is not visible, or should otherwise be prohibited (e.g. a method that
has a useful side-effect even if there is a mutation that will not be seen),
and so you can wind up with a bug instead of a compiler error.

That's one of the biggest reasons, if not THE biggest reasons, my
opinion is that mutable value types should be avoided altogether.  it is
very easy, even for experienced programmers, to overlook either the
mutable aspect or the value type aspect and introduce bugs, or at the
very least find it difficult to track down a bug someone else
introduced.  Immutable data types and value types go hand in hand for a
lot of reasons, and they are less likely to lead to these bugs.

Pete
  Harlan Messinger replied to Peter Duniho
15-Dec-09 05:49 PM
My understanding of the term "mutable variable types" includes the likes of

int i;

Surely you do not mean those should be avoided?
  Göran_Andersson replied to Peter Duniho
15-Dec-09 06:10 PM
IIRC, C# version 1 did not have this check, so it would happily get a
copy of the value and modify it. Of course causing some confusion when
people used mutable structs like Point, and they suddenly would not
change when they made a property of it...

--
G?ran Andersson
_____
http://www.guffa.com
  Peter Duniho replied to Harlan Messinger
15-Dec-09 07:55 PM
Variables are, well...variable.  By definition, they are mutable.
However, Int32 is _not_ mutable.  it is immutable.  When you write:

i = 5;
i++;

You are not modifying the instance of Int32 that has the value of 5 and
changing it to 6.  You are replacing the instance of 5 stored in the
variable "i" with the instance of 6, now stored in the variable "i".

Pete
  Harlan Messinger replied to Peter Duniho
15-Dec-09 10:22 PM
Right, but I was not asking about that, I was asking about simple, basic
ints. You wrote, "my opinion is that mutable value types should be
avoided altogether". The type *int* is a mutable value type. Therefore,
it looked like you were saying that *int* should be avoided, which I am
sure is not what you meant, so I thought you might want to double-check
your words.
  Göran_Andersson replied to Harlan Messinger
16-Dec-09 02:49 AM
The types int and System.Int32 are the same.

The int type is by definition not mutable. You can not take a part of an
int value and change it, you have to create a new value and replace the
old value.

int i = 41;
i++; // this creates the value 42 and stores in the variable

--
G?ran Andersson
_____
http://www.guffa.com
  Peter Duniho replied to Harlan Messinger
16-Dec-09 03:21 AM
Double-checked, and they are correct.  See G?ran's reply.  The type
System.Int32 is immutable (as are all of the other primitive value types
similar to "int").

Pete
  Harlan Messinger replied to Peter Duniho
16-Dec-09 07:38 AM
I see. it is come back to me now from back when I originally learned
about C#. I guess I just have not found reason to think about it since
then. But in that case, what makes it a value type? It seems that it
does not hold a value, but a reference to a changeable place in memory
where a value has been placed.
  Patrice replied to Harlan Messinger
16-Dec-09 10:20 AM
it is possible if this is what your property returns. Strictly speaking this
is not the fault of those operators.  It all depends on how the property is
implemented (for example if you implament the count property as returning a
rndom number you ahve no way to knwo what values the code you posted in your
first message will return).

--
Patrice
  Peter Duniho replied to Harlan Messinger
16-Dec-09 03:40 PM
You mean other than the fact that is _is_ a value type?  :)

The short answer is: because it is a "struct" and not a "class".

That's the mechanical explanation for why it is a value type.  I am not
sure what other answer you might be expecting.  I mean, I could use the
behavior of System.Int32 to argue that is why it is a value type.  But in
reality, it is the other way around.  That is, it has that behavior
_because_ it is a value type.  The only thing that "makes it a value
type" is the fact that that is how it was implemented in the language and
framework.


Unfortunately, I think you do not really have a full understanding of the
concepts of a variable, versus a value type or reference type.  it is
hard in this context to provide a good explanation ? the forum is not
really interactive enough for a proper discussion ? but I will try my best.

As I mentioned before, a variable is always mutable (in C#?in other
languages this is not necessarily true).  And yes, the _variable_ can be
thought of as "a changeable place in memory where a value has been placed".

it is unfortunate that the words "value" and "reference" have slightly
different meanings depending on the context.  But, they do.  So
hopefully by pointing that out, I can use those words in their different
ways without making the explanation too confusing.  With that said, here
goes nothin'?  :)

The question of "value type" versus "reference type" has nothing to do
with the variable per se, but rather what that "value" that is in the
variable is.  Note that all variables have a "value", even variables
that hold a "reference type".  This is what I mean by the use of the
words in multiple ways.

Now, a variable holding a value type has as its value the value type
itself.  The storage allocated for the variable _is_ the value type
instance itself.  You can modify the contents of that storage by
assigning a new instance of a value type to the variable.  Or, if the
value type is mutable, you can do something that will ultimately modify
a field in the value type (assign to the field, or call a method or
property that assigns to the field).

But in this case, the storage the variable represents is modified _only_
if you are using that variable representing the value type itself.  Any
other way of getting the value type instance (e.g. returned from a
property) will create a copy of the original value, and the operation
will modify the copy, not the value in the original storage location.

A variable holding a reference type has as its value the _reference_ to
the instance of that type, which is actually stored elsewhere.  The
storage allocated for the variable is only that reference, while the
storage for the reference type instance is elsewhere (i.e. the heap).

For a reference type variable, if you modify the contents of the
variable, you are simply copying a different reference into the
variable.  Nothing happens to the object that variable was previously
referencing.  Conversely, if you modify the object the variable was
referencing, you will see that modification immediately when accessing
the instance via that variable _and_ via any other variable that was
referencing that same instance, while nothing at all happens to the
variable's value itself.

So, when we look at the type System.Int32 (i.e. "int"), because it is
declared as a "struct" and not a "class", it is by declaration and by
definition a value type.  This gives it the specific value type behavior
described above.

Furthermore, there is nothing in the System.Int32 struct that allows you
to modify an instance of System.Int32.  The only thing you can ever do
is assign a new value of System.Int32 to a variable of that type.  This
does mutate the _variable_, but not the original instance of
System.Int32 the variable used to hold.  A whole new instance of
System.Int32 is copied into the variable.

Thus, System.Int32 is a value type (because it is declared as "struct")
and it is immutable (because there is nothing in the type that allows you
to modify an instance of the type?you can only copy a new instance over
an old one).


I will now digress a bit?  :)

I think part of the problem is that because many programmers are so used
to using primitive types without ever thinking about mutability or
immutability, their internal conceptualization of the behavior of the
types is too imprecise.  I know that happened to me when I starting
using C# after years of C++.

The same concepts of mutability can apply in other languages, such as
C++.  But C++ does not provide the same kind of clear division between
value types and reference types.  Instead, any given structure or class
can act as either, depending on usage.
  Göran_Andersson replied to Harlan Messinger
17-Dec-09 03:13 AM
Well, there is a reference to the changeable memory area, but it is the
memory area that is the variable, not the reference. You can change
what is stored in the variable, but you cannot change the reference to it.

Also, the variable does not have the reference all by itself. The
reference is either a reference to the class containing the variable, or
a pointer to a stack frame containing the variable. So, the reference to
the variable itself does not exist all the time, it is calculated by
adding an offset to another reference when you need to access the variable.

--
G?ran Andersson
_____
http://www.guffa.com
Create New Account
help
NET, then maps its builtin types to the .NET types. Examples: VB.NET maps Integer-> System.Int32 and String-> System.String C++ maps int-> System.Int32 and does not map std::string (different semantics) Delphi.NET maps integer-> System.Int32, string-> System.String A# aka MGNAT maps Integer System.Int32 and does not map Unbounded_String (different semantics) C# maps int-> System.Int32 and string-> System
I need to add / update a registry value with a dword that is greater than System.Int32.MaxValue. The value is 0x80000024 and is used for setting the BrowserFlags value for software my sample code: RegistryKey rk = Registry.LocalMachine.OpenSubKey("software \ classes \ \ BrowserFlags", true); rk.SetValue(key, System.Int32.MaxValue, RegistryValueKind.DWord); / / works rk.SetValue(key, 0x80000024, RegistryValueKind.DWord); / / gives an error Any advice is a uint not an int). C# Discussions Registry.LocalMachine.OpenSubKey (1) RegistryValueKind.DWord (1) System.Int32.MaxValue (1) RegistryKey.SetValue (1) RegistryValueKind (1) RegistryKey (1) OpenSubKey (1) SetValue (1) It would I need to add / update a registry value with a dword that is greater than System.Int32.MaxValue. The value is 0x80000024 and is used for setting the Browser
effettuare un casting dinamico noto il type? Ovvero, supponendo che il passaggio di stringhe come System.Int32 o System.DateTime, ottenere in risposta il valore opportunamente convertito? Ho trovato in rete dei mi hanno convinto eccessivamente. Grazie. Ciao. Stefano. C# - Italian Discussions System.DateTime (1) DateTime (1) System.Int32 (1) Database (1) Ovvero (1) Opportunamente (1) Suggerimenti (1) Restituisce (1) Stefano ha scritto: mm effettuare un casting dinamico noto il type Ovvero, supponendo che il passaggio di stringhe come System.Int32 o System.DateTime, otten
was boxed ? foreach (int i in alist) { Console.WriteLine(i.GetType()); / / this is of type System.Int32 Console.WriteLine(i); } } / / Tony C# Discussions InvalidCastException (1) Console.WriteLine (1) ArrayList (1) GetEnumerator (1) System.Int32 (1) Console (1) IEnumerator (1) Main (1) Internally, the WriteLine method calls o.ToString() in in the list that is not an int, you will get an InvalidCastException. - - G?ran Andersson _ __ __ http: / / www.guffa.com keywords: Why, do, I, not, need, any, boxing, here description
Regards, Fred Chateau C# Discussions InvalidCastException (1) DBNull.Value (1) DBNull (1) SubCategoryRow.IsNull (1) System.Int32 (1) Nullable (1) Database (1) Equals (1) That's because (presumably?you failed to show cast at all? So, the type of this ? subCategoryRow["RevisionNumber"] ? is actually int (i.e. System.Int32)? Yes, you said that in the first message. But without a proper concise-but-complete