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

Boxing & UnBoxing access question

P: n/a
Hi all:

I'm using a struct of type Point that is being passed on to a method as a
refrence type (boxing), the UpdatePoint method changes the coordinates of
this point as such:

Point p = new Point();
UpdatePoint( P );
..
..
..

void UpdatePoint( Object oP )
{
((Point) oP).X = 5;//error CS0131: The left-hand side of an assignment
must
// be a variable, property or indexer
}
Could someone explain to me why I can't access my boxed Point?
Thanks
Ed;;
Nov 16 '05 #1
Share this Question
Share on Google+
16 Replies


P: n/a
See 11.3.5 Boxing and unboxing.

What I would do is create a new Point, set the values as needed and return
the new Point i.e.

Point UpdatePoint( Point oldP )
{
Point newP = newPoint();
newP.X = oldP.X + ...
...
return newP;
}

"Ed A" <Ed A@discussions.microsoft.com> wrote in message
news:89**********************************@microsof t.com...
Hi all:

I'm using a struct of type Point that is being passed on to a method as a
refrence type (boxing), the UpdatePoint method changes the coordinates of
this point as such:

Point p = new Point();
UpdatePoint( P );
.
.
.

void UpdatePoint( Object oP )
{
((Point) oP).X = 5;//error CS0131: The left-hand side of an assignment
must
// be a variable, property or indexer
}
Could someone explain to me why I can't access my boxed Point?
Thanks
Ed;;

Nov 16 '05 #2

P: n/a
Why are you declaring the parameter in UpdatePoint as Object. You could
use ref to value type and change it in the function. Something like
this:
Point p = new Point();
UpdatePoint(ref P );

// After calling this function P.X should be 5.
....
void UpdatePoint( ref Point pt )
{
pt.X = 5;
}

---------
Ajay Kalra
aj*******@yahoo.com

Ed A wrote:
Hi all:

I'm using a struct of type Point that is being passed on to a method as a refrence type (boxing), the UpdatePoint method changes the coordinates of this point as such:

Point p = new Point();
UpdatePoint( P );
.
.
.

void UpdatePoint( Object oP )
{
((Point) oP).X = 5;//error CS0131: The left-hand side of an assignment must
// be a variable, property or indexer
}
Could someone explain to me why I can't access my boxed Point?
Thanks
Ed;;


Nov 16 '05 #3

P: n/a
Remember that Point is a value type, not a reference type. I mean, you
know that, because you're talking about boxing and unboxing, but think
of the implications. Think of what's really going on in your function,
line by line.

You make a call:

UpdatePoint(p);

where UpdatePoint takes an Object. This boxes your Point p... but what
does that really mean? It means that p will be _copied_ to another
place in memory, onto the heap (from the stack, where it currently
lives), and placed within an object-like construct (boxed).

Now, inside UpdatePoint, you say:

((Point)oP)

Here, you're _unboxing_ the point. What does that mean? It means that
the Point that is on the heap (oP) will again be _copied_ to a
temporary location (on the stack, perhaps, or in a register) as a Point
value. Now you say:

((Point)oP).X = 5;

Here, you're saying that you want to change the X coordinate of that
_tempoaray copy_ of the boxed point oP. However, the compiler knows
that this is just a temporary copy on the stack or in a register...
it's not a real variable that you could ever use again. Once the
assignment is done, the temporary copy is thrown away and you're left
with the original value in oP. So, the compiler complains, because
you're doing something that could never have any meaningful effect.

Remember: Points are _value types_. They're copied on usage. Yes,
they're mutable, but using that mutability to do things is dodgy at
best, because it's often difficult to figure out when a value type is
going to be copied and when it's not, as you've found out.

Code that takes advantage of the mutability of a value type is delicate
code, and thus (generally speaking) "bad code" from a maintenance
standpoint.

James came up with the usual solution to this problem: turn UpdatePoint
into a method that returns a Point, and do this:

p = UpdatePoint(p);

or, if UpdatePoint must return an object for some reason, this:

p = (Point)UpdatePoint(p);

Using this method does not, at any point in the process, take advantage
of the mutability of Points, so it's much more robust.

