By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,318 Members | 2,300 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,318 IT Pros & Developers. It's quick & easy.

Modifying List items (generics)

P: n/a
For a declaration like:

List<MyTypeitems = ...

where MyType is a struct, attempt to modify an item with

items[0].member = something;

fails with the message:

Cannot modify the return value of
'System.Collections.Generic.List<MyType>.this[int]' because it is not a
variable (CS1612) - E:\project\MainForm.cs:189,8

While searching the documentation I haven't found a specific mention
that it *should* work, but it seems logical. How to get around the
restriction?
Mar 4 '07 #1
Share this Question
Share on Google+
7 Replies


P: n/a
Ivan Voras wrote:
For a declaration like:

List<MyTypeitems = ...

where MyType is a struct, attempt to modify an item with

items[0].member = something;

fails with the message:

Cannot modify the return value of
'System.Collections.Generic.List<MyType>.this[int]' because it is not a
variable (CS1612) - E:\project\MainForm.cs:189,8

While searching the documentation I haven't found a specific mention
that it *should* work, but it seems logical. How to get around the
restriction?
How wise of the compiler to prevent you from doing that. If it would
have let you, you would have changed the member of the copy of the value
that you requested from the list. This would have no effect at all, as
the original value in the list would be unchanged.

If you want to change the member of a struct, you have to get a copy of
the value, change the member, and replace the original value with the
changed value:

MyType temp = items[0];
temp.member = something;
items[0] = temp;

However, a struct should generally be immutable. If you have items that
you want to modify, you should make it a class instead.

--
Göran Andersson
_____
http://www.guffa.com
Mar 4 '07 #2

P: n/a
Göran Andersson wrote:
MyType temp = items[0];
temp.member = something;
items[0] = temp;

However, a struct should generally be immutable. If you have items that
you want to modify, you should make it a class instead.
Hmm, this reduces the usability of structs. But ok, it's probably
because [] is overloaded and returns a struct (i.e. a value) and
pointers don't exist.

Mar 4 '07 #3

P: n/a
Ivan Voras wrote:
Göran Andersson wrote:
>MyType temp = items[0];
temp.member = something;
items[0] = temp;

However, a struct should generally be immutable. If you have items that
you want to modify, you should make it a class instead.

Hmm, this reduces the usability of structs. But ok, it's probably
because [] is overloaded and returns a struct (i.e. a value) and
pointers don't exist.
Well, the indexer is actually not overloaded, it always returns the
value of the item. For a reference type the value is the reference, and
for value types it's the value itself. :)

--
Göran Andersson
_____
http://www.guffa.com
Mar 5 '07 #4

P: n/a
On Mar 4, 2:44 pm, Gran Andersson <g...@guffa.comwrote:
Ivan Voras wrote:
For a declaration like:
List<MyTypeitems = ...
where MyType is a struct, attempt to modify an item with
items[0].member = something;
fails with the message:
Cannot modify the return value of
'System.Collections.Generic.List<MyType>.this[int]' because it is not a
variable (CS1612) - E:\project\MainForm.cs:189,8
While searching the documentation I haven't found a specific mention
that it *should* work, but it seems logical. How to get around the
restriction?

How wise of the compiler to prevent you from doing that. If it would
have let you, you would have changed the member of the copy of the value
that you requested from the list. This would have no effect at all, as
the original value in the list would be unchanged.

If you want to change the member of a struct, you have to get a copy of
the value, change the member, and replace the original value with the
changed value:

MyType temp = items[0];
temp.member = something;
items[0] = temp;

However, a struct should generally be immutable. If you have items that
you want to modify, you should make it a class instead.
Sorry, probably slightly off topic, but I don't consider that the best
advice. Certainly you should think long and hard before creating a
mutable struct, precisely because of the behaviour the OP just
observed: they act in ways that aren't intuitive to the casual C#
programmer.

I would be more inclined to say the following: "If you have items that
logically should be structs, but you want to be able to modify them,
then realize that allowing structs to be modified in place is just
syntactic sugar for adding another constructor. Consider doing that
instead."

Viz:

