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

Struct vs Class

P: n/a
Hi,

Newbie question...

After a recent article in VSJ I had a go at implementing a Fraction
class to aid my understanding of operator overloading. After a previous
message someone suggested that I implement it as a struct rather than a
class which I did and all worked OK.

The simplest declaration for the struct is:

public struct Fraction
{
private Int32 _numerator;
private Int32 _denominator;

public Int32 numerator
{
get { return _numerator; }
}

public Int32 denominator
{
get { return _denominator; }
}

public Fraction(Int32 numerator)
{
this._numerator = numerator;
this._denominator = 1;
}

public Fraction(Int32 numerator, Int32 denominator)
{
this._numerator = numerator;
this._denominator = denominator;
if (denominator < 1)
throw new ArgumentException("Fraction denominator value
'" + denominator.ToString() + "' is invalid.");
}

// All other declarations follow (for overloads of
+,-,*,/,++,--,>,<, etc).
}
As you can see, it is essential that the denominator must be 1 or more.
As it was originally a class, the constructors ensured that the
denominator was >= 1. Alos, the numerator and denominator values are
read only as they can only be modified by operators such as +,-,++,*,/
etc (not shown).

However, during my testing I realised that, as a struct, it is possible
to declare a struct which is initialised to 0 so the denominator
becomes illegal.

I've found that you cannot declare a parameterless construction such
as:

public struct Fraction
{
private Int32 _numerator;
private Int32 _denominator;
....
public Fraction()
{
this._numerator = 0;
this._denominator = 1;
}
....
}

This gives a compiler error: 'Structs cannot contain explicit
parameterless constructors'.
Also, you cannot initialise the fields of a struct such as:

public struct Fraction
{
private Int32 _numerator;
private Int32 _denominator = 1;
....
}

This gives a compilation error: '_denominator': cannot have instance
field initializers in structs'.
Is there any way to force a field of a struct to be initialised to a
non zero value?

If not, I'll go back to implementing it as a class.

TIA,

John.

Oct 28 '06 #1
Share this Question
Share on Google+
37 Replies


P: n/a
Hi,

You can't prevent the initialization of an instance of a struct with default
values. You'll always be able to code: Fraction fr = new Fraction(),
regardless of the constructors that you define.

If you decide to stick with a struct, don't forget to override Equals and
GetHashCode as well. And make sure that their return values are deterministic
and consistent with each other.

--
Dave Sexton

<Jo********@hotmail.co.ukwrote in message
news:11**********************@k70g2000cwa.googlegr oups.com...
Hi,

Newbie question...

After a recent article in VSJ I had a go at implementing a Fraction
class to aid my understanding of operator overloading. After a previous
message someone suggested that I implement it as a struct rather than a
class which I did and all worked OK.

The simplest declaration for the struct is:

public struct Fraction
{
private Int32 _numerator;
private Int32 _denominator;

public Int32 numerator
{
get { return _numerator; }
}

public Int32 denominator
{
get { return _denominator; }
}

public Fraction(Int32 numerator)
{
this._numerator = numerator;
this._denominator = 1;
}

public Fraction(Int32 numerator, Int32 denominator)
{
this._numerator = numerator;
this._denominator = denominator;
if (denominator < 1)
throw new ArgumentException("Fraction denominator value
'" + denominator.ToString() + "' is invalid.");
}

// All other declarations follow (for overloads of
+,-,*,/,++,--,>,<, etc).
}
As you can see, it is essential that the denominator must be 1 or more.
As it was originally a class, the constructors ensured that the
denominator was >= 1. Alos, the numerator and denominator values are
read only as they can only be modified by operators such as +,-,++,*,/
etc (not shown).

However, during my testing I realised that, as a struct, it is possible
to declare a struct which is initialised to 0 so the denominator
becomes illegal.

I've found that you cannot declare a parameterless construction such
as:

public struct Fraction
{
private Int32 _numerator;
private Int32 _denominator;
....
public Fraction()
{
this._numerator = 0;
this._denominator = 1;
}
....
}

This gives a compiler error: 'Structs cannot contain explicit
parameterless constructors'.
Also, you cannot initialise the fields of a struct such as:

public struct Fraction
{
private Int32 _numerator;
private Int32 _denominator = 1;
....
}

This gives a compilation error: '_denominator': cannot have instance
field initializers in structs'.
Is there any way to force a field of a struct to be initialised to a
non zero value?

If not, I'll go back to implementing it as a class.

TIA,

John.

Oct 28 '06 #2

P: n/a
Thanks Dave,

I do override Equals and GetHashcode already. I guess I'll change it
back to a class. Thank you for you feedback. From what I had read, I
thought this was the case.

As a newbie, I'm interested in how much boxing / unboxing will be going
on when I define a struct as opposed to a class. I've just got Jeffrey
Richter's CLR via C# which seems to show me how to determine this via
the IL Disassembler. Some investigations to be done!

Thanks.

John.

Oct 28 '06 #3

P: n/a
<Jo********@hotmail.co.ukwrote:

<snip>
Is there any way to force a field of a struct to be initialised to a
non zero value?
No - and you'll always end up with the zero value if you create, say,
an array of the struct type.
If not, I'll go back to implementing it as a class.
I wouldn't make that the most important influence in your decision.
It's easy to ensure that the struct is initialised appropriately
wherever it's actually used. Think of a zero value for a struct as a
sort of equivalent (in this particular case) to a null value for a
reference type. Just as you could do:

FractionStruct x = new FractionStruct(); // x is useless at the moment

you could do:

FractionClass y = null; // y is just as useless at the moment
A fraction still feels more like a value type than a reference type to
me.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Oct 28 '06 #4

P: n/a

Jo********@hotmail.co.uk wrote:
Thanks Dave,

I do override Equals and GetHashcode already. I guess I'll change it
back to a class. Thank you for you feedback. From what I had read, I
thought this was the case.

As a newbie, I'm interested in how much boxing / unboxing will be going
on when I define a struct as opposed to a class. I've just got Jeffrey
Richter's CLR via C# which seems to show me how to determine this via
the IL Disassembler. Some investigations to be done!
I, too, created a Fraction class for use in our company. Trust me:
don't make it a class. Simply assign meaning to "everything zero". It's
"essential" that the denominator be greater than zero only if you say
it's essential; you're writing the code, so you can make any
assumptions you want.

Simply write the internals so that denominator and numerator both zero
means "zero". Yes, it means more checks inside your code, but as I
said, trust me: making this a class will make it much less useful and
make it act much less intuitively. It should be a struct.

Oct 28 '06 #5

P: n/a
You could make the _denominator field nullable and check for null in
the property:

public struct Fraction {
private Int32? _denominator;

[...]
public Int32 Denominator {
get{ if ( _denominator == null ) return 1; else return
(Int32)_denominator; }
}

[...]
}

Regards
,
Ryan

On Oct 28, 4:43 pm, JohnGoo...@hotmail.co.uk wrote:
Hi,

Newbie question...

After a recent article in VSJ I had a go at implementing a Fraction
class to aid my understanding of operator overloading. After a previous
message someone suggested that I implement it as a struct rather than a
class which I did and all worked OK.

The simplest declaration for the struct is:

public struct Fraction
{
private Int32 _numerator;
private Int32 _denominator;

public Int32 numerator
{
get { return _numerator; }
}

public Int32 denominator
{
get { return _denominator; }
}

public Fraction(Int32 numerator)
{
this._numerator = numerator;
this._denominator = 1;
}

public Fraction(Int32 numerator, Int32 denominator)
{
this._numerator = numerator;
this._denominator = denominator;
if (denominator < 1)
throw new ArgumentException("Fraction denominator value
'" + denominator.ToString() + "' is invalid.");
}

// All other declarations follow (for overloads of
+,-,*,/,++,--,>,<, etc).
}

As you can see, it is essential that the denominator must be 1 or more.
As it was originally a class, the constructors ensured that the
denominator was >= 1. Alos, the numerator and denominator values are
read only as they can only be modified by operators such as +,-,++,*,/
etc (not shown).

However, during my testing I realised that, as a struct, it is possible
to declare a struct which is initialised to 0 so the denominator
becomes illegal.

I've found that you cannot declare a parameterless construction such
as:

public struct Fraction
{
private Int32 _numerator;
private Int32 _denominator;
....
public Fraction()
{
this._numerator = 0;
this._denominator = 1;
}
....
}

This gives a compiler error: 'Structs cannot contain explicit
parameterless constructors'.

Also, you cannot initialise the fields of a struct such as:

public struct Fraction
{
private Int32 _numerator;
private Int32 _denominator = 1;
....
}

This gives a compilation error: '_denominator': cannot have instance
field initializers in structs'.

Is there any way to force a field of a struct to be initialised to a
non zero value?

If not, I'll go back to implementing it as a class.

TIA,

John.
Oct 30 '06 #6

P: n/a
In general you want a way to flag the object as "uninitialized" - while
there are numerous clever ways to do it, ultimately the simplest
approach is to include a boolean. It's tempting to use a nullable
type, but afaik nullables are reference types, thus eliminating the
niceties using a struct. Structs work so much better when only
containing values.

As such, include a private boolean "isDenominatorIinitialized" - and
use

public Int32 Denominator {
get{ if (isDenominatorIinitialized == false ) return 1; else
return (Int32)_denominator; }
private set {isDenominatorInitialized = true; _denominator =
value; }
}

And then use the private set whenever you (internally) assign to the
denominator. This assumes 2.0 where you can have differing access to
get/set attributes. This should perform better than the nullable
approach.

Ryan wrote:
You could make the _denominator field nullable and check for null in
the property:

public struct Fraction {
private Int32? _denominator;

[...]
public Int32 Denominator {
get{ if ( _denominator == null ) return 1; else return
(Int32)_denominator; }
}

[...]
}

Regards
,
Ryan

On Oct 28, 4:43 pm, JohnGoo...@hotmail.co.uk wrote:
Hi,

Newbie question...

After a recent article in VSJ I had a go at implementing a Fraction
class to aid my understanding of operator overloading. After a previous
message someone suggested that I implement it as a struct rather than a
class which I did and all worked OK.

The simplest declaration for the struct is:

public struct Fraction
{
private Int32 _numerator;
private Int32 _denominator;

public Int32 numerator
{
get { return _numerator; }
}

public Int32 denominator
{
get { return _denominator; }
}

public Fraction(Int32 numerator)
{
this._numerator = numerator;
this._denominator = 1;
}

public Fraction(Int32 numerator, Int32 denominator)
{
this._numerator = numerator;
this._denominator = denominator;
if (denominator < 1)
throw new ArgumentException("Fraction denominator value
'" + denominator.ToString() + "' is invalid.");
}

// All other declarations follow (for overloads of
+,-,*,/,++,--,>,<, etc).
}