Ajay also came up with a valid idea: pass a Point by ref instead of an
object. However, even there, I wouldn't do this:

public void UpdatePoint(ref Point p)
{
p.X = 5;
}

I would always prefer to do this:

public void UpdatePoint(ref Point p)
{
p = new Point(5, p.Y);
}

Again, at no point does this take advantage of the mutability of Point
fields. No matter what you do to p, it will always work.

Nov 16 '05 #4

P: n/a
Bruce,

I am curious to know why you prefer this:

public void UpdatePoint(ref Point p)
{
p = new Point(5, p.Y);
}

to

public void UpdatePoint(ref Point p)
{
p.X = 5;
}

IOW, why is it better to create a new object as opposed to modifying
the existing object (if its permitted). Is it just personal style or
something else?

Thanks.

----------
Ajay Kalra
aj*******@yahoo.com

Nov 16 '05 #5

P: n/a
But a Point isn't an object... that's the... um... point. :)

I suppose it does boil down to a personal style thing. I prefer to keep
it clear in my head that value types such as Points aren't objects, and
manipulating them as if they were, while it often works, requires that
you keep a more sophisticated mental model of what's going on.

In the particular example I gave:

public void UpdatePoint(ref Point p)
{
p.X = 5;
}

versus

public void UpdatePoint(ref Point p)
{
p = new Point(5, p.Y);
}

It is true that one more Point value is being created (the temporary
one created by new Point(), before it's assigned to p), but this isn't
a heap object being allocated: it's a value that at worst lives briefly
on the stack, and at best is in some register. This is _not_ like
saying "new DataTable()" and then cloning it. Value types are much more
lightweight in terms of resources.

Look at these two examples:

public Point UpdatePoint(Point p)
{
p.X = 5;
return p;
}

versus

public Point UpdatePoint(Point p)
{
return new Point(5, p.Y);
}

Here there is _no difference_ whatsoever. Well, at least the compiler
could easily optimize away any difference. A new Point needs to be
copied onto the stack in any event as a return value. Whether you
modify p and then copy that into the return area, or build a new Point
directly into the return area using p as a model... it's all the same.

In the end, I suppose that it doesn't matter, except that saying

p.X = 5;

lulls my feeble brain into forgetting that I'm dealing with a value
type, which in turn gets me into the kinds of trouble that Ed
experienced. I prefer to clearly separate value types and reference
types by convention: I always change value types by making new ones and
assigning them. I just helps me keep things straight in my head. :)

Nov 16 '05 #6

P: n/a
When I said that saying

p.X = 5;

lulls my feeble brain into forgetting that I'm dealing with a value
type, what I mean is that I start forgetting that I can't do things
like this:

someObject.SomePointProperty.X = 5;

because the Point returned by SomePointProperty is a _copy_ of the
Point stored inside someObject. Of course, the compiler complains if I
try to do this. I must instead say this:

someObject.SomePointProperty = new Point(5,
someOjbect.SomePointProperty.Y);