structValue.Member = newValue;

is equivalent to:

structValue = new MyStruct(structValue, newValue);

A bit more typing, perhaps, and a few more bytes get moved around, but
nothing earthshaking.

Some examples of mutable structs in the .NET Framework (which cause no
end of consternation if this newsgroup is anything to go by) are Point
and Rectangle. The posts asking why you can't do this:

myForm.Location.X = 5;

seem to have died down lately, but I'm waiting for them to flare up
again.

Anyway, I don't consider it a good idea to decide between using struct
and class based on whether you think the thing should be mutable. IMHO
it has much more to do with semantics, in particular what I refer to
as "whether the thing has an identity."

Mar 5 '07 #5

P: n/a
Bruce Wood wrote:
On Mar 4, 2:44 pm, Gran Andersson <g...@guffa.comwrote:
>Ivan Voras wrote:
>>For a declaration like:
List<MyTypeitems = ...
where MyType is a struct, attempt to modify an item with
items[0].member = something;
fails with the message:
Cannot modify the return value of
'System.Collections.Generic.List<MyType>.this[int]' because it is not a
variable (CS1612) - E:\project\MainForm.cs:189,8
While searching the documentation I haven't found a specific mention
that it *should* work, but it seems logical. How to get around the
restriction?
How wise of the compiler to prevent you from doing that. If it would
have let you, you would have changed the member of the copy of the value
that you requested from the list. This would have no effect at all, as
the original value in the list would be unchanged.

If you want to change the member of a struct, you have to get a copy of
the value, change the member, and replace the original value with the
changed value:

MyType temp = items[0];
temp.member = something;
items[0] = temp;

However, a struct should generally be immutable. If you have items that
you want to modify, you should make it a class instead.

Sorry, probably slightly off topic, but I don't consider that the best
advice.
That depends on how deep you want to go into the matter. I think that
it's good advice for anyone who doesn't really know the difference
between a struct and a class.

Perhaps I should have added a "in most cases" in the advice about making
it a class. That would suggest that there is more to learn about the
matter to be able to make a definitive decision in every case.
Certainly you should think long and hard before creating a
mutable struct, precisely because of the behaviour the OP just
observed: they act in ways that aren't intuitive to the casual C#
programmer.

I would be more inclined to say the following: "If you have items that
logically should be structs, but you want to be able to modify them,
then realize that allowing structs to be modified in place is just
syntactic sugar for adding another constructor. Consider doing that
instead."
I don't think that this really contradicts my advice. Most items that
you want to modify shouldn't logically be structures anyway.

However, the part about modifying structures being syntactic sugar for a
constructor only applies if you modify the entire value of the
structure, and in that case it should always be done using a constructor.
Viz:

structValue.Member = newValue;

is equivalent to:

structValue = new MyStruct(structValue, newValue);

A bit more typing, perhaps, and a few more bytes get moved around, but
nothing earthshaking.
Especially if the suggested size limit for structures of 16 bytes is
followed. :)
Some examples of mutable structs in the .NET Framework (which cause no
end of consternation if this newsgroup is anything to go by) are Point
and Rectangle. The posts asking why you can't do this:

myForm.Location.X = 5;

seem to have died down lately, but I'm waiting for them to flare up
again.
They surely will. Making a structure mutable will always cause problems
for people unaware of the problems that it introduces.
Anyway, I don't consider it a good idea to decide between using struct
and class based on whether you think the thing should be mutable. IMHO
it has much more to do with semantics, in particular what I refer to
as "whether the thing has an identity."
Good advice. I guess that the basis for the decision depends on how you
are accustomed to think about data.

--
Gran Andersson
_____
http://www.guffa.com
Mar 5 '07 #6