As you can see, it is essential that the denominator must be 1 or more.
As it was originally a class, the constructors ensured that the
denominator was >= 1. Alos, the numerator and denominator values are
read only as they can only be modified by operators such as +,-,++,*,/
etc (not shown).

However, during my testing I realised that, as a struct, it is possible
to declare a struct which is initialised to 0 so the denominator
becomes illegal.

I've found that you cannot declare a parameterless construction such
as:

public struct Fraction
{
private Int32 _numerator;
private Int32 _denominator;
....
public Fraction()
{
this._numerator = 0;
this._denominator = 1;
}
....
}

This gives a compiler error: 'Structs cannot contain explicit
parameterless constructors'.

Also, you cannot initialise the fields of a struct such as:

public struct Fraction
{
private Int32 _numerator;
private Int32 _denominator = 1;
....
}

This gives a compilation error: '_denominator': cannot have instance
field initializers in structs'.

Is there any way to force a field of a struct to be initialised to a
non zero value?

If not, I'll go back to implementing it as a class.

TIA,

John.
Oct 30 '06 #7

P: n/a
Bruce, My understanding is that, if designed to be entirely immutable
and containing no events, then there is almost no visible difference
between a class and a struct. The struct is primarily a
speed-optimization - access to stack-variables is much faster. Hence,
structs should only contain other valuetypes.

Bruce Wood wrote:
Jo********@hotmail.co.uk wrote:
Thanks Dave,

I do override Equals and GetHashcode already. I guess I'll change it
back to a class. Thank you for you feedback. From what I had read, I
thought this was the case.

As a newbie, I'm interested in how much boxing / unboxing will be going
on when I define a struct as opposed to a class. I've just got Jeffrey
Richter's CLR via C# which seems to show me how to determine this via
the IL Disassembler. Some investigations to be done!

I, too, created a Fraction class for use in our company. Trust me:
don't make it a class. Simply assign meaning to "everything zero". It's
"essential" that the denominator be greater than zero only if you say
it's essential; you're writing the code, so you can make any
assumptions you want.

Simply write the internals so that denominator and numerator both zero
means "zero". Yes, it means more checks inside your code, but as I
said, trust me: making this a class will make it much less useful and
make it act much less intuitively. It should be a struct.
Oct 30 '06 #8

P: n/a
Hi Martin,
The struct is primarily a
speed-optimization - access to stack-variables is much faster. Hence,
structs should only contain other valuetypes.
But values can be stored on the heap as well.

Check out this article by Jon Skeet:
http://www.yoda.arachsys.com/csharp/memory.html

Structs that have private fields that reference objects simply store the
reference with the rest of the structure. Memory-wise, it's just like storing
Int32, AFAIK.

A value type is meant to be just that - a value. Values are not meant to be
tangible objects - like paper - they are meant to represent a value that you
can assign to an object - like worth (money). Therefore, it makes sense to me
that values are stored in-line with the objects that contain them, or on the
stack if that's where they are placed. They stay with their container because
they only have value, not presence.

I ask myself the following question when choosing between a struct or class
definition:

When an instance is used as a hash key, should the corresponding value in a
hash table be accessible by value or by reference only?

In other words, will I need the reference of the entity in order to retrieve
the keyed value at a later time, or just the value?

It's usually obvious whether to use a struct or a class from there, even if I
don't plan on using any instances to key a hash table. I never take into
consideration whether the struct will contain references, however I don't
think I've ever created a struct that had references anyway - so I might agree
with you after all, but for a different reason :)

--
Dave Sexton

"Martin Z" <ma***********@gmail.comwrote in message
news:11********************@k70g2000cwa.googlegrou ps.com...
Bruce, My understanding is that, if designed to be entirely immutable
and containing no events, then there is almost no visible difference
between a class and a struct. The struct is primarily a
speed-optimization - access to stack-variables is much faster. Hence,
structs should only contain other valuetypes.

Bruce Wood wrote:
>Jo********@hotmail.co.uk wrote:
Thanks Dave,

I do override Equals and GetHashcode already. I guess I'll change it
back to a class. Thank you for you feedback. From what I had read, I
thought this was the case.

As a newbie, I'm interested in how much boxing / unboxing will be going
on when I define a struct as opposed to a class. I've just got Jeffrey
Richter's CLR via C# which seems to show me how to determine this via
the IL Disassembler. Some investigations to be done!

I, too, created a Fraction class for use in our company. Trust me:
don't make it a class. Simply assign meaning to "everything zero". It's
"essential" that the denominator be greater than zero only if you say
it's essential; you're writing the code, so you can make any
assumptions you want.

Simply write the internals so that denominator and numerator both zero
means "zero". Yes, it means more checks inside your code, but as I
said, trust me: making this a class will make it much less useful and
make it act much less intuitively. It should be a struct.

Oct 30 '06 #9

P: n/a

Martin Z wrote:
Bruce, My understanding is that, if designed to be entirely immutable
and containing no events, then there is almost no visible difference
between a class and a struct.
Apparently so. I'm trying to think of differences in behaviour between
an immutable class and a struct, and I can't. Of course, it's Monday
morning. I could be wrong.

One would have to overload == appropriately (and, one presumes, the
other mathematical and comparison operators), but apart from that I
can't think of any hitches. Of course, the temptation with a class
would be to make it mutable, but that's just a temptation, not a given.
The struct is primarily a speed-optimization - access to stack-variables is much faster.
I wouldn't state that as the primary speed benefits of structs. I
consider the primary speed benefit of structs being that they don't
need to be garbage-collected. So, if you are doing extensive
calculations that involve the creation of myriad intermediate results
then structs are a better choice because objects created on the heap
have to be GC'd.

However, this is only one consideration in whether to make something a
struct or a class, and not even the most important. The most important
consideration, IMHO, is whether the thing you want to create displays
_value semantics_. There are lots of discussions in this newsgroup
about struct vs class and value vs reference semantics.
Hence, structs should only contain other valuetypes.
No, I disagree. For example, I have a struct called a Measure, which
contains a decimal quantity and a unit of measure. UnitOfMeasure is a(n
immutable) reference type. I think that our disagreement on this point
goes back to the speed benefits of structs: I see storage on the stack
as a side-effect of using structs, not as a motivation for using
structs, and so I don't see anything wrong with structs that contain
references. Of course, structs that contain references to _mutable_
objects can lead to some awfully puzzling, nearly-unpredictable
behaviour, so I wouldn't recommend that. :-)

Oct 30 '06 #10

P: n/a

Martin Z wrote:
afaik nullables are reference types
Nope. From the MSDN doc:

http://msdn2.microsoft.com/en-us/library/1t3y8s4s.aspx

"Nullable types are instances of the System.Nullable struct."

Nullable types are value types, not reference types. They contain a
boolean flag indicating whether they are null or not, and space for the
value if they are not null.

Oct 30 '06 #11

P: n/a
Hi Bruce,
Of course, structs that contain references to _mutable_
objects can lead to some awfully puzzling, nearly-unpredictable
behaviour, so I wouldn't recommend that. :-)
DictionaryEntry is one that doesn't conform to that idea, however.

--
Dave Sexton

"Bruce Wood" <br*******@canada.comwrote in message
news:11*********************@b28g2000cwb.googlegro ups.com...
>
Martin Z wrote:
>Bruce, My understanding is that, if designed to be entirely immutable
and containing no events, then there is almost no visible difference
between a class and a struct.

Apparently so. I'm trying to think of differences in behaviour between
an immutable class and a struct, and I can't. Of course, it's Monday
morning. I could be wrong.

One would have to overload == appropriately (and, one presumes, the
other mathematical and comparison operators), but apart from that I
can't think of any hitches. Of course, the temptation with a class
would be to make it mutable, but that's just a temptation, not a given.
>The struct is primarily a speed-optimization - access to stack-variables is
much faster.

I wouldn't state that as the primary speed benefits of structs. I
consider the primary speed benefit of structs being that they don't
need to be garbage-collected. So, if you are doing extensive
calculations that involve the creation of myriad intermediate results
then structs are a better choice because objects created on the heap
have to be GC'd.

However, this is only one consideration in whether to make something a
struct or a class, and not even the most important. The most important
consideration, IMHO, is whether the thing you want to create displays
_value semantics_. There are lots of discussions in this newsgroup
about struct vs class and value vs reference semantics.
>Hence, structs should only contain other valuetypes.

No, I disagree. For example, I have a struct called a Measure, which
contains a decimal quantity and a unit of measure. UnitOfMeasure is a(n
immutable) reference type. I think that our disagreement on this point
goes back to the speed benefits of structs: I see storage on the stack
as a side-effect of using structs, not as a motivation for using
structs, and so I don't see anything wrong with structs that contain
references. Of course, structs that contain references to _mutable_
objects can lead to some awfully puzzling, nearly-unpredictable
behaviour, so I wouldn't recommend that. :-)

Oct 30 '06 #12

P: n/a
Holy poop, DictionaryEntry is mutable? (off to MSDN).... Whoa. Oh,
and my comment about avoiding including value-types in structs was from
the optimization direction - obviously if you're using structs because
you want value-type semantics then it doesn't matter what you stuff in
them (as long as they're immutable to avoid confusing aliasing
behaviour).

Funny that nullables are value-type - I recently got an error from the
XmlSerializer where it complained that they were reference types, and
thus couldn't be XmlAttributes. That was just silly.

Anyhow, I think the reason DictionaryEntry is mutable is just because
people got really sick of saying new DictionaryEntry<MyKeyType,
MyValueType- not for any good technical reason. I think it's
hilarious that the structs have the nice immediate-setting semantics
for mutable structs
myStructClass foo;
foo.bar = 1;
foo.baz = 2;
//all parameters initialized, it's ready to use, no constructor
needed.

but you can only use them with mutable structs anyways, making it
completely useless since MS says to never-ever-do-mutable-structs. I
want the readonly attribute to apply to property setters, and then
integrate that with the 3.0 Object Initializers so we can have some
non-excruciating syntax for immutables.

Dave Sexton wrote:
Hi Bruce,
Of course, structs that contain references to _mutable_
objects can lead to some awfully puzzling, nearly-unpredictable
behaviour, so I wouldn't recommend that. :-)

DictionaryEntry is one that doesn't conform to that idea, however.

--
Dave Sexton

"Bruce Wood" <br*******@canada.comwrote in message
news:11*********************@b28g2000cwb.googlegro ups.com...

Martin Z wrote:
Bruce, My understanding is that, if designed to be entirely immutable
and containing no events, then there is almost no visible difference
between a class and a struct.
Apparently so. I'm trying to think of differences in behaviour between
an immutable class and a struct, and I can't. Of course, it's Monday
morning. I could be wrong.

One would have to overload == appropriately (and, one presumes, the
other mathematical and comparison operators), but apart from that I
can't think of any hitches. Of course, the temptation with a class
would be to make it mutable, but that's just a temptation, not a given.
The struct is primarily a speed-optimization - access to stack-variables is
much faster.
I wouldn't state that as the primary speed benefits of structs. I
consider the primary speed benefit of structs being that they don't
need to be garbage-collected. So, if you are doing extensive
calculations that involve the creation of myriad intermediate results
then structs are a better choice because objects created on the heap
have to be GC'd.