I just prefer to continue the convention everywhere, even when I don't
have to. That way I never get confused. (I'm easily confused. :-)

Nov 16 '05 #7

P: n/a

Thanks Bruce for the explanation, so it seems that I must either create a
wrapper class around “Point” or re-implement it all together if I wanted it
to behave like a real object!! The idea is to create these points once and
then all methods have access to them instead of having to copy and recopy
them all over the code.
The code draws a simple 2-d shape, the user has the ability to modify any
vertex (Point), so when that happens the OnPaint() event should pickup this
newly modified vertex without having to copy it every time.
It seems that boxing and unboxing is over rated and probably does not truly
convert a value type to a reference type like the help suggests.
Ed;;

"Bruce Wood" wrote:
Remember that Point is a value type, not a reference type. I mean, you
know that, because you're talking about boxing and unboxing, but think
of the implications. Think of what's really going on in your function,
line by line.

You make a call:

UpdatePoint(p);

where UpdatePoint takes an Object. This boxes your Point p... but what
does that really mean? It means that p will be _copied_ to another
place in memory, onto the heap (from the stack, where it currently
lives), and placed within an object-like construct (boxed).

Now, inside UpdatePoint, you say:

((Point)oP)

Here, you're _unboxing_ the point. What does that mean? It means that
the Point that is on the heap (oP) will again be _copied_ to a
temporary location (on the stack, perhaps, or in a register) as a Point
value. Now you say:

((Point)oP).X = 5;

Here, you're saying that you want to change the X coordinate of that
_tempoaray copy_ of the boxed point oP. However, the compiler knows
that this is just a temporary copy on the stack or in a register...
it's not a real variable that you could ever use again. Once the
assignment is done, the temporary copy is thrown away and you're left
with the original value in oP. So, the compiler complains, because
you're doing something that could never have any meaningful effect.

Remember: Points are _value types_. They're copied on usage. Yes,
they're mutable, but using that mutability to do things is dodgy at
best, because it's often difficult to figure out when a value type is
going to be copied and when it's not, as you've found out.

Code that takes advantage of the mutability of a value type is delicate
code, and thus (generally speaking) "bad code" from a maintenance
standpoint.

James came up with the usual solution to this problem: turn UpdatePoint
into a method that returns a Point, and do this:

p = UpdatePoint(p);

or, if UpdatePoint must return an object for some reason, this:

p = (Point)UpdatePoint(p);

Using this method does not, at any point in the process, take advantage
of the mutability of Points, so it's much more robust.

Ajay also came up with a valid idea: pass a Point by ref instead of an
object. However, even there, I wouldn't do this:

public void UpdatePoint(ref Point p)
{
p.X = 5;
}

I would always prefer to do this:

public void UpdatePoint(ref Point p)
{
p = new Point(5, p.Y);
}

Again, at no point does this take advantage of the mutability of Point
fields. No matter what you do to p, it will always work.

Nov 16 '05 #8

P: n/a
> It seems that boxing and unboxing is over rated and probably does not
truly
convert a value type to a reference type like the help suggests.


Its not over rated and it does convert a value type to a reference
type. There is no question about it. Choosing between the two is a
careful decision. As a programmer, you should minimize boxing/unboxing.

---------
Ajay Kalra
aj*******@yahoo.com

Nov 16 '05 #9

P: n/a
Ok, the conversion works... but is it useful? If it make a copy of your data
everytime you box and unbox then how is that truly a refrence type?

"Ajay Kalra" wrote:
It seems that boxing and unboxing is over rated and probably does not

truly
convert a value type to a reference type like the help suggests.


Its not over rated and it does convert a value type to a reference
type. There is no question about it. Choosing between the two is a
careful decision. As a programmer, you should minimize boxing/unboxing.

---------
Ajay Kalra
aj*******@yahoo.com

Nov 16 '05 #10

P: n/a
I am not sure what you mean by useful. Its something you must account
for when thinking about passing parameters. Since you are dealing with
the copy, any modification to the copy will not be reflected to the
original object. In addition, there are performance hits because of
copying.

Consider this:

Console.WriteLine("{0}", 5); // Console.WriteLine takes an object and
// parameter 5 (int, a value type) will
// need to be boxed

The above statement is really same as:

int i = 5;
object obj = i; // Box
Console.WriteLine(obj.ToString());

Inside WriteLine you will need to unbox it as:

object obj;
int i = (int) obj; // Unbox it
string str = i.ToString();

What it shows is the performance penalty of boxing/unboxing. When you
deal with Value types, you have to be careful about implicit
conversions to System.Object. If you can avoid it, Value types should
not be converted to System.Object(your OP was doing it).

In addition, you have to know why you are using Value types. Does your
type just have data? Does it define behavior? Do you expect it to be
polymorphic?

-------
Ajay Kalra
aj*******@yahoo.com

Nov 16 '05 #11

P: n/a
If I may suggest... don't bend the language to your will. Don't twist
the language around to fit your solution... find a solution within the
spirit of the language. Surely other designers (including those at MS)
have come up against these sorts of problems and solved them in some
way.

Yes, you have to "copy and recopy" points. There is no choice, any more
than there is a choice about "copying and recopying" integers. Would
you create your own special Integer class and write all of the
operations for it, just because you didn't want it to be copied all the
time? Of course not. (At least, I hope not. :)

If you have a class that represents a 2D shape, a polygon, then you can
expose its points and allow callers to manipulate them. You can do it
using indexers:

public class Polygon
{
PointList points;

public Polygon()
{
this.points = new PointList();
}

public PointList PointList
{
get { return this.points; }
}
}

public class PointList : IEnumerable, IList, ICollection
{
ArrayList points;

public PointList()
{
points = new ArrayList();
}
...
public object Item[int index]
{
get { return this.Point[index]; }
set { this.Point[index] = (Point)value; }
}

public Point Point[int index]
{
get { return (Point)this.points[index]; }
set { this.points[index] = value; }
}
}

Of course, you have to implement all of the other functionality in
PointList as well. This allows your callers to do things like this:

myPolygon.PointList.Point[12] = new Point(5, 10);

or

myPolygon.PointList.Point[10] = new Point(5,
myPolygon.PointList.Point[10]);

but never

myPolygon.PointList.Point[10].X = 5;

Then again, your callers will see that Polygon.PointList.Point returns
a Point, and so will be expecting this behaviour (since they'll be .NET
programmers who understand value types). If your "custom points" act
like objects rather than like values, this will be confusing, because
programmers familiar with the System.Drawing namespace will wonder
what's going on: they'll be used to Points as values.

As I said: don't try to make the language conform to your vision...
change your vision to conform to the language. In the long run,
programmers using your classes will have an easier time of it, because
your software works the way everything else in .NET works (even if you
think it works wrong).

Boxing does not "convert a value type to a reference type" in the sense
that you're thinking. Boxing changes a value type (such as an integer)
so that it can stand in for an object, which it must in certain
circumstances.

By the way, all of this gets a lot easier in V2.0, which provides us
with generics, and should (almost) remove any need for boxing and
unboxing.

Nov 16 '05 #12

P: n/a
It's a reference type merely for the purposes of getting it from A to
B, or storing it in some aggregate structure that requires a reference
type. It doesn't become a reference type in the sense of becoming a
manipulable object stored on the heap that has an identity. If you try
to use value types that way then you are pushing on a rope. :)

