csharp language idea

  • Thread starter Thread starter cody
  • Start date Start date
C

cody

currently when trying to change a struct returned by a property, the
compiler generates an error.

so if you try

someControl.Location.Y = 10;

you get an error which is logical if one understands how value types work.
but wouldn't it be an good idea to allow such a construct and let the
compiler generate code like that in such a case:

Point p = someControl.Location;
p.Y=10;
someControl.Location = p;

In cases where there is a set accessor in the property this will certainly
possible. In most cases such properties will be trivial so they will get
inlined and the overhead with the temporary variable can be optimized away.
What do you think about that?
 
This really has nothing to do with structs. It has to do with properties.
The Location property of a Control is a Point. Because a Point is a value
type, when you access the property, you access it by value, that is, you get
back a copy of the original Point rather than a reference to the original
Point. You can certainly change the members of any struct individually. But
not in this case.

What you *can* do is to create a new Point and assign it to the Location
property, or you can set the Left property, which corresponds to the
Location.X property, or you can set the Top property to change the
Location.Y.

--
HTH,

Kevin Spencer
Microsoft MVP
Professional Numbskull

Hard work is a medication for which
there is no placebo.
 
Yes, it would work. I'll leave it to luminaries such as Jon Skeet to
say whether the compiler would be capable of figuring out what to do in
every situation.

However, I think that it would obscure something that is already cloudy
in the minds of many newbie C# programmers: when to use classes and
when to use structs.

For my part, I find it annoying that the Framework designers made Point
and Rectangle mutable structs. I think that it would have been clearer
to have left them immutable and require you to say this:

Point newPoint = new Point(oldPoint.X, 10);

to change the Y coordinate to 10, for example. Yes, it's more verbose,
but it removes the temptation to try to do what you pointed out and
which generates a compiler error.

As it stands right now, Point and Rectangle can be altered...
sometimes... depending upon the behaviour of values in the particular
situation. Stuff like that just sticks in my craw.

So, yes, the two solutions would be: 1) make the struct immutable, or
2) try to fix the situations in which the compiler refuses to set
struct properties.
 
Kevin Spencer said:
This really has nothing to do with structs. It has to do with properties.

I disagree. It has *everything* to do with structs.
The Location property of a Control is a Point. Because a Point is a value
type, when you access the property, you access it by value, that is, you get
back a copy of the original Point rather than a reference to the original
Point.

At which point it's classified as a value, not a variable. Exactly - in
what way does this have nothing to do with structs?

From section 14.3.1 of the C# ECMA spec (v1.1 of C#):

<quote>
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.
</quote>

That's exactly what's happening here - but the instance expression here
is classified as a value, hence the error.

That restriction does not apply to classes, hence it has everything to
do with structs, IMO.
 
Bruce Wood said:
Yes, it would work. I'll leave it to luminaries such as Jon Skeet to
say whether the compiler would be capable of figuring out what to do in
every situation.

I wouldn't like to say, to be honest. I can certainly imagine some
situations where it could produce some *very* odd results. It's a bit
like passing a property by reference - you can do it in VB.NET, and I
guess occasionally it's handy for saving a few lines, but doing it
long-hand makes it clearer what's going on.
However, I think that it would obscure something that is already cloudy
in the minds of many newbie C# programmers: when to use classes and
when to use structs.
Agreed.

For my part, I find it annoying that the Framework designers made Point
and Rectangle mutable structs.

Absolutely. Mutable structs are, in general, a bad idea, IMO. They
worked that out for DateTime, but not Point/Rectangle. There are some
very strange corner cases you can get with mutable structs.

(Out of interest, did you know you could assign to "this" in a struct?
It certainly took me by surprise when I was reading the spec recently.)
 
This really has nothing to do with structs. It has to do with properties.
I disagree. It has *everything* to do with structs.

Hey, Jon, I was revising my message and forgot to remove that part! You're
right, of course. Put it down to sloppy editing.

--

Kevin Spencer
Microsoft MVP
Professional Numbskull

Hard work is a medication for which
there is no placebo.
 
Kevin Spencer said:
Hey, Jon, I was revising my message and forgot to remove that part! You're
right, of course. Put it down to sloppy editing.

No problem - I did think it a bit strange given the rest of the message
:)
 
I can certainly imagine some
situations where it could produce some *very* odd results.

Which situations?
At the moment there is always the problem when refactoring code making a
class into a struct or changing a public variable to a property, the code
suddenly refuses to compile due to the changed behaviour which is a thing
which should not be.