However, this is only one consideration in whether to make something a
struct or a class, and not even the most important. The most important
consideration, IMHO, is whether the thing you want to create displays
_value semantics_. There are lots of discussions in this newsgroup
about struct vs class and value vs reference semantics.
Hence, structs should only contain other valuetypes.
No, I disagree. For example, I have a struct called a Measure, which
contains a decimal quantity and a unit of measure. UnitOfMeasure is a(n
immutable) reference type. I think that our disagreement on this point
goes back to the speed benefits of structs: I see storage on the stack
as a side-effect of using structs, not as a motivation for using
structs, and so I don't see anything wrong with structs that contain
references. Of course, structs that contain references to _mutable_
objects can lead to some awfully puzzling, nearly-unpredictable
behaviour, so I wouldn't recommend that. :-)
Oct 30 '06 #13

P: n/a
Hi Martin,
obviously if you're using structs because
you want value-type semantics then it doesn't matter what you stuff in
them (as long as they're immutable to avoid confusing aliasing
behaviour).
What do you mean by "aliasing behaviour"?
Funny that nullables are value-type - I recently got an error from the
XmlSerializer where it complained that they were reference types, and
thus couldn't be XmlAttributes. That was just silly.
I think Nullable<Tshould be a value type just like DictionaryEntry. They
each assign a value to the objects that they contain - nullability or hash
entry, respectively.

Although nullability is only useful for value types, which is why I suspect
that you can't make a Nullable<string>, for example.

But hash entries can be anything, including mutable objects. DictionaryEntry
is just a value: the relationship between a key and its corresponding value.
If the key or the value are object references then the value of the hash entry
itself is simply the relationship between the two references. If another
DictionaryEntry contains the same key and value references, then the values of
the DictionaryEntries are equal.

Nullable<Tand DictionaryEntry do not represent tangible objects, they
represent assignable values. It helps some people to think of values as
conceptual and objects as physical, like me!
Anyhow, I think the reason DictionaryEntry is mutable is just because
people got really sick of saying new DictionaryEntry<MyKeyType,
MyValueType- not for any good technical reason.
I've never actually created an instance of DictionaryEntry though. I've only
used it in iterators so I'm not sure the mutability was necessary. I assume
the author(s) made it mutable due to some internal implementation constraints
that I don't feel like searching for right now :)

But just to clear things up, my response to Bruce wasn't about the mutability
of DictionaryEntry, it was about the mutability of the objects that it
references. That's what I assumed Bruce meant when he wrote, "structs that
contain references to _mutable_ objects", although reading it out-of-context
now I can see why you thought that.
I think it's
hilarious that the structs have the nice immediate-setting semantics
for mutable structs
myStructClass foo;
foo.bar = 1;
foo.baz = 2;
//all parameters initialized, it's ready to use, no constructor
needed.
but you can only use them with mutable structs anyways, making it
completely useless since MS says to never-ever-do-mutable-structs. I
want the readonly attribute to apply to property setters, and then
integrate that with the 3.0 Object Initializers so we can have some
non-excruciating syntax for immutables.
I won't argue that :)

--
Dave Sexton

"Martin Z" <ma***********@gmail.comwrote in message
news:11**********************@b28g2000cwb.googlegr oups.com...
Holy poop, DictionaryEntry is mutable? (off to MSDN).... Whoa. Oh,
and my comment about avoiding including value-types in structs was from
the optimization direction - obviously if you're using structs because
you want value-type semantics then it doesn't matter what you stuff in
them (as long as they're immutable to avoid confusing aliasing
behaviour).

Funny that nullables are value-type - I recently got an error from the
XmlSerializer where it complained that they were reference types, and
thus couldn't be XmlAttributes. That was just silly.

Anyhow, I think the reason DictionaryEntry is mutable is just because
people got really sick of saying new DictionaryEntry<MyKeyType,
MyValueType- not for any good technical reason. I think it's
hilarious that the structs have the nice immediate-setting semantics
for mutable structs
myStructClass foo;
foo.bar = 1;
foo.baz = 2;
//all parameters initialized, it's ready to use, no constructor
needed.

but you can only use them with mutable structs anyways, making it
completely useless since MS says to never-ever-do-mutable-structs. I
want the readonly attribute to apply to property setters, and then
integrate that with the 3.0 Object Initializers so we can have some
non-excruciating syntax for immutables.

Dave Sexton wrote:
>Hi Bruce,
Of course, structs that contain references to _mutable_
objects can lead to some awfully puzzling, nearly-unpredictable
behaviour, so I wouldn't recommend that. :-)

DictionaryEntry is one that doesn't conform to that idea, however.

--
Dave Sexton

"Bruce Wood" <br*******@canada.comwrote in message
news:11*********************@b28g2000cwb.googlegr oups.com...
>
Martin Z wrote:
Bruce, My understanding is that, if designed to be entirely immutable
and containing no events, then there is almost no visible difference
between a class and a struct.

Apparently so. I'm trying to think of differences in behaviour between
an immutable class and a struct, and I can't. Of course, it's Monday
morning. I could be wrong.

One would have to overload == appropriately (and, one presumes, the
other mathematical and comparison operators), but apart from that I
can't think of any hitches. Of course, the temptation with a class
would be to make it mutable, but that's just a temptation, not a given.

The struct is primarily a speed-optimization - access to stack-variables
is
much faster.

I wouldn't state that as the primary speed benefits of structs. I
consider the primary speed benefit of structs being that they don't
need to be garbage-collected. So, if you are doing extensive
calculations that involve the creation of myriad intermediate results
then structs are a better choice because objects created on the heap
have to be GC'd.

However, this is only one consideration in whether to make something a
struct or a class, and not even the most important. The most important
consideration, IMHO, is whether the thing you want to create displays
_value semantics_. There are lots of discussions in this newsgroup
about struct vs class and value vs reference semantics.

Hence, structs should only contain other valuetypes.

No, I disagree. For example, I have a struct called a Measure, which
contains a decimal quantity and a unit of measure. UnitOfMeasure is a(n
immutable) reference type. I think that our disagreement on this point
goes back to the speed benefits of structs: I see storage on the stack
as a side-effect of using structs, not as a motivation for using
structs, and so I don't see anything wrong with structs that contain
references. Of course, structs that contain references to _mutable_
objects can lead to some awfully puzzling, nearly-unpredictable
behaviour, so I wouldn't recommend that. :-)

Oct 30 '06 #14

P: n/a
structs containing references to mutable objects is what I meant by
"aliasing" - that is, if I have a struct I may assume that everything I
do with it will be copy-semantics... however, if it contains a
reference to a mutable class (say a stringbuilder) then if I make
changes to that stringbuilder, then all copies (not just the object I'm
accessing to make the changes) will see that, which is unexpected
behaviour for a struct. That is, an alias where we expect a copy.

And yes, I agree that Nullables _should_ be valuetype, and likely are
in implementation - I just thought that they were reference-types
because errors thrown by the XmlSerializer informed me that they were
reference types... which is likely just the serializer getting very
confused by the concept of a nullable value-type.

Dave Sexton wrote:
Hi Martin,
obviously if you're using structs because
you want value-type semantics then it doesn't matter what you stuff in
them (as long as they're immutable to avoid confusing aliasing
behaviour).

What do you mean by "aliasing behaviour"?
Funny that nullables are value-type - I recently got an error from the
XmlSerializer where it complained that they were reference types, and
thus couldn't be XmlAttributes. That was just silly.

I think Nullable<Tshould be a value type just like DictionaryEntry. They
each assign a value to the objects that they contain - nullability or hash
entry, respectively.

Although nullability is only useful for value types, which is why I suspect
that you can't make a Nullable<string>, for example.

But hash entries can be anything, including mutable objects. DictionaryEntry
is just a value: the relationship between a key and its corresponding value.
If the key or the value are object references then the value of the hash entry
itself is simply the relationship between the two references. If another
DictionaryEntry contains the same key and value references, then the values of
the DictionaryEntries are equal.

Nullable<Tand DictionaryEntry do not represent tangible objects, they
represent assignable values. It helps some people to think of values as
conceptual and objects as physical, like me!
Anyhow, I think the reason DictionaryEntry is mutable is just because
people got really sick of saying new DictionaryEntry<MyKeyType,
MyValueType- not for any good technical reason.

I've never actually created an instance of DictionaryEntry though. I've only
used it in iterators so I'm not sure the mutability was necessary. I assume
the author(s) made it mutable due to some internal implementation constraints
that I don't feel like searching for right now :)

But just to clear things up, my response to Bruce wasn't about the mutability
of DictionaryEntry, it was about the mutability of the objects that it
references. That's what I assumed Bruce meant when he wrote, "structs that
contain references to _mutable_ objects", although reading it out-of-context
now I can see why you thought that.
I think it's
hilarious that the structs have the nice immediate-setting semantics
for mutable structs
myStructClass foo;
foo.bar = 1;
foo.baz = 2;
//all parameters initialized, it's ready to use, no constructor
needed.
but you can only use them with mutable structs anyways, making it
completely useless since MS says to never-ever-do-mutable-structs. I
want the readonly attribute to apply to property setters, and then
integrate that with the 3.0 Object Initializers so we can have some
non-excruciating syntax for immutables.

I won't argue that :)

--
Dave Sexton

"Martin Z" <ma***********@gmail.comwrote in message
news:11**********************@b28g2000cwb.googlegr oups.com...
Holy poop, DictionaryEntry is mutable? (off to MSDN).... Whoa. Oh,
and my comment about avoiding including value-types in structs was from
the optimization direction - obviously if you're using structs because
you want value-type semantics then it doesn't matter what you stuff in
them (as long as they're immutable to avoid confusing aliasing
behaviour).

Funny that nullables are value-type - I recently got an error from the
XmlSerializer where it complained that they were reference types, and
thus couldn't be XmlAttributes. That was just silly.

Anyhow, I think the reason DictionaryEntry is mutable is just because
people got really sick of saying new DictionaryEntry<MyKeyType,
MyValueType- not for any good technical reason. I think it's
hilarious that the structs have the nice immediate-setting semantics
for mutable structs
myStructClass foo;
foo.bar = 1;
foo.baz = 2;
//all parameters initialized, it's ready to use, no constructor
needed.

but you can only use them with mutable structs anyways, making it
completely useless since MS says to never-ever-do-mutable-structs. I
want the readonly attribute to apply to property setters, and then
integrate that with the 3.0 Object Initializers so we can have some
non-excruciating syntax for immutables.

Dave Sexton wrote:
Hi Bruce,

Of course, structs that contain references to _mutable_
objects can lead to some awfully puzzling, nearly-unpredictable
behaviour, so I wouldn't recommend that. :-)

