my rant on value types and accessors

T

The Petar

I am really unhappy that C# accessors are not powerful
enough to mimic as if you were accessing an class field.

In particular, let S be:

public struct S {
public int v;
public void change () { v = 99; }
}

Let C be:

public class C {
public S s;
}

Then I could change the value of s, by soing:

C c;
c.s.change ();

If, instead, I wanted to run access to s through an accessor:

public class C {
private S s;
public S s_accessor {
get { return s; }
set { s = value; }
}
}

Then the expression:

C c;
c.s_accessor.change ();

will not have the same effect as:

C c;
c.s.change ();

I find this to be a big flaw. I.e. accessors cannot mimic the behavior
of
value typed fields properly. I also think this flaw is unfixable, b/c
Microsoft
itself exhibits this flaw in its own implementation of Nullable types:

class Test {

public struct S {
public int v;
public void ch () { v = 88; }
}

public static void Main () {
S y;
y.v = 0;
S? x = y;
x.Value.ch ();

Console.WriteLine ("{0}", x.Value.v);
}
}

Prints out "0", instead of the naturally expected "88".
 
J

james.curran

The said:
Prints out "0", instead of the naturally expected "88".


In other words, you want S to reference sematics instead of value
sematic. So, then, why are you make it a struct instead of a class?
 
B

Ben Voigt

In other words, you want S to reference sematics instead of value
sematic. So, then, why are you make it a struct instead of a class?

I don't know, maybe to allocate an array of 1000 of them as local variables
without hammering the garbage collector. Maybe because 99% of the time the
type is used with value semantics, and calling Clone() all the time is just
too much (and again hammers the garbage collector). Maybe it's predefined
as a struct in someone else's class library. In short, a million reasons.

For example, how about having a Vector class:

class Vector
{
private Point internalHead;
public Point Head
{
get { return internalHead; }
set { internalHead = value; }
}

//same for tail
}

System.Drawing.Point is a struct. Microsoft already made that choice. But
now you can do (where v is type Vector):
int x = v.Head.X;
but not
v.Head.X = x*3; // changes temporary Point returned from get_Head()

In the good old days of C++, there was no difference between struct and
class. Reference and value semantics were both available for all
user-defined types using language features such as "references".

MyStruct operator[](int index) const; // value semantics
MyStruct& operator[](int index); // reference semantics

Actually this has been true from ordinary C, but in C you had to use
pointers, which required the caller to use a different syntax, and
encouraged breaking type-safety. C# is a throwback to C...

The answer is: yes you can get reference semantics with structs. You must
use pointers to do so. You use the -> operator familiar to C/C++
programmers for accessing structure members through a pointer. And you must
mark your code as "unsafe"... though the documentation suggests unsafe is
only needed if you do pointer arithmetic. I haven't tested whether you can
do:
int a = 5;
int* p = &a;
p->ToString();
without an unsafe context. There's no pointer arithmetic, so type-safety is
assured.

However, you're going to have a problem when you need a pointer to a struct
inside a ref class, because the garbage collector can change the object.
What you really need is the fancy support Microsoft added to C++/CLI to
handle all of this very neatly: tracking references (%) and interior_ptr.

If C# let you override operator->, you could have interior_ptr in C# pretty
quick. Instead, you need to have member (so they can access the private
fields backing the public properties) classes or structs, with properties
defined so that they proxy the properties of the private field.

class Vector
{
private Point internalHead;
public class RefHeadPoint
{
private Point? fromPoint;
private Vector boss;
public RefHeadPoint(Point pt) : fromPoint(pt), boss(null) {}
public RefHeadPoint(Vector v) : fromPoint(null), boss(v) {}
public static implicit operator Point(RefHeadPoint pt) { return
pt.pt ?? pt.boss.internalHead; }
public static implicit operator RefHeadPoint(pt) { return new
RefHeadPoint(pt); }
public int X
{
get { return (pt ?? boss.internalHead).X; }
set { if (pt.HasValue) pt.X = value; else boss.internalHead.X =
value; }
}
// same for Y
}

public RefHeadPoint Head
{
get { return new RefHeadPoint(this); }
set { internalHead = (Point)value; }
}

//same for tail
}

and now you can write:
v.Head.X = x*3;
 
M

Mark Wilden

Ben Voigt said:
In the good old days of C++, there was no difference between struct and
class.

Right -- so some folks wondered why they had both class and struct. The
answer, of course, was that an OOP language must have classes! :)

///ark
 

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

Top