At the moment people doing lots or stupid workarounds getting around the
problem so for example the Windows.Forms.Control class has a Size and Bounds
property (both structs). Because we cannot set the properties of these
structs, there are additionally a Width, Height, Top, Bottom, Left and
Height property in the class!

Also the struct PositionNormalTextured in managed directX has a Position, a
TextureCoordinates and Normal property. Because we cannot assign to the
properties of them we additionally have: X,Y,Z,Nx,Ny,Nz,U and V properties
in the PositionNormalTextured class so we can change all variables
separately, I tell you this is more than just funny...
Absolutely. Mutable structs are, in general, a bad idea, IMO. They
worked that out for DateTime, but not Point/Rectangle.

I absolutely disagree! You certainly never programmed directx, imagine
matrices, vectors or vertices being immutable!
There are some very strange corner cases you can get with mutable structs.

which cases?
(Out of interest, did you know you could assign to "this" in a struct?
It certainly took me by surprise when I was reading the spec recently.)

a funny thing, but a good feature.
 
cody said:
Which situations?

Ones where setting a property has an additional side-effect. With the
new syntax, it's not obvious that you'd be actualy setting the whole
Size property. In some cases, that wouldn't make much odds - but in
other cases it could be significantly different. For instance, suppose
you had a struct with a lot of fields, and validation involved going
off to the database. If setting each "sub-property" in turn actually
involved setting the "master property" each time, that could be quite
painful - whereas what you should be doing in that case is fetching the
value once, changing the properties appropriately, and then resetting
the "master" property a single time. That's just one example though...
At the moment there is always the problem when refactoring code making a
class into a struct or changing a public variable to a property, the code
suddenly refuses to compile due to the changed behaviour which is a thing
which should not be.

Yes, it should be - it shows that they've changed the semantics in an
incompatible way. Changing something from a class to a struct can break
lots and lots of behaviour - the *good* thing about this is that you
get told about it at compile-time, instead of things just breaking!
At the moment people doing lots or stupid workarounds getting around the
problem so for example the Windows.Forms.Control class has a Size and Bounds
property (both structs). Because we cannot set the properties of these
structs, there are additionally a Width, Height, Top, Bottom, Left and
Height property in the class!

As has been said before, the structs shouldn't really be mutable. There
were design decisions before - but patching the language to get round
those and create (IMO) a bigger mess is not the way to go.
I absolutely disagree! You certainly never programmed directx, imagine
matrices, vectors or vertices being immutable!

What would be wrong with that? You'd just have methods like you have on
DateTime, which return a new DateTime instead. Unless those structs are
huge (in which case they probably shouldn't be structs in the first
place) that shouldn't be a problem.
which cases?

I can't remember all of them off-hand, but there are some really weird
ones. I've been reading through the C# 2.0 specification, and there are
some places where mutable structs behave in ways you really need to
read the specification *very* closely to understand.
a funny thing, but a good feature.

I think we'll have to disagree.
 
However, I think that it would obscure something that is already cloudy
in the minds of many newbie C# programmers: when to use classes and
when to use structs.

Since when is "it could confuse newbies" a valid criteria :)
Besides, at the moment the different behaviour of class and struct are very
confusing and require a deep understanding how value types work.
It assignment works if you have an array of Point: array[0].X=0 but it
doesn't work with ArrayList or even List<Point>.
 
Now it came to my mind that my proposed solution has to be extended to solve
an additional existing problem:
(Jon I think this is the problem you where talking about :) )

List<Point> l = new List<Point>();
l.Add(new Point());
l[0].Offset(3,3); // this is supposed to offset point by 3,3

At the moment this code will give no warning, it simply will not work. all
Methods that alter structs has this problem.
It cannot be solved because the compiler cannot know it a method will alter
the struct or not (maybe they could do some flow analysis which would
introduce very high complexity here).

One solution that the accessed property/indexer is reassigned after a method
is called so the last line of my code would be compiled as:

Point p = l[0];
p.Offset(3,3);
l[0] = p;

Which is not much overhead, but the overhead starts here:

string s = myControl.Size.ToString();

since ToString() is a method and Size a struct an implicit assignment would
be generated (in my proposal) to myControl.Size which is certainly not
expected or desired by anyone :(
 
However, I think that it would obscure something that is already cloudy
Since when is "it could confuse newbies" a valid criteria :)
Besides, at the moment the different behaviour of class and struct are very
confusing and require a deep understanding how value types work.
It assignment works if you have an array of Point: array[0].X=0 but it
doesn't work with ArrayList or even List<Point>.

That's what I was trying to say: mutable structs make life (and one's
code) very confusing. It's better to avoid them if at all possible. You
seem to start of disagreeing with me and then go on to give a great
example of what I was saying...?
I absolutely disagree! You certainly never programmed directx, imagine
matrices, vectors or vertices being immutable!