Boxing is merely a way to get value types (such as Point or integer)
into the object realm in some limited way. Otherwise you wouldn't be
able to put them in ArrayLists, for example.

Most of this will go away with V2.0, as I mentioned.

Nov 16 '05 #13

P: n/a
If I wanted to use a value as a reference type I would have to box it...
which would copy this value into the heap and give me a pointer to it (ooops
I said the p-word ;-) ) I meant a reference to it.
Now I expect, and if this is truly a reference type, that I should be able
to use it like I would any other object of type Object.. Right?
Not so, because before I can use it (to write to) I must unbox it back into
a value type which would make yet another copy of it for me to modify!! Hence
it’s not useful!! I should just create my own reference type or make a
wrapper around some of the .NET structures (Point) if I wanted to use them as
*reference types*.

Ed;;
"Ajay Kalra" wrote:
I am not sure what you mean by useful. Its something you must account
for when thinking about passing parameters. Since you are dealing with
the copy, any modification to the copy will not be reflected to the
original object. In addition, there are performance hits because of
copying.

Consider this:

Console.WriteLine("{0}", 5); // Console.WriteLine takes an object and
// parameter 5 (int, a value type) will
// need to be boxed

The above statement is really same as:

int i = 5;
object obj = i; // Box
Console.WriteLine(obj.ToString());

Inside WriteLine you will need to unbox it as:

object obj;
int i = (int) obj; // Unbox it
string str = i.ToString();

What it shows is the performance penalty of boxing/unboxing. When you
deal with Value types, you have to be careful about implicit
conversions to System.Object. If you can avoid it, Value types should
not be converted to System.Object(your OP was doing it).

In addition, you have to know why you are using Value types. Does your
type just have data? Does it define behavior? Do you expect it to be
polymorphic?

-------
Ajay Kalra
aj*******@yahoo.com

Nov 16 '05 #14

P: n/a
Or, as I said, come up with a design that doesn't require you to use
Points as though they were reference types. I submit that this is a
much better idea, because then your design will work in concert with
the .NET Framework, rather than trying to trump it, and other
programmers will more easily understand how to use your classes.