DictionaryEntry is one that doesn't conform to that idea, however.

--
Dave Sexton

"Bruce Wood" <br*******@canada.comwrote in message
news:11*********************@b28g2000cwb.googlegro ups.com...

Martin Z wrote:
Bruce, My understanding is that, if designed to be entirely immutable
and containing no events, then there is almost no visible difference
between a class and a struct.

Apparently so. I'm trying to think of differences in behaviour between
an immutable class and a struct, and I can't. Of course, it's Monday
morning. I could be wrong.

One would have to overload == appropriately (and, one presumes, the
other mathematical and comparison operators), but apart from that I
can't think of any hitches. Of course, the temptation with a class
would be to make it mutable, but that's just a temptation, not a given.

The struct is primarily a speed-optimization - access to stack-variables
is
much faster.

I wouldn't state that as the primary speed benefits of structs. I
consider the primary speed benefit of structs being that they don't
need to be garbage-collected. So, if you are doing extensive
calculations that involve the creation of myriad intermediate results
then structs are a better choice because objects created on the heap
have to be GC'd.

However, this is only one consideration in whether to make something a
struct or a class, and not even the most important. The most important
consideration, IMHO, is whether the thing you want to create displays
_value semantics_. There are lots of discussions in this newsgroup
about struct vs class and value vs reference semantics.

Hence, structs should only contain other valuetypes.

No, I disagree. For example, I have a struct called a Measure, which
contains a decimal quantity and a unit of measure. UnitOfMeasure is a(n
immutable) reference type. I think that our disagreement on this point
goes back to the speed benefits of structs: I see storage on the stack
as a side-effect of using structs, not as a motivation for using
structs, and so I don't see anything wrong with structs that contain
references. Of course, structs that contain references to _mutable_
objects can lead to some awfully puzzling, nearly-unpredictable
behaviour, so I wouldn't recommend that. :-)
Oct 30 '06 #15

P: n/a
Hi Marin,
structs containing references to mutable objects is what I meant by
"aliasing" - that is, if I have a struct I may assume that everything I
do with it will be copy-semantics... however, if it contains a
reference to a mutable class (say a stringbuilder) then if I make
changes to that stringbuilder, then all copies (not just the object I'm
accessing to make the changes) will see that, which is unexpected
behaviour for a struct. That is, an alias where we expect a copy.
Thanks for clearing that up. I didn't realize that you were agreeing with
Bruce when you wrote, "aliasing".

But I think DictionaryEntry proves that it may be appropriate to define a
struct that has references to mutable objects. When DictionaryEntry contains
references, the value of the DictionaryEntry itself is the relationship
between the references. It doesn't matter whether the objects being
referenced can be mutated or not. Therefore, structs that assign value to
references or their relationships should have no problem referencing mutable
objects.
And yes, I agree that Nullables _should_ be valuetype, and likely are
in implementation - I just thought that they were reference-types
because errors thrown by the XmlSerializer informed me that they were
reference types... which is likely just the serializer getting very
confused by the concept of a nullable value-type.
Nullable<Tis an immutable value type.
That is a strange error - quite possibly a bug.

--
Dave Sexton

"Martin Z" <ma***********@gmail.comwrote in message
news:11**********************@h48g2000cwc.googlegr oups.com...
structs containing references to mutable objects is what I meant by
"aliasing" - that is, if I have a struct I may assume that everything I
do with it will be copy-semantics... however, if it contains a
reference to a mutable class (say a stringbuilder) then if I make
changes to that stringbuilder, then all copies (not just the object I'm
accessing to make the changes) will see that, which is unexpected
behaviour for a struct. That is, an alias where we expect a copy.

And yes, I agree that Nullables _should_ be valuetype, and likely are
in implementation - I just thought that they were reference-types
because errors thrown by the XmlSerializer informed me that they were
reference types... which is likely just the serializer getting very
confused by the concept of a nullable value-type.

Dave Sexton wrote:
>Hi Martin,
obviously if you're using structs because
you want value-type semantics then it doesn't matter what you stuff in
them (as long as they're immutable to avoid confusing aliasing
behaviour).

What do you mean by "aliasing behaviour"?
Funny that nullables are value-type - I recently got an error from the
XmlSerializer where it complained that they were reference types, and
thus couldn't be XmlAttributes. That was just silly.

I think Nullable<Tshould be a value type just like DictionaryEntry. They
each assign a value to the objects that they contain - nullability or hash
entry, respectively.

Although nullability is only useful for value types, which is why I suspect
that you can't make a Nullable<string>, for example.

But hash entries can be anything, including mutable objects.
DictionaryEntry
is just a value: the relationship between a key and its corresponding
value.
If the key or the value are object references then the value of the hash
entry
itself is simply the relationship between the two references. If another
DictionaryEntry contains the same key and value references, then the values
of
the DictionaryEntries are equal.

Nullable<Tand DictionaryEntry do not represent tangible objects, they
represent assignable values. It helps some people to think of values as
conceptual and objects as physical, like me!
Anyhow, I think the reason DictionaryEntry is mutable is just because
people got really sick of saying new DictionaryEntry<MyKeyType,
MyValueType- not for any good technical reason.

I've never actually created an instance of DictionaryEntry though. I've
only
used it in iterators so I'm not sure the mutability was necessary. I
assume
the author(s) made it mutable due to some internal implementation
constraints
that I don't feel like searching for right now :)

But just to clear things up, my response to Bruce wasn't about the
mutability
of DictionaryEntry, it was about the mutability of the objects that it
references. That's what I assumed Bruce meant when he wrote, "structs that
contain references to _mutable_ objects", although reading it
out-of-context
now I can see why you thought that.
I think it's
hilarious that the structs have the nice immediate-setting semantics
for mutable structs
myStructClass foo;
foo.bar = 1;
foo.baz = 2;
//all parameters initialized, it's ready to use, no constructor
needed.
but you can only use them with mutable structs anyways, making it
completely useless since MS says to never-ever-do-mutable-structs. I
want the readonly attribute to apply to property setters, and then
integrate that with the 3.0 Object Initializers so we can have some
non-excruciating syntax for immutables.

I won't argue that :)

--
Dave Sexton

"Martin Z" <ma***********@gmail.comwrote in message
news:11**********************@b28g2000cwb.googleg roups.com...
Holy poop, DictionaryEntry is mutable? (off to MSDN).... Whoa. Oh,
and my comment about avoiding including value-types in structs was from
the optimization direction - obviously if you're using structs because
you want value-type semantics then it doesn't matter what you stuff in
them (as long as they're immutable to avoid confusing aliasing
behaviour).

Funny that nullables are value-type - I recently got an error from the
XmlSerializer where it complained that they were reference types, and
thus couldn't be XmlAttributes. That was just silly.

Anyhow, I think the reason DictionaryEntry is mutable is just because
people got really sick of saying new DictionaryEntry<MyKeyType,
MyValueType- not for any good technical reason. I think it's
hilarious that the structs have the nice immediate-setting semantics
for mutable structs
myStructClass foo;
foo.bar = 1;
foo.baz = 2;
//all parameters initialized, it's ready to use, no constructor
needed.

but you can only use them with mutable structs anyways, making it
completely useless since MS says to never-ever-do-mutable-structs. I
want the readonly attribute to apply to property setters, and then
integrate that with the 3.0 Object Initializers so we can have some
non-excruciating syntax for immutables.

Dave Sexton wrote:
Hi Bruce,

Of course, structs that contain references to _mutable_
objects can lead to some awfully puzzling, nearly-unpredictable
behaviour, so I wouldn't recommend that. :-)

DictionaryEntry is one that doesn't conform to that idea, however.

--
Dave Sexton

"Bruce Wood" <br*******@canada.comwrote in message
news:11*********************@b28g2000cwb.googlegr oups.com...

Martin Z wrote:
Bruce, My understanding is that, if designed to be entirely immutable
and containing no events, then there is almost no visible difference
between a class and a struct.

Apparently so. I'm trying to think of differences in behaviour between
an immutable class and a struct, and I can't. Of course, it's Monday
morning. I could be wrong.

One would have to overload == appropriately (and, one presumes, the
other mathematical and comparison operators), but apart from that I
can't think of any hitches. Of course, the temptation with a class
would be to make it mutable, but that's just a temptation, not a
given.

The struct is primarily a speed-optimization - access to
stack-variables
is
much faster.

I wouldn't state that as the primary speed benefits of structs. I
consider the primary speed benefit of structs being that they don't
need to be garbage-collected. So, if you are doing extensive
calculations that involve the creation of myriad intermediate results
then structs are a better choice because objects created on the heap
have to be GC'd.

However, this is only one consideration in whether to make something a
struct or a class, and not even the most important. The most important
consideration, IMHO, is whether the thing you want to create displays
_value semantics_. There are lots of discussions in this newsgroup
about struct vs class and value vs reference semantics.

Hence, structs should only contain other valuetypes.

No, I disagree. For example, I have a struct called a Measure, which
contains a decimal quantity and a unit of measure. UnitOfMeasure is
a(n
immutable) reference type. I think that our disagreement on this point
goes back to the speed benefits of structs: I see storage on the stack
as a side-effect of using structs, not as a motivation for using
structs, and so I don't see anything wrong with structs that contain
references. Of course, structs that contain references to _mutable_
objects can lead to some awfully puzzling, nearly-unpredictable
behaviour, so I wouldn't recommend that. :-)


Oct 30 '06 #16

P: n/a

Martin Z wrote:
Anyhow, I think the reason DictionaryEntry is mutable is just because
people got really sick of saying new DictionaryEntry<MyKeyType,
MyValueType- not for any good technical reason. I think it's
hilarious that the structs have the nice immediate-setting semantics
for mutable structs
myStructClass foo;
foo.bar = 1;
foo.baz = 2;
//all parameters initialized, it's ready to use, no constructor
needed.

but you can only use them with mutable structs anyways, making it
completely useless since MS says to never-ever-do-mutable-structs.
Do they? I've never seen them say this, but then I delve into the MSDN
doc only when I have to.

In fact, MS made some more famous mutable structs: Point and Rectangle.
I think that I understand why they did it: they did it so that people
could use syntax like this:

myPoint.X = 7;

rather than forcing them to create a whole new Point just to change the
X or Y coordinate, like this:

Point myPoint = new Point(7, myPoint.Y);

Yes, the former looks cleaner, but IMHO making Point mutable wasn't
worth all of the confusion it causes, and they would have been better
off to force us to use the second syntax.

I'm sure you know about the confusion: non-intuitive behaviour when a
property returns a Point, or when a Point is boxed for storage in an
aggregate structure. Many, many newbies try to use the above p.X = 7
syntax in those situations and then wonder why their point's
coordinates didn't change. Yuck.

I just plain don't indulge in creating mutable structs for questionable
improvements in syntax. If you want to change one aspect of a struct's
state, "new" up a new one. You just have to be sure to include a
constructor that takes all publicly-settable state as arguments.