No, I haven't programmed DirectX, but as Jon said, you would just have
methods that returned new matricies, vectors, or vertices, instead of
being able to change them in place. Could you give an example (for
those of us who haven't used DirectX) of where that would make life
difficult?

Mind you, I'm not saying that mutable structs should _never_ be
allowed... just that they're very difficult to work with and one should
avoid creating them if possible. I've been doing this (programming)
long enough to know that for every rule of style there are a dozen
exceptions in niche areas of computing for highly specialized reasons.
That doesn't make the general rule any less valid; it just makes it a
general rule that has some exceptions.
At the moment there is always the problem when refactoring code making a
class into a struct or changing a public variable to a property, the code
suddenly refuses to compile due to the changed behaviour which is a thing
which should not be.

I would never compare changing a class to a struct or vice versa with
changing a public variable to a public property. The latter is a common
refactoring operation that has very little fallout on client code
(leaving aside the fact that creating the public field in the first
place wasn't a very smart thing to do). The only thing that will break
in that case is if you passed it by "ref" or "out" anywhere, which
should be relatively rare.

But, good heavens... changing a class to a struct (or vice versa) means
changing the fundamental semantics of what the thing is and how it
acts. I would _expect_ the compiler to get heartily sick on the
resulting code! If a person finds himself changing a class to a struct
or vice versa then I would claim that that person didn't understand
value and reference semantics when they wrote the original code. That's
sort of like returning your new stereo amp and exchanging it for a
refrigerator, and then being annoyed that there's no obvious place to
plug in the speakers.... :-)
 
Ones where setting a property has an additional side-effect. With the
new syntax, it's not obvious that you'd be actualy setting the whole
Size property. In some cases, that wouldn't make much odds - but in
other cases it could be significantly different. For instance, suppose
you had a struct with a lot of fields, and validation involved going
off to the database. If setting each "sub-property" in turn actually
involved setting the "master property" each time, that could be quite
painful - whereas what you should be doing in that case is fetching the
value once, changing the properties appropriately, and then resetting
the "master" property a single time. That's just one example though...

Yes, you are right.
Yes, it should be - it shows that they've changed the semantics in an
incompatible way. Changing something from a class to a struct can break
lots and lots of behaviour - the *good* thing about this is that you
get told about it at compile-time, instead of things just breaking!

Maybe, a think the problem connected with value types cannot be solved
without making drawbacks.
I think the CLR team had a hard time, not how to do it perfectly, but solve
ther problem it the best possible way.
What would be wrong with that? You'd just have methods like you have on
DateTime, which return a new DateTime instead. Unless those structs are
huge (in which case they probably shouldn't be structs in the first
place) that shouldn't be a problem.

a matrix consist of 4x4 floats, making them at least 64 byte in size.
Vertices like PositionnormalTextured are 3*4+4*4+2*4 bytes in size, if
loading big models from a file consisting of 100.000 vertices it makes a
difference imo.
I can't remember all of them off-hand, but there are some really weird
ones. I've been reading through the C# 2.0 specification, and there are
some places where mutable structs behave in ways you really need to
read the specification *very* closely to understand.

could you please try and remember now Iam very tense :)
I think we'll have to disagree.

Why not? Remember the "this" in a value type is not a pointer like it is in
a class but a value passed by reference. So we can change it.
How else would you program a method which makes a copy of a given struct
without copying each field separately?
 
Besides, at the moment the different behaviour of class and struct are
very
confusing and require a deep understanding how value types work.
It assignment works if you have an array of Point: array[0].X=0 but it
doesn't work with ArrayList or even List<Point>.

That's what I was trying to say: mutable structs make life (and one's
code) very confusing. It's better to avoid them if at all possible. You
seem to start of disagreeing with me and then go on to give a great
example of what I was saying...?

Yes Iam starting to agree with you and Jon :)
No, I haven't programmed DirectX, but as Jon said, you would just have
methods that returned new matricies, vectors, or vertices, instead of
being able to change them in place. Could you give an example (for
those of us who haven't used DirectX) of where that would make life
difficult?

a matrix is a stuct of 16 float values (can logical be thought as 4x4
array).
The struct has fields named M11 to M44.
A not very uncommon operation is for example doing myMatrix.M32 = someValue;
I've been doing this (programming)
long enough to know that for every rule of style there are a dozen
exceptions in niche areas of computing for highly specialized reasons.

I couldn't agree more!
I would never compare changing a class to a struct or vice versa with
changing a public variable to a public property. The latter is a common
refactoring operation that has very little fallout on client code

Changing a public struct variable into a property is what I meant here and
this has an impact on client code since it causes the effect discussed here.
The only thing that will break
in that case is if you passed it by "ref" or "out" anywhere, which
should be relatively rare.

depends on the code. remember "niche areas of computing for highly
specialized reasons" :)
If a person finds himself changing a class to a struct
or vice versa then I would claim that that person didn't understand
value and reference semantics when they wrote the original code. That's
sort of like returning your new stereo amp and exchanging it for a
refrigerator, and then being annoyed that there's no obvious place to
plug in the speakers.... :-)