You are correct: boxing does not allow you to "do that" (make
"reference" versions of value types), but then it wasn't intended to
allow you to "do that". It was intended to allow value types to briefly
exist in an object environment, because it was one way to solve some
problems within the .NET Framework. Generics are another way (and the
preferred way) to solve many of those same problems, and will no doubt
largely replace boxing and unboxing.

All of this, however, doesn't help you solve your problem. As I see it
you have only two choices:

1. Change your design so that it uses Points, which are value types,
while still providing your callers with a convenient interface.

2. Re-implement those sections of the .NET framework (most notably
Point) so that you can use your original design.

IMHO, choice #2 is a really bad idea. That's just me, though. :)

Nov 16 '05 #15

P: n/a
> Not so, because before I can use it (to write to) I must unbox it
back

Thats actually not true. There is another technique that can be used to
change the content of the original value type of a boxed copy. The idea
is to have access to the original data. You can do it by having a value
type support an interface. Essentially you are giving access to the
value type thru an inteface. Keep in mind that boxing implements the
interfaces supported by value type. The interface itself will change
the data:

public interface IMyInterface
{
string SomeProperty
{
get;
set;
}
}

struct MyStruct : IMyInterface
{
private string property;

public string MyProperty
{
get { return this.property;}
set { this.property = value;}
}
}

When you do this, no copy is made of the Value type and boxing
implements the Interface IMyInterface. Now when you want to change the
property value, you go thru IMyInterface:

//In some function, where boxedObject is a boxed copy of above object

((IMyInterface) boxedObject).MyProperty = "NewValue";

Above will change MyProperty of original object. So there are ways to
do it. You just have to be careful in your selection about which type
to use.

----------
Ajay Kalra
aj*******@yahoo.com

Nov 16 '05 #16

P: n/a
Rather than me banging on about changing your design, here is some more
practical advice.

IMHO, the proper way to think about classes (reference types) versus
structs (value types) in .NET is to think of _identity_. Consider the
following:

A customer is certainly something that has an identity. It corresponds
to a real-world thing (a person or business), and if you were to store
it in a database you would give it a UID.

An integer, on the other hand, has no identity. It has a value. One can
talk about "that integer there" versus "this integer here" only in the
sense that some additional semantic meaning is attached to the integer,
at which point it stops being just an integer and becomes a value with
meaning. "My salary" for example. My salary _could_ have a UID because
it's mine, not someone else's. The number 100000 does not have an
identity.

A polygon probably does have an identity. You might want to refer to a
specific polygon, and I can imagine storing a polygon somewhere and
giving it a UID. Two squares with the same coordinates are not the same
square, although they are the same size and at the same position. A
Point, on the other hand, is just a value. (5,10) means nothing out of
context. As such, you should think of it the same way you think about
an integer.

When you say that you want to create a reference type to hold a point,
what you're really saying is, "I want this point here to have an
identity different from that point there." However, what does that
really mean out of context? I maintain that it's the context to which
you want to assign an identity, not the point value itself. You want to
be able to say, "The 12th point of that polygon." (where "that polygon"
implies identity and thus a reference type). A point has identity only
within the context of a polygon.

So, points are values. Given a polygon, you can manipulate its points.
However--and here's the bottom line--you can't simply grab a point from
a polygon and pass it about your system, _and have that point remember
it was from that polygon_, and by manipulating that stand-alone point
manipulate it within the context of its polygon. That's a weird concept
anyway, don't you think: "Hey, I have this point, that belongs to some
polygon somewhere, and I'm going to change it." You really can't do
anything with the point unless you know what polygon it's in. As such,
you offer operations on _polygons_ or _points within polygons_, not on
points all by themselves, out of context.

I think that Point-as-value-type plays beautifully with what you want
to do, and Point-as-reference-type makes for a strange logical
framework in which you can have points floating about with independent
identities separate from their polygons.

Or maybe I just don't understand well enough what you want to do. :-)

Nov 16 '05 #17

This discussion thread is closed

Replies have been disabled for this discussion.