Oct 30 '06 #17

P: n/a
Hi Bruce,

<snip>
I'm sure you know about the confusion: non-intuitive behaviour when a
property returns a Point, or when a Point is boxed for storage in an
aggregate structure. Many, many newbies try to use the above p.X = 7
syntax in those situations and then wonder why their point's
coordinates didn't change. Yuck.
I just plain don't indulge in creating mutable structs for questionable
improvements in syntax
<snip>

I agree that structs should be immutable, without question. However, many,
many newbies do many, many things wrong. I'm not sure that I agree with the
reasoning behind your conclusion. Newbs seems to always catch all exceptions
too, but we really can't get rid of that functionality either.

I guess I'd prefer immutability in structs just so shrewd programmers don't
make the same mistake on accident. I can't think of a better reason than
that, unfortunately.

--
Dave Sexton
Oct 31 '06 #18

P: n/a

Dave Sexton wrote:
Hi Bruce,

<snip>
I'm sure you know about the confusion: non-intuitive behaviour when a
property returns a Point, or when a Point is boxed for storage in an
aggregate structure. Many, many newbies try to use the above p.X = 7
syntax in those situations and then wonder why their point's
coordinates didn't change. Yuck.
I just plain don't indulge in creating mutable structs for questionable
improvements in syntax
<snip>

I agree that structs should be immutable, without question. However, many,
many newbies do many, many things wrong. I'm not sure that I agree with the
reasoning behind your conclusion. Newbs seems to always catch all exceptions
too, but we really can't get rid of that functionality either.

I guess I'd prefer immutability in structs just so shrewd programmers don't
make the same mistake on accident. I can't think of a better reason than
that, unfortunately.
LOL... well, I guess appealing to the newbie thing wasn't a good
argument. :-)

What I meant to say is that if Location is a property of type Point,
then this looks as though it ought to work:

myRectangle.Location.X = 7;

but it doesn't. It's perfectly logical that it doesn't work, but the
logic is subtle and requires considerable knowledge of how .NET / C#
works. I dislike things that look as though they should do something
but which, for subtle reasons, do something else (or, in this case,
nothing). Granted, the compiler complains about this specific case, but
there are other cases in which it doesn't. I prefer that my code be
clearly readable to all: newbies and veterans alike, so I prefer to
give up syntactic sugar if it makes my code clearer.

It's so much easier to remember that you can't change a struct's
state--ever--than to remember that you can change it under some
circumstances but not under other circumstances, for perfectly logical
but non-obvious reasons. That just makes the code more difficult to
maintain, IMHO.

One of the clues that this is going on is when newbies (who usually
know other languages, so they're not new to programming, just new to
C#) make the same mistake over and over again. Now, sometimes the
feature is so truly useful that its very utility outweighs the
resulting confusion. Structs, for example, confuse the heck out of
people coming from the C/C++ world, but it's so very useful to be able
to create new objects with value semantics that I wouldn't give it up
to make the language easier to understand. Mere semantic sugar, such as

myPoint.X = 7;

is another thing entirely. I would rather live with more long-winded
code and do away with the confusion than have a handy shorthand that
then creates problems elsewhere in the language.

I've worked in several shops of mixed-language, mixed-skill
programmers, so I prefer code that someone not terribly familiar with
the language can understand. Mutable structs just throw a big wrench
into that, so I avoid them.

Oct 31 '06 #19

P: n/a
Hi Bruce,

I agree with your new reasoning :)

I guess I don't mind this too much:

Point pt = new Point(
[complex math for x goes here],
[complex math for y goes here]
);

I've used the format above a lot and it's just as clean as assignments that
follow construction, IMO. However, ".X = ..." and ".Y = ..." is a bit more
intuitive, although Point is probably a bad example of this because everyone
knows it's (x,y), but if it were a struct with several parameters then inline
construction might get confusing. Although, you can declare local variables
instead and pass the variables to the constructor. But that seems a bit
ridiculous just to construct a single value type.

Whatever - I'm just going to stick with the idea that all structs should be
immutable for now in light of the reasons that you have stated.
myRectangle.Location.X = 7;
I know this won't compile, but I think the only way for the compiler to miss
an assignment to a mutable struct that doesn't have a variable is when it's
boxed. I don't know what kind of effect this would have on the CLR, but maybe
a subsequent version of the framework could force immutability on all boxed
value-types and throw an exception on an assignment attempt. C# 8.5 perhaps?

Of course, I really don't know for sure if the compiler will miss non-variable
assignments on boxed structs only.

--
Dave Sexton

"Bruce Wood" <br*******@canada.comwrote in message
news:11**********************@e3g2000cwe.googlegro ups.com...
>
Dave Sexton wrote:
>Hi Bruce,

<snip>
I'm sure you know about the confusion: non-intuitive behaviour when a
property returns a Point, or when a Point is boxed for storage in an
aggregate structure. Many, many newbies try to use the above p.X = 7
syntax in those situations and then wonder why their point's
coordinates didn't change. Yuck.
I just plain don't indulge in creating mutable structs for questionable
improvements in syntax
<snip>

I agree that structs should be immutable, without question. However, many,
many newbies do many, many things wrong. I'm not sure that I agree with
the
reasoning behind your conclusion. Newbs seems to always catch all
exceptions
too, but we really can't get rid of that functionality either.

I guess I'd prefer immutability in structs just so shrewd programmers don't
make the same mistake on accident. I can't think of a better reason than
that, unfortunately.

LOL... well, I guess appealing to the newbie thing wasn't a good
argument. :-)

What I meant to say is that if Location is a property of type Point,
then this looks as though it ought to work:

myRectangle.Location.X = 7;

but it doesn't. It's perfectly logical that it doesn't work, but the
logic is subtle and requires considerable knowledge of how .NET / C#
works. I dislike things that look as though they should do something
but which, for subtle reasons, do something else (or, in this case,
nothing). Granted, the compiler complains about this specific case, but
there are other cases in which it doesn't. I prefer that my code be
clearly readable to all: newbies and veterans alike, so I prefer to
give up syntactic sugar if it makes my code clearer.

It's so much easier to remember that you can't change a struct's
state--ever--than to remember that you can change it under some
circumstances but not under other circumstances, for perfectly logical
but non-obvious reasons. That just makes the code more difficult to
maintain, IMHO.

One of the clues that this is going on is when newbies (who usually
know other languages, so they're not new to programming, just new to
C#) make the same mistake over and over again. Now, sometimes the
feature is so truly useful that its very utility outweighs the
resulting confusion. Structs, for example, confuse the heck out of
people coming from the C/C++ world, but it's so very useful to be able
to create new objects with value semantics that I wouldn't give it up
to make the language easier to understand. Mere semantic sugar, such as

myPoint.X = 7;

is another thing entirely. I would rather live with more long-winded
code and do away with the confusion than have a handy shorthand that
then creates problems elsewhere in the language.

I've worked in several shops of mixed-language, mixed-skill
programmers, so I prefer code that someone not terribly familiar with
the language can understand. Mutable structs just throw a big wrench
into that, so I avoid them.

Oct 31 '06 #20

P: n/a
One approach I've rather liked: provide an immutable interface to a
mutable object, and in cases where you'd like it to be immutable (like
in collections) use the interface. So you have the immutable IPoint
(which your collections handle) and the mutable Point (which you can
play with).

An alternate approach that would take some codegen but would make
immutables more palatable: autogenerate a constructor for the Struct
class that has one argument for each public property/field. Then,
autogenerate a "Copy" method for each such property, which uses that
constructor. So, for a 2D point we have the autogenerated constructor
public Point(x, y)
{
this.x = x;
this.y = y;
}

and the autogenerated Copy methods
public Point CopyWithX(x) {return new Point(x, this.y);}
public Point CopyWithY(y) {return new Point(this.x, y);}

So then you'd have a little convenience for doing changes on
immutables.

In general, constructors are just too damn much boilerplate legwork -
they're the sort of thing that screams out for codegen. The whole
DotNet framwork seems designed to work best with the basic,
parameterless constructor (witness the XmlSerializer, generics only
allowing new(), etc.) which is totally incompatible with immutable
objects. Now we're getting the object-initializers in 3.0 to make
initializing objects outside of the constructor even easier... I'm
starting to think that somebody at Microsoft hates parametric
constructors... but constructors are crucial to immutable objects. I'm
thinking the former, interface-based approach (or outright copying the
mutable object into a different, immutable type of object before using
it) would be most compatible with DotNet's preference for parameterless
constructors.

Dave Sexton wrote:
Hi Bruce,

I agree with your new reasoning :)

I guess I don't mind this too much:

Point pt = new Point(
[complex math for x goes here],
[complex math for y goes here]
);

I've used the format above a lot and it's just as clean as assignments that
follow construction, IMO. However, ".X = ..." and ".Y = ..." is a bit more
intuitive, although Point is probably a bad example of this because everyone
knows it's (x,y), but if it were a struct with several parameters then inline
construction might get confusing. Although, you can declare local variables
instead and pass the variables to the constructor. But that seems a bit
ridiculous just to construct a single value type.

Whatever - I'm just going to stick with the idea that all structs should be
immutable for now in light of the reasons that you have stated.
myRectangle.Location.X = 7;

I know this won't compile, but I think the only way for the compiler to miss
an assignment to a mutable struct that doesn't have a variable is when it's
boxed. I don't know what kind of effect this would have on the CLR, but maybe
a subsequent version of the framework could force immutability on all boxed
value-types and throw an exception on an assignment attempt. C# 8.5 perhaps?

Of course, I really don't know for sure if the compiler will miss non-variable
assignments on boxed structs only.

--
Dave Sexton

"Bruce Wood" <br*******@canada.comwrote in message
news:11**********************@e3g2000cwe.googlegro ups.com...

Dave Sexton wrote:
Hi Bruce,

<snip>
I'm sure you know about the confusion: non-intuitive behaviour when a
property returns a Point, or when a Point is boxed for storage in an
aggregate structure. Many, many newbies try to use the above p.X = 7
syntax in those situations and then wonder why their point's
coordinates didn't change. Yuck.

I just plain don't indulge in creating mutable structs for questionable
improvements in syntax
<snip>

I agree that structs should be immutable, without question. However, many,
many newbies do many, many things wrong. I'm not sure that I agree with
the
reasoning behind your conclusion. Newbs seems to always catch all
exceptions
too, but we really can't get rid of that functionality either.

I guess I'd prefer immutability in structs just so shrewd programmers don't
make the same mistake on accident. I can't think of a better reason than
that, unfortunately.
LOL... well, I guess appealing to the newbie thing wasn't a good
argument. :-)

What I meant to say is that if Location is a property of type Point,
then this looks as though it ought to work:

myRectangle.Location.X = 7;