Sometimes it is hard to determine whether to use class or struct.
Maybe when refactoring or redesign of an application it turns out that
requirements/semantics of a given class should be changed into a value type.

Maybe if at a later time one finds the class slower or more memory intensive
than planned because he thought that only a few instances of this object
would be used and later one sees "oh, generating one million instances of
this class makes my code really slow and memory intensive".
Ok, maybe a bit far fetched.
 
Bruce Wood said:
[...] mutable structs make life (and one's code) very confusing.
It's better to avoid them if at all possible.

Well then, how about applying the 'readonly' keyword to
a whole struct or class, forcing all fields to be readonly and
of readonly type. A readonly class would have to derive
from object or another readonly class - perhaps a
System.Readonly class should serve as base for all readonly
classes.

And then, as a means of getting unique representations of
Readonly objects, in the manner of intern'ed strings, a
generic system class with a method for this:

class System.Unique<T> where T: System.Readonly
{
static T [T cnst]
{ ... lookup cnst in a global table of some sort and
insert it if not found ... }
}

This would allow me to write something like:

readonly class Name
{
public Name(string f, string l) {first = f; last = l;}
string first; //implicitly readonly
string last; //implicitly readonly
}

And elsewhere:

Name fowl = Unique<Name>[new Name("Donald", "Duck")];

Or, perhaps with some syntactical sugar and a new keyword 'the':

Name fowl = the Name("Donald", "Duck");

I'm not sure this is the way it should be done but I'd sure
like a generalization of what Intern() does to strings.
 
cody said:
Maybe, a think the problem connected with value types cannot be solved
without making drawbacks.
I think the CLR team had a hard time, not how to do it perfectly, but solve
ther problem it the best possible way.

I don't know about "the best possible way" but they've done pretty
well. (I'm not saying I would necessarily be able to make it better
myself - I'm just cautious about ruling out the possibility of better
ideas!)
a matrix consist of 4x4 floats, making them at least 64 byte in size.
Vertices like PositionnormalTextured are 3*4+4*4+2*4 bytes in size, if
loading big models from a file consisting of 100.000 vertices it makes a
difference imo.

Well, if you're using a value type for performance reasons rather than
semantic reasons, you've already made a design trade-off. When you're
further bending good design practice (which IMO includes making structs
immutable) I think it's reasonable that the compiler makes it slightly
harder to do things. I think that's better than the compiler making it
easy to go behind your back, calling setters which aren't *obviously*
being called in your source.
could you please try and remember now Iam very tense :)

Well, this isn't a *brilliant* example, but it's a start. I wish I
could remember the others.

You know if you have a value type in an ArrayList (not a List<T>) you
have to get it out, change it, and then put it back in order to change
the value, right?

Well, not quite.

Suppose the value type implements an interface which allows mutation.
That interface is implemented by the boxed version as well as the
unboxed version, so can change things in-place, in the box. Here's an
example:

using System;
using System.Collections;

interface IMutable
{
int X { get; set; }
}

struct MutableStruct : IMutable
{
int x;

public int X
{
get { return x; }
set { x = value; }
}
}

class Test
{
static void Main()
{
IList list = new ArrayList();

MutableStruct original = new MutableStruct();
original.X=5;

list.Add(original);

// Compiler disallows this
// ((MutableStruct)list[0]).X = 10;

// But this is fine
((IMutable)list[0]).X = 10;

MutableStruct mutated = (MutableStruct) list[0];
Console.WriteLine (mutated.X);
}
}

It makes sense, but it's slightly unnerving at the same time.
Why not? Remember the "this" in a value type is not a pointer like it is in
a class but a value passed by reference.

Exactly - but that difference is rarely particularly visible, so it
comes as a surprise when you see this syntax for the first time.
So we can change it. How else would you program a method which makes a
copy of a given struct without copying each field separately?

To be honest, I'd copy each field separately if this feature weren't
available. If you're following the normal design guidelines for
structs, there are rarely many fields anyway.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top