P: n/a
Bruce Wood wrote:
Sorry, probably slightly off topic, but I don't consider that the best
advice. Certainly you should think long and hard before creating a
mutable struct, precisely because of the behaviour the OP just
observed: they act in ways that aren't intuitive to the casual C#
programmer.
....or to programmers coming from other languages...
I would be more inclined to say the following: "If you have items that
logically should be structs, but you want to be able to modify them,
then realize that allowing structs to be modified in place is just
syntactic sugar for adding another constructor. Consider doing that
instead."
While I accept there are situation that benefit from unmutable structs,
they are few and far between. So, for now, since I'm thinking in terms
of mutable structures, I'll just make them classes.
Some examples of mutable structs in the .NET Framework (which cause no
end of consternation if this newsgroup is anything to go by) are Point
and Rectangle. The posts asking why you can't do this:

myForm.Location.X = 5;

seem to have died down lately, but I'm waiting for them to flare up
again.
.... because you must admit that doing it that way looks very
straightforward :)
Anyway, I don't consider it a good idea to decide between using struct
and class based on whether you think the thing should be mutable. IMHO
it has much more to do with semantics, in particular what I refer to
as "whether the thing has an identity."
Maybe on a higher level of thinking about it, yes, but C# is still a
more down-to-earth language. I was very surprised with the decision to
make "structs" have methods, constructors, etc, instead of making them
just be light-weight containers for data like they're mostly used (in
other languages).
Mar 5 '07 #7

P: n/a
On Mar 5, 10:05 am, Ivan Voras <ivoras@__fer.hr__wrote:
Bruce Wood wrote:
Sorry, probably slightly off topic, but I don't consider that the best
advice. Certainly you should think long and hard before creating a
mutable struct, precisely because of the behaviour the OP just
observed: they act in ways that aren't intuitive to the casual C#
programmer.

...or to programmers coming from other languages...
I would be more inclined to say the following: "If you have items that
logically should be structs, but you want to be able to modify them,
then realize that allowing structs to be modified in place is just
syntactic sugar for adding another constructor. Consider doing that
instead."

While I accept there are situation that benefit from unmutable structs,
they are few and far between. So, for now, since I'm thinking in terms
of mutable structures, I'll just make them classes.
A friendly warning: struct to class (or vice versa) is a big jump in
C#. It fundamentally changes the semantics of the thing you're
defining. "I'll just make them classes" may be a fair statement in
other languages, but in the .NET world it sounds scary.

I don't want to rehash a lot of discussion that's already gone on
here, but consider the Point structure in the Framework. What would be
the difference between a Point class and a Point struct? I claim that
the main (conceptual) difference is that the former has _identity_, or
can have identity, while the latter does not. That is, if you have a
Point class then you can talk about "this point" versus "that point"
even if they have the same coordinates. You could give a Point a UID
and it would make some sense. In the latter case, you're saying that
Point is a value, that there is no concept of "this point 5, 5" versus
"that point 5, 5" any more than there is a concept of "this integer
15" versus "that integer 15". 15 is just a value, and as such has no
identity other than its value.
Some examples of mutable structs in the .NET Framework (which cause no
end of consternation if this newsgroup is anything to go by) are Point
and Rectangle. The posts asking why you can't do this:
myForm.Location.X = 5;
seem to have died down lately, but I'm waiting for them to flare up
again.

... because you must admit that doing it that way looks very
straightforward :)
Oh, absolutely it does. The problem is that what appears
straightforward isn't, which is why I tend to avoid mutable structs.
Anyway, I don't consider it a good idea to decide between using struct
and class based on whether you think the thing should be mutable. IMHO
it has much more to do with semantics, in particular what I refer to
as "whether the thing has an identity."

Maybe on a higher level of thinking about it, yes, but C# is still a
more down-to-earth language. I was very surprised with the decision to
make "structs" have methods, constructors, etc, instead of making them
just be light-weight containers for data like they're mostly used (in
other languages).
Do you know C++? If you do, think about it this way: in C++ you have
to make a value-versus-reference decision every time you declare a
variable, and every time you pass something to a method. Do you
declare it as Foo f, or Foo *f? Do you want to store the value, or a
reference to that value?

In C#, you make that decision once for a type, when you define it. If
it's a class, then every variable declaration is, effectively, Foo *f.
If it's a struct, then every variable declaration is Foo f.

Mar 5 '07 #8

This discussion thread is closed

Replies have been disabled for this discussion.