but it doesn't. It's perfectly logical that it doesn't work, but the
logic is subtle and requires considerable knowledge of how .NET / C#
works. I dislike things that look as though they should do something
but which, for subtle reasons, do something else (or, in this case,
nothing). Granted, the compiler complains about this specific case, but
there are other cases in which it doesn't. I prefer that my code be
clearly readable to all: newbies and veterans alike, so I prefer to
give up syntactic sugar if it makes my code clearer.

It's so much easier to remember that you can't change a struct's
state--ever--than to remember that you can change it under some
circumstances but not under other circumstances, for perfectly logical
but non-obvious reasons. That just makes the code more difficult to
maintain, IMHO.

One of the clues that this is going on is when newbies (who usually
know other languages, so they're not new to programming, just new to
C#) make the same mistake over and over again. Now, sometimes the
feature is so truly useful that its very utility outweighs the
resulting confusion. Structs, for example, confuse the heck out of
people coming from the C/C++ world, but it's so very useful to be able
to create new objects with value semantics that I wouldn't give it up
to make the language easier to understand. Mere semantic sugar, such as

myPoint.X = 7;

is another thing entirely. I would rather live with more long-winded
code and do away with the confusion than have a handy shorthand that
then creates problems elsewhere in the language.

I've worked in several shops of mixed-language, mixed-skill
programmers, so I prefer code that someone not terribly familiar with
the language can understand. Mutable structs just throw a big wrench
into that, so I avoid them.
Oct 31 '06 #21

P: n/a

Dave Sexton wrote:
Hi Bruce,

I agree with your new reasoning :)

I guess I don't mind this too much:

Point pt = new Point(
[complex math for x goes here],
[complex math for y goes here]
);

I've used the format above a lot and it's just as clean as assignments that
follow construction, IMO. However, ".X = ..." and ".Y = ..." is a bit more
intuitive, although Point is probably a bad example of this because everyone
knows it's (x,y), but if it were a struct with several parameters then inline
construction might get confusing. Although, you can declare local variables
instead and pass the variables to the constructor. But that seems a bit
ridiculous just to construct a single value type.

Whatever - I'm just going to stick with the idea that all structs should be
immutable for now in light of the reasons that you have stated.
myRectangle.Location.X = 7;

I know this won't compile, but I think the only way for the compiler to miss
an assignment to a mutable struct that doesn't have a variable is when it's
boxed. I don't know what kind of effect this would have on the CLR, but maybe
a subsequent version of the framework could force immutability on all boxed
value-types and throw an exception on an assignment attempt. C# 8.5 perhaps?
The problem isn't really that boxed value types must be immutable. It's
better to say that temporary values that are never copied to any
addressable location must be immutable. That's what's going on in the
myRectangle.Location.X case: the .X being set is not the one held
against the rectangle, but the return result from a property, which is
a temporary value on the stack that will be thrown away as soon as the
operation is done. The compiler detects that the value will never be
used again, and complains that modifying it will have no effect.

Unfortunately, the compiler doesn't do this in every circumstance. In
particular, as you pointed, out, it seems not to be able to tell in the
case of boxed value types, in which case the unboxed value is a copy of
the value in the box, and so modifying the copy does not, of course,
modify the value in the box.

Even generics doesn't solve this latter problem, because unless I miss
my guess the following:

List<PointmyList = new List<Point>();
myList.Add(new Point(5,5));
myList[0].X = 7;

will not work either. I hope that the compiler is smart enough to catch
this and complain about it, though. (I'm not running 2.0 yet... anyone
care to confirm?)

Oct 31 '06 #22

P: n/a
Hi Martin,
One approach I've rather liked: provide an immutable interface to a
mutable object, and in cases where you'd like it to be immutable (like
in collections) use the interface. So you have the immutable IPoint
(which your collections handle) and the mutable Point (which you can
play with).
"Shield" pattern - I like it.
An alternate approach that would take some codegen but would make
immutables more palatable: autogenerate a constructor for the Struct
class that has one argument for each public property/field. Then,
autogenerate a "Copy" method for each such property, which uses that
constructor. So, for a 2D point we have the autogenerated constructor
public Point(x, y)
{
this.x = x;
this.y = y;
}

and the autogenerated Copy methods
public Point CopyWithX(x) {return new Point(x, this.y);}
public Point CopyWithY(y) {return new Point(this.x, y);}

So then you'd have a little convenience for doing changes on
immutables.
A bit convoluted and impractical - I'd rather just use a mutable struct with
good documentation :)
In general, constructors are just too damn much boilerplate legwork -
they're the sort of thing that screams out for codegen. The whole
DotNet framwork seems designed to work best with the basic,
parameterless constructor (witness the XmlSerializer, generics only
allowing new(), etc.) which is totally incompatible with immutable
objects. Now we're getting the object-initializers in 3.0 to make
initializing objects outside of the constructor even easier... I'm
starting to think that somebody at Microsoft hates parametric
constructors... but constructors are crucial to immutable objects. I'm
thinking the former, interface-based approach (or outright copying the
mutable object into a different, immutable type of object before using
it) would be most compatible with DotNet's preference for parameterless
constructors.
I don't see any preference for parameterless constructors aside from the
generic where : new() and Control/Component designer support. And don't
forget you always have the factory pattern when constructors become a problem.

Object initializers, BTW, are required for LINQ - I don't think they are meant
to supplant any constructor design issues.

--
Dave Sexton
Oct 31 '06 #23

P: n/a
Hi Bruce,
myRectangle.Location.X = 7;

I know this won't compile, but I think the only way for the compiler to
miss
an assignment to a mutable struct that doesn't have a variable is when it's
boxed. I don't know what kind of effect this would have on the CLR, but
maybe
a subsequent version of the framework could force immutability on all boxed
value-types and throw an exception on an assignment attempt. C# 8.5
perhaps?

The problem isn't really that boxed value types must be immutable. It's
better to say that temporary values that are never copied to any
addressable location must be immutable. That's what's going on in the
myRectangle.Location.X case: the .X being set is not the one held
against the rectangle, but the return result from a property, which is
a temporary value on the stack that will be thrown away as soon as the
operation is done. The compiler detects that the value will never be
used again, and complains that modifying it will have no effect.

Unfortunately, the compiler doesn't do this in every circumstance. In
particular, as you pointed, out, it seems not to be able to tell in the
case of boxed value types, in which case the unboxed value is a copy of
the value in the box, and so modifying the copy does not, of course,
modify the value in the box.
That's exactly my point. The compiler catches it because it's detecting the
value type - but if it were boxed, then the compiler wouldn't complain. My
proposal is that the CLR should throw an exception at runtime when any public
property on a struct that only exists on the stack, and is currently boxed, is
assigned a value. Instead, mabye the CLR should protect all private fields
while the instance is boxed, on the stack, so that even method calls that
attempt to mutate the struct would fail as well. What do you think?
Even generics doesn't solve this latter problem, because unless I miss
my guess the following:

List<PointmyList = new List<Point>();
myList.Add(new Point(5,5));
myList[0].X = 7;

will not work either. I hope that the compiler is smart enough to catch
this and complain about it, though. (I'm not running 2.0 yet... anyone
care to confirm?)
Good idea - but the compiler is really acute:

{ Error 2 Cannot modify the return value of
'System.Collections.Generic.List<System.Drawing.Po int>.this[int]' because it
is not a variable [file] 19 3 [project] }

Looks like my proposal might still have some merit :)

--
Dave Sexton
Oct 31 '06 #24

P: n/a

Dave Sexton wrote:
Hi Bruce,

My proposal is that the CLR should throw an exception at runtime when any public
property on a struct that only exists on the stack, and is currently boxed, is
assigned a value. Instead, mabye the CLR should protect all private fields
while the instance is boxed, on the stack, so that even method calls that
attempt to mutate the struct would fail as well. What do you think?
Well, the difficulty is that the value isn't "boxed on the stack". The
value is taken out of the box and then placed on the stack... in
effect, it's unboxed *onto* the stack. The compiler would then have to
remember that the value on the stack came from a box on the heap.

I would prefer that the compiler continue to be developed in the
direction it's going: disallow changes to structs based on where the
value is _going_, not where it came from. That is, you're not allowed
to modify a value on the stack if that modified value is not destined
for any permanent home, either stored into a variable on the stack,
stored into some object's state on the heap, or boxed back onto the
heap. Regardless of where it came from, modifying a value that has no
destination and is therefore thrown away doesn't make sense.

Unfortunately, there seem to be limits to the compiler's ability to
perform static analysis to find out if the modified value will end up
being used anywhere.
Even generics doesn't solve this latter problem, because unless I miss
my guess the following:

List<PointmyList = new List<Point>();
myList.Add(new Point(5,5));
myList[0].X = 7;

will not work either. I hope that the compiler is smart enough to catch
this and complain about it, though. (I'm not running 2.0 yet... anyone
care to confirm?)

Good idea - but the compiler is really acute:

{ Error 2 Cannot modify the return value of
'System.Collections.Generic.List<System.Drawing.Po int>.this[int]' because it
is not a variable [file] 19 3 [project] }
I expected as much. It's unfortunate, though, that the message isn't
clearer: something like, "Setting a property of this
System.Drawing.Point value will have no effect because the modification
would be made to a temporary copy returned by the property this[int],
not to the backing value itself." Maybe it's a good thing I don't work
for MS, or all of the error messages would turn into novels. :-)

Oct 31 '06 #25

P: n/a
The problem is, of course, that structs can hold references to objects,
and struct code can access other classes. As such, assigning to a
struct's property and dropping it on the floor is not necessarily
fruitless. If you could be sure that a method/setter on a struct was
"functional" (that is, it only affects the struct itself and does not
use any other classes) then you can be assured the operation is
harmless.

However, you probably could safely apply this to fields. If our struct
has a public field value changed and nothing is being done with the
struct after that change (including copying it) then that field change
was 100% pointless.

Bruce Wood wrote:
Dave Sexton wrote:
Hi Bruce,

My proposal is that the CLR should throw an exception at runtime when any public
property on a struct that only exists on the stack, and is currently boxed, is
assigned a value. Instead, mabye the CLR should protect all private fields
while the instance is boxed, on the stack, so that even method calls that
attempt to mutate the struct would fail as well. What do you think?

Well, the difficulty is that the value isn't "boxed on the stack". The
value is taken out of the box and then placed on the stack... in
effect, it's unboxed *onto* the stack. The compiler would then have to
remember that the value on the stack came from a box on the heap.

I would prefer that the compiler continue to be developed in the
direction it's going: disallow changes to structs based on where the
value is _going_, not where it came from. That is, you're not allowed
to modify a value on the stack if that modified value is not destined
for any permanent home, either stored into a variable on the stack,
stored into some object's state on the heap, or boxed back onto the
heap. Regardless of where it came from, modifying a value that has no
destination and is therefore thrown away doesn't make sense.

Unfortunately, there seem to be limits to the compiler's ability to
perform static analysis to find out if the modified value will end up
being used anywhere.
Even generics doesn't solve this latter problem, because unless I miss
my guess the following:
>
List<PointmyList = new List<Point>();
myList.Add(new Point(5,5));
myList[0].X = 7;
>
will not work either. I hope that the compiler is smart enough to catch
this and complain about it, though. (I'm not running 2.0 yet... anyone
care to confirm?)
Good idea - but the compiler is really acute:

{ Error 2 Cannot modify the return value of
'System.Collections.Generic.List<System.Drawing.Po int>.this[int]' because it
is not a variable [file] 19 3 [project] }

I expected as much. It's unfortunate, though, that the message isn't
clearer: something like, "Setting a property of this
System.Drawing.Point value will have no effect because the modification
would be made to a temporary copy returned by the property this[int],
not to the backing value itself." Maybe it's a good thing I don't work
for MS, or all of the error messages would turn into novels. :-)
Oct 31 '06 #26

P: n/a

Martin Z wrote:
The problem is, of course, that structs can hold references to objects,
and struct code can access other classes. As such, assigning to a
struct's property and dropping it on the floor is not necessarily
fruitless. If you could be sure that a method/setter on a struct was
"functional" (that is, it only affects the struct itself and does not
use any other classes) then you can be assured the operation is
harmless.

However, you probably could safely apply this to fields. If our struct
has a public field value changed and nothing is being done with the
struct after that change (including copying it) then that field change
was 100% pointless.
The compiler seems able to sort this out in some situations, such as
that of Point. X and Y are properties, not fields, and the compiler
seems able to determine that they have no side-effects and therefore
setting them in a temporary copy is a useless operation. I assume that
this is part-and-parcel of the information the the compiler leaves
lying around in assemblies to allow the JITter to decide whether it can
in-line property assignments, etc.

Oct 31 '06 #27

P: n/a
Hi Bruce,
>My proposal is that the CLR should throw an exception at runtime when any
public
property on a struct that only exists on the stack, and is currently boxed,
is
assigned a value. Instead, mabye the CLR should protect all private fields
while the instance is boxed, on the stack, so that even method calls that
attempt to mutate the struct would fail as well. What do you think?

Well, the difficulty is that the value isn't "boxed on the stack". The
value is taken out of the box and then placed on the stack... in
effect, it's unboxed *onto* the stack.
Thanks for pointing that out. I shouldn't have wrote "boxed on the stack"
because that's not exactly what I meant :)

Lol - I just tried to illustrate my idea in code, but to my surprise the
compiler caught it! Clever:

struct Value
{
public object NestedValue;
public int Number;
}

static void Main()
{
Value value = new Value();
value.NestedValue = new Value();

((Value) value.NestedValue).Number = 1;

Console.WriteLine(((Value) value.NestedValue).Number);
}

Error 1 Cannot modify the result of an unboxing conversion [file] 45 5
[project]
I thought this would be the simplest example of what I was trying to explain.
I'd really like to know if there are any cases where unaddressed
value-assignment won't be caught by the 2.0 compiler. Maybe we're making too
many assumptions now :)

(Is unaddressed an appropriate term to describe a struct that has no
established roots in memory?)

The compiler would then have to
remember that the value on the stack came from a box on the heap.
Good point and I assumed that the CLR could do that, but maybe it's just not
feasible.
I would prefer that the compiler continue to be developed in the
direction it's going: disallow changes to structs based on where the
value is _going_, not where it came from. That is, you're not allowed
to modify a value on the stack if that modified value is not destined
for any permanent home, either stored into a variable on the stack,
stored into some object's state on the heap, or boxed back onto the
heap. Regardless of where it came from, modifying a value that has no
destination and is therefore thrown away doesn't make sense.

Unfortunately, there seem to be limits to the compiler's ability to
perform static analysis to find out if the modified value will end up
being used anywhere.
I'm not so sure that there are any limits. Maybe at a certain level of
abstraction the compiler finally gives up?
>{ Error 2 Cannot modify the return value of
'System.Collections.Generic.List<System.Drawing.P oint>.this[int]' because
it
is not a variable [file] 19 3 [project] }

I expected as much. It's unfortunate, though, that the message isn't
clearer: something like, "Setting a property of this
System.Drawing.Point value will have no effect because the modification
would be made to a temporary copy returned by the property this[int],
not to the backing value itself." Maybe it's a good thing I don't work
for MS, or all of the error messages would turn into novels. :-)
That could be a good thing, Bruce. People who don't know what the error means
would benefit from an in-depth message and people who do know what it means
can just avoid it to begin with ;)

--
Dave Sexton
Oct 31 '06 #28

P: n/a
Hi Martin,

I'm partial to the readonly private field idea myself, however I'm
hard-pressed to think of an example where the 2.0 compiler will miss the
assignment.

Originally, I thought that the compiler would only miss an assignment if it
didn't know whether the struct being mutated was retrieved from a boxed
struct, and therefore wouldn't have any roots in memory. But the compiler
knew this.

Actually, I just realized that the example I posted to Bruce was overkill.
The following code produces the same results:

object o = Point.Empty;
((Point) o).X = 5;

So it seems that you really can't trick the compiler in this fashion.

Does anybody have any sample code that will trick the compiler to allow
assignment to a struct without roots in memory?

It seems like mutable structs might not be so dangerous after all (< more
assumptions) ;)

--
Dave Sexton

"Martin Z" <ma***********@gmail.comwrote in message
news:11**********************@f16g2000cwb.googlegr oups.com...
The problem is, of course, that structs can hold references to objects,
and struct code can access other classes. As such, assigning to a
struct's property and dropping it on the floor is not necessarily
fruitless. If you could be sure that a method/setter on a struct was
"functional" (that is, it only affects the struct itself and does not
use any other classes) then you can be assured the operation is
harmless.

However, you probably could safely apply this to fields. If our struct
has a public field value changed and nothing is being done with the
struct after that change (including copying it) then that field change
was 100% pointless.

Bruce Wood wrote:
>Dave Sexton wrote:
Hi Bruce,

My proposal is that the CLR should throw an exception at runtime when any
public
property on a struct that only exists on the stack, and is currently
boxed, is
assigned a value. Instead, mabye the CLR should protect all private
fields
while the instance is boxed, on the stack, so that even method calls that
attempt to mutate the struct would fail as well. What do you think?

Well, the difficulty is that the value isn't "boxed on the stack". The
value is taken out of the box and then placed on the stack... in
effect, it's unboxed *onto* the stack. The compiler would then have to
remember that the value on the stack came from a box on the heap.

I would prefer that the compiler continue to be developed in the
direction it's going: disallow changes to structs based on where the
value is _going_, not where it came from. That is, you're not allowed
to modify a value on the stack if that modified value is not destined
for any permanent home, either stored into a variable on the stack,
stored into some object's state on the heap, or boxed back onto the
heap. Regardless of where it came from, modifying a value that has no
destination and is therefore thrown away doesn't make sense.

Unfortunately, there seem to be limits to the compiler's ability to
perform static analysis to find out if the modified value will end up
being used anywhere.
Even generics doesn't solve this latter problem, because unless I miss
my guess the following:

List<PointmyList = new List<Point>();
myList.Add(new Point(5,5));
myList[0].X = 7;

will not work either. I hope that the compiler is smart enough to catch
this and complain about it, though. (I'm not running 2.0 yet... anyone
care to confirm?)

Good idea - but the compiler is really acute:

{ Error 2 Cannot modify the return value of
'System.Collections.Generic.List<System.Drawing.Po int>.this[int]' because
it
is not a variable [file] 19 3 [project] }

I expected as much. It's unfortunate, though, that the message isn't
clearer: something like, "Setting a property of this
System.Drawing.Point value will have no effect because the modification
would be made to a temporary copy returned by the property this[int],
not to the backing value itself." Maybe it's a good thing I don't work
for MS, or all of the error messages would turn into novels. :-)

Oct 31 '06 #29

P: n/a
Hi Bruce,

This is the only relevant information I found in the spec cited afterwards:

"When a property or indexer declared in a struct-type is the target of an
assignment, the instance expression associated with the property or indexer
access must be classified as a variable. If the instance expression is
classified as a value, a compile-time error occurs. [Note: Because of 14.5.4,
the same rule also applies to fields as well. end note]"
[14.3.1 Simple Assignment]
Draft C# Language Spec March 2001
http://msdn.microsoft.com/net/ecma/WD05-Review.pdf

The following spec seems to contain no information that is relevant to our
discussion:

C# 2.0 Language Spec
http://download.microsoft.com/downlo...cationVer2.doc

So it seems that the C# compiler prevents assignment to value-types that
aren't classified as a variable. [14.3.1 Simple Assignment]

I think that covers everything, unless you can somehow set a private field of
a struct while it's boxed, which is exactly what I suggested that the CLR
should prevent.

Was the immutable structure paradigm established by older languages and just
carried over by experts as something to warn people about, without any hard
evidence of it being problematic in C#?

I could have sworn that I've seen examples of C# code that was susceptible to
the behavior we have been discussing without prevention by the compiler,
although I can almost remember all of them being tagged with what you said
before: "Granted, the compiler complains about this specific case, but there
are other cases in which it doesn't". With all due respect, are you sure?

I like having the flexibility of "Point.X =", but I've always been against it
because of the aforementioned reasons, which I'm starting to doubt. Until I
dig up some more proof that structs shouldn't be mutable I'm going to consider
this issue unresolved, in light of this discussion, and try to avoid it when
people ask me why this should be. I'll just change the subject: "So, how
about them Yanks?" ;)

--
Dave Sexton
Nov 1 '06 #30

P: n/a
Thanks for all the replies in this thread. I've learnt a lot (I
think!).

I'm going to investigate the nullable types mentioned by Ryan.

John.

Nov 2 '06 #31

P: n/a
I'm now confused by earlier comments that said that a struct should be
immutable.

I've been reading the C# Language Specification for Structs and found
the following in $11.3.1 Value semantics:

Given the declaration

struct Point
{
public int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
the code fragment

Point a = new Point(10, 10);
Point b = a;
a.x = 100;
System.Console.WriteLine(b.x);

outputs the value 10. The assignment of a to b creates a copy of the
value, and b is thus unaffected by the assignment to a.x. Had Point
instead been declared as a class, the output would be 100 because a and
b would reference the same object

I understand why the output value is 10.

My concern is that various people have said that a struct should be
immutable and Microsoft says so in their documentation. If that is the
case, why does the example in the language specification provide public
fields (X,Y) and show an example where they are modified?

John.

Nov 2 '06 #32

P: n/a

Jo********@hotmail.co.uk wrote:
I'm now confused by earlier comments that said that a struct should be
immutable.

I've been reading the C# Language Specification for Structs and found
the following in $11.3.1 Value semantics:

Given the declaration

struct Point
{
public int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
the code fragment

Point a = new Point(10, 10);
Point b = a;
a.x = 100;
System.Console.WriteLine(b.x);

outputs the value 10. The assignment of a to b creates a copy of the
value, and b is thus unaffected by the assignment to a.x. Had Point
instead been declared as a class, the output would be 100 because a and
b would reference the same object

I understand why the output value is 10.

My concern is that various people have said that a struct should be
immutable and Microsoft says so in their documentation. If that is the
case, why does the example in the language specification provide public
fields (X,Y) and show an example where they are modified?
Because Microsoft doesn't always provide the best of examples. :-)

Really, because the statement "structs should be immutable" is a
guideline, not a law. For example, System.Drawing.Point and
System.Drawing.Rectangle are mutable structs.

The problem with mutable structs is that the disadvantages typically
outweight the advantages. In some cases, the people at Microsoft
decided that the advantages won out. It's a matter of taste (I don't
agree with them in the cases of Point and Rectangle), but that was
their decision.

The advantage of mutable structs is that sometimes it makes the code
syntactically cleaner. So, using the example of System.Drawing.Point,
it reads better to write

Point a = new Point(5, 10);
....
a.X = 15;

than it reads to write

Point a = new Point(5, 10);
....
a = new Point(15, a.Y);

The latter looks clumsy and roundabout, while the former is more
intuitive.

The disadvantage is that this intuitive, cleaner-looking code falls
absolutely flat on its face in many common situations, as you've seen
discussed in this thread. Fortunately, the compiler catches many of
them, but the whole thing causes much head-scratching and confusion.

Personally, I prefer to live with the latter, clumsy syntax and avoid
the problems that mutable structs can introduce. Evidently the folks at
MS don't take as extreme a view as I do. Their rules can be stated as,
"Structs should be immutable unless you can think of a good reason why
one shouldn't be." My rules can be stated as, "Structs should be
immutable, and I've never seen a good reason why one shouldn't be."

Nov 3 '06 #33

P: n/a
Hi John,

I assume that Microsoft used a mutable struct to try and show why you should
make structs immutable.
Point b = a;
If it's not obvious to a programmer that "b" is a copy of "a" then they might
make the wrong assumption about the values that "b" contains when "a" is
modified, as you've illustrated, but if "a" was immutable then that can't
happen.

The idea that "all structs should be immutable" is to prevent programmers from
inadvertently introducing bugs into their code by misusing value-types.

I tried to figure out in this thread whether the idea has any merit. It
seems, in my research thus far, that the C# compiler will prevent one form of
misuse whereby a value is assigned to a struct that doesn't have a variable
backing it, in which case the value would be lost and so the operation would
be pointless. This can occur when you try to assign a value to an instance of
a struct by setting one of its properties or fields after it has just been
unboxed or if it was obtained via a public property, but not assigned to a
variable in both cases.

I've heard experts state that this could be a problem in C# but never saw any
evidence of that. Though the compiler does allow structs to be mutated in
method calls, even when not assigned to a variable.

I don't think I, or anyone I know has ever introduced a bug into their code
because they called a method on a struct that wasn't assigned to a variable.
Therefore, I'm not so sure that is a good excuse for universal struct
immutability.

The only remaining excuse that I'm aware of for the axiom is the idea that
value-type semantics might not be intuitive enough for us programmers to have
the ability in the first place. I dislike that, and I think that's what
Microsoft's example is trying to illustrate.

What do you think?

--
Dave Sexton

<Jo********@hotmail.co.ukwrote in message
news:11**********************@i42g2000cwa.googlegr oups.com...
I'm now confused by earlier comments that said that a struct should be
immutable.

I've been reading the C# Language Specification for Structs and found
the following in $11.3.1 Value semantics:

Given the declaration

struct Point
{
public int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
the code fragment

Point a = new Point(10, 10);
Point b = a;
a.x = 100;
System.Console.WriteLine(b.x);

outputs the value 10. The assignment of a to b creates a copy of the
value, and b is thus unaffected by the assignment to a.x. Had Point
instead been declared as a class, the output would be 100 because a and
b would reference the same object

I understand why the output value is 10.

My concern is that various people have said that a struct should be
immutable and Microsoft says so in their documentation. If that is the
case, why does the example in the language specification provide public
fields (X,Y) and show an example where they are modified?

John.

Nov 3 '06 #34

P: n/a

Dave Sexton wrote:
Hi John,

I assume that Microsoft used a mutable struct to try and show why you should
make structs immutable.
Point b = a;

If it's not obvious to a programmer that "b" is a copy of "a" then they might
make the wrong assumption about the values that "b" contains when "a" is
modified, as you've illustrated, but if "a" was immutable then that can't
happen.

The idea that "all structs should be immutable" is to prevent programmers from
inadvertently introducing bugs into their code by misusing value-types.

I tried to figure out in this thread whether the idea has any merit. It
seems, in my research thus far, that the C# compiler will prevent one form of
misuse whereby a value is assigned to a struct that doesn't have a variable
backing it, in which case the value would be lost and so the operation would
be pointless. This can occur when you try to assign a value to an instance of
a struct by setting one of its properties or fields after it has just been
unboxed or if it was obtained via a public property, but not assigned to a
variable in both cases.

I've heard experts state that this could be a problem in C# but never saw any
evidence of that. Though the compiler does allow structs to be mutated in
method calls, even when not assigned to a variable.
Remember, however, that the compiler catches only the obvious. I don't
believe that the compiler could catch this:

public struct ValueThingy
{
int _x;
int _y;

public ValueThingy(int x, int y) { this._x = x; this._y = y; }
public void Flip() { int flip = this._x; this._x = this._y; this._y
= flip; }
}

public class Foo
{
ValueThingy _v;

public Foo() { this._v = new ValueThingy(1, 2); }

public ValueThingy V { get { return this._v; } }
}

....

Foo f = new Foo();
f.V.Flip();

which will, of course, modify a temporary copy of the ValueThingy
returned by the property V, and then throw away the result.

Once you start getting into structs that can be altered via methods,
it's a whole other ballgame, and the compiler can't help you. The
compiler helps only in the classic case of modification via property
setters.

Nov 3 '06 #35

P: n/a
Hi Bruce,

<snip>
Once you start getting into structs that can be altered via methods,
it's a whole other ballgame, and the compiler can't help you. The
compiler helps only in the classic case of modification via property
setters.
Yes, I pointed that out in my article too.

The compiler prevents setting fields as well as properties, so methods are the
only variable here.

Everyone always makes it seem like there are so many unintuitive ways you can
screw up using a mutable struct, but calling methods on value-types that
aren't assigned to a variable appears to be the only way and that happens
rarely (never in my experience). Therefore, I don't agree this constitutes
that when designing a struct there should be a default of immutability in the
design unless mutability is required anymore than that would be true when
designing a class. Also, not allowing mutability of value-types in the
language at all seems quite extreme to me as well.

I used to side with you, but I've changed gears because our discussion has
showed me that the compiler does handle what I believe to be the worst cases
of unintuativeness when using structs and that any other restrictions would
simply be catering to the needs of programmers that don't really understand
value-types in the first place.

--
Dave Sexton
Nov 3 '06 #36

P: n/a
BTW, how great is the word, "unintuitiveness"?

I doubt it's real but I couldn't think of anything better to use at the time
;)

--
Dave Sexton

"Bruce Wood" <br*******@canada.comwrote in message
news:11*********************@i42g2000cwa.googlegro ups.com...
>
Dave Sexton wrote:
>Hi John,

I assume that Microsoft used a mutable struct to try and show why you
should
make structs immutable.
Point b = a;

If it's not obvious to a programmer that "b" is a copy of "a" then they
might
make the wrong assumption about the values that "b" contains when "a" is
modified, as you've illustrated, but if "a" was immutable then that can't
happen.

The idea that "all structs should be immutable" is to prevent programmers
from
inadvertently introducing bugs into their code by misusing value-types.

I tried to figure out in this thread whether the idea has any merit. It
seems, in my research thus far, that the C# compiler will prevent one form
of
misuse whereby a value is assigned to a struct that doesn't have a variable
backing it, in which case the value would be lost and so the operation
would
be pointless. This can occur when you try to assign a value to an instance
of
a struct by setting one of its properties or fields after it has just been
unboxed or if it was obtained via a public property, but not assigned to a
variable in both cases.

I've heard experts state that this could be a problem in C# but never saw
any
evidence of that. Though the compiler does allow structs to be mutated in
method calls, even when not assigned to a variable.

Remember, however, that the compiler catches only the obvious. I don't
believe that the compiler could catch this:

public struct ValueThingy
{
int _x;
int _y;

public ValueThingy(int x, int y) { this._x = x; this._y = y; }
public void Flip() { int flip = this._x; this._x = this._y; this._y
= flip; }
}

public class Foo
{
ValueThingy _v;

public Foo() { this._v = new ValueThingy(1, 2); }

public ValueThingy V { get { return this._v; } }
}

...

Foo f = new Foo();
f.V.Flip();

which will, of course, modify a temporary copy of the ValueThingy
returned by the property V, and then throw away the result.

Once you start getting into structs that can be altered via methods,
it's a whole other ballgame, and the compiler can't help you. The
compiler helps only in the classic case of modification via property
setters.

Nov 3 '06 #37

P: n/a
Hi Bruce,

I just realized too that the following
Therefore, I don't agree this constitutes that when designing a struct there
should be a default of immutability in the design unless mutability is
required anymore than that would be true when designing a class
might give the wrong impression.

I was trying to say that I think classes should be designed with immutability
in mind, by default, and that the evidence provided does not indicate to me
there is any more of a reason to do the same when designing structs than the
reasons for doing so when designing a class.

I promise that this is my last self-post :)

Thanks for the conversation, BTW.

--
Dave Sexton

"Dave Sexton" <dave@jwa[remove.this]online.comwrote in message
news:e6**************@TK2MSFTNGP02.phx.gbl...
Hi Bruce,

<snip>
>Once you start getting into structs that can be altered via methods,
it's a whole other ballgame, and the compiler can't help you. The
compiler helps only in the classic case of modification via property
setters.

Yes, I pointed that out in my article too.

The compiler prevents setting fields as well as properties, so methods are
the only variable here.

Everyone always makes it seem like there are so many unintuitive ways you
can screw up using a mutable struct, but calling methods on value-types that
aren't assigned to a variable appears to be the only way and that happens
rarely (never in my experience). Therefore, I don't agree this constitutes
that when designing a struct there should be a default of immutability in
the design unless mutability is required anymore than that would be true
when designing a class. Also, not allowing mutability of value-types in the
language at all seems quite extreme to me as well.

I used to side with you, but I've changed gears because our discussion has
showed me that the compiler does handle what I believe to be the worst cases
of unintuativeness when using structs and that any other restrictions would
simply be catering to the needs of programmers that don't really understand
value-types in the first place.

--
Dave Sexton


Nov 3 '06 #38

This discussion thread is closed

Replies have been disabled for this discussion.