How come value types are not true objects?

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

In C++, it is not uncommon to design a class to hold a pointer to another
object. For example:

class foo
{
Object * Obj;
void SetObj(Object * obj) { Obj = obj; }
Object * GetObj() { return Obj; }
};

The nice thing about this simple class is that once the pointer is set with
SetObj, it does not matter how, when, or where Obj is modified. Class foo
will be able to see the most recent updates to the object because it is not
using a copy, but rather a reference to the actual object that is being used
by other classes.

Under the .NET framework, classes or reference types also work the same way.
For example:

class foo
{
Object Obj;
void SetObj(Object obj) { Obj = obj; }
Object GetObj() { return Obj; }
}

This C# code is very similar to the C++ code above and works the same way as
the C++ code. However, consider the following code:

class foo
{
int Num;
void SetNum(int num) { Num = num; }
int GetObj() { return Num; }
}

The above code works quite a bit differently than the prior 2 examples. Num
is a native value type that is passed by value. So, a copy of the contents
of num is assigned to the class variable Num. If the integer passed to
SetNum is modified by another class outside of foo, then foo won't know about
it. Even if num were passed by reference, I don't believe there is any
legitimate safe mode C# syntax that will assign the pointer to the class
variable Num. So, it seems that reference types and value types have been
designed to operate quite differently in .NET. Why is that? I understand
that Java and other modern languages don't seem to have this problem.

As a developer, this is quite inconvenient. I am currently working on a C#
project where I have had to create classes like RefInt, RefDbl, and RefString
to simply hold the appropriate value type (with no other functionality) so
that my classes can be used without having to pass the value types each time
a method from my class is called. For example, here is some current code
from one of my projects:

public class RefInt
{
// This class exists as a work around to the fact that the .NET framework
does not allow
// native data types to be used as true objects, or for the address of a
native data type to
// be assigned like a regular reference type.

public int I; // The value to be used.

public override string ToString()
{
return I.ToString();
}
}

I am faced with the unhappy prospect of telling the users of my classes to
either always use the RefInt class variable directly in their code, or to
keep track of when they update their local variables that are being used with
my class and to move it into the RefInt variable before calling any of my
class methods.

The class that I'm writing encapsulates the functionality of a report file
with columns. The user of my class calls an add method to add columns. The
column data can be used with an int, double, or string and the add method
assigns the variable to be used to the class. So, the only options I see are
to either have the user always use one of my Ref wrapper classes (like
RefInt) in all their calculations, or tell them to move the local variable
into my wrapper class before calling my class methods. If anyone can suggest
some other way of doing it, I would love to hear it. But for right now,
these are the only 2 solutions that I see. Also, even if someone does think
of a better way to do this, the point about value types acting differently
than reference types is still of concern.

So, it seems to me that anytime the language forces you to do something
unpleasant like this, its bad for all concerned. Bad for my customers, bad
for me, and eventually its bad for Microsoft since other languages like Java
don't have this limitation. So, I am requesting Microsoft to remove this
limitation and make C# as well as all the other .NET languages truly object
oriented by making value types act like references.

How to do this with minimal impact? One way might be expand the native data
types such that for each value type a new reference-value type is added. The
reference-value type would have the same properties as a value type, except
that it would act as a reference and be allocated on the heap and subject to
garbage collection like other reference types. Value types would still work
the same way in this scenario. A way of assigning the address of a
reference-value type would have to be provided. The = operator should still
assign the contents of one variable to another in order to provide backward
compatibility. Perhaps := could be used to assign an address. Value types
could not have their address assigned and a reference-value could not be
assigned to anything other than another referernce-value variable of the same
type. This approach should be backwards compatible with all existing code.
Another simpler approach would be to simply create all variables on the heap
and thus subject them to garbage collection. If this were done, then there
would not be a need for a new set of reference-value variables. But, most
programs would run a little slower and the := assignment statement would
still be needed to assign the address.

I tried to submit this as a suggestion in the Microsoft MSDN product
feedback, but the system would not let me get past the search for
suggestions. So I a submitting this here. Could someone from Microsoft
please refer this suggestion to the appropriate team.

Thanks,

Bob Bryan
 
Answers inline
class foo
{
int Num;
void SetNum(int num) { Num = num; }
int GetObj() { return Num; }
}

The above code works quite a bit differently than the prior 2 examples. Num
is a native value type that is passed by value. So, a copy of the contents
of num is assigned to the class variable Num. If the integer passed to
SetNum is modified by another class outside of foo, then foo won't know about
it. Even if num were passed by reference, I don't believe there is any
legitimate safe mode C# syntax that will assign the pointer to the class
variable Num. So, it seems that reference types and value types have been
designed to operate quite differently in .NET. Why is that? I understand
that Java and other modern languages don't seem to have this problem.
Java work the same, it's even worse!
while it is legal in C# to write
object o = 42;
it's illegal in Java.
what other modern language were you speaking of?

As a developer, this is quite inconvenient. I am currently working on a C#
project where I have had to create classes like RefInt, RefDbl, and RefString
to simply hold the appropriate value type (with no other functionality) so
that my classes can be used without having to pass the value types each time
a method from my class is called. For example, here is some current code
from one of my projects:

public class RefInt
{
// This class exists as a work around to the fact that the .NET framework
does not allow
// native data types to be used as true objects, or for the address of a
native data type to
// be assigned like a regular reference type.

public int I; // The value to be used.

public override string ToString()
{
return I.ToString();
}
}
I can't quite see what's the purpose of your class, anyway, with 2.0 you could solve that easily

class Ref<T> where T: struct
{
public T Value;
public override string ToString() { return Value .ToString(); }
}
I am faced with the unhappy prospect of telling the users of my classes to
either always use the RefInt class variable directly in their code, or to
keep track of when they update their local variables that are being used with
my class and to move it into the RefInt variable before calling any of my
class methods.
I'm not sure to understand your problem but I will hazard that event is what you need to solve it.
The class that I'm writing encapsulates the functionality of a report file
with columns. The user of my class calls an add method to add columns. The
column data can be used with an int, double, or string and the add method
assigns the variable to be used to the class. So, the only options I see are
to either have the user always use one of my Ref wrapper classes (like
RefInt) in all their calculations, or tell them to move the local variable
into my wrapper class before calling my class methods. If anyone can suggest
some other way of doing it, I would love to hear it. But for right now,
these are the only 2 solutions that I see. Also, even if someone does think
of a better way to do this, the point about value types acting differently
than reference types is still of concern.

what about the user keeping a reference to the column and call the column's method
aColumn.SetData(aData);
to update the value?
So, it seems to me that anytime the language forces you to do something
unpleasant like this, its bad for all concerned. Bad for my customers, bad
for me, and eventually its bad for Microsoft since other languages like Java
don't have this limitation.
I would hazard your class suffer from irrealistic expectation.
Many library work around this kind problem without having to change the whole language.
So, I am requesting Microsoft to remove this
limitation and make C# as well as all the other .NET languages truly object
oriented by making value types act like references.
no less!! ;-)

Anyway pointer are banned from C# (in most case) as they prevent garbage collection.
So it's the end of your suggestion, I believe...
 
You're trying to fit a round peg into a square hole. There's a reason why
they're called "reference types" and "value types". It's not a design
mistake or oversight, it's how the thing is supposed to work.

If you want to pass a pointer to a primitive type between 16 different class
instances (or even worse, expose value pointers directly from class member
variables as in your example), that's fine. Use C++. If you want to do it in
C#, wrap the value type in a reference type or simply box it. The
"inconvenience" of having to do this is one of the tradeoffs of using a
managed, GC'ed language like C#.

Pointers are probably the number one reason people write unstable, insecure
code in low-level languages. One of the framework's primary objectives is to
solve those problems, but you have to live within the confines of the
sandbox.
 
Klaus H. Probst said:
You're trying to fit a round peg into a square hole. There's a reason why
they're called "reference types" and "value types". It's not a design
mistake or oversight, it's how the thing is supposed to work.

And I'm saying that it would work better if value reference types could be
added to the language... If you can't see that then perhaps you need to
think more about the example I gave. Again - why should value types be
treated any differently than reference types from an OO point of view. Why
should the developer be forced to kluge his way around a problem that should
not exist in the first place? It may have been designed this way, but its
not a good design. Sue me for saying that the emperor is not wearing clothes
if you want... Try asking 10 OO experts (not associated with Microsoft)
about this and listen to what they tell you.
If you want to pass a pointer to a primitive type between 16 different class
instances (or even worse, expose value pointers directly from class member
variables as in your example), that's fine. Use C++. If you want to do it in
C#, wrap the value type in a reference type or simply box it. The
"inconvenience" of having to do this is one of the tradeoffs of using a
managed, GC'ed language like C#.

Again, in my code - I do wrap the value type in a class simply so that it
can be treated as an object. Do you really think this is the way a modern OO
language should work?
Pointers are probably the number one reason people write unstable, insecure
code in low-level languages. One of the framework's primary objectives is to
solve those problems, but you have to live within the confines of the
sandbox.

I agree that pointers can lead to severe bugs. The .NET framework is a
great advance over the previous version of Visual Studio 6. Working within
the confines of the framework is a given. Then again, are you saying that
suggestions for improvements to the framework is a bad idea?

You really don't see how the introduction of reference-value types would
help solve having to kluge a class as a workaround simply because there is no
other way to get a value type to act as a reference type? Are you aware of
the impact that will have on users of my class? Right now, they have to
either use my wrapper class for all calculations, or they have to move the
value type to my wrapper class each time it gets updated. This is much more
painful than you seem to be giving credit for...

Again, Java does not seem to have this problem.

Bob Bryan
 
Again, Java does not seem to have this problem.
Again .. why again?
Particularly when this statment is PLAIN wrong!
How come you keeps repeating a false statment as a proof of you're right?

I would be curious to see your working java code?

For your information int, double, float, all simple type behave exactly the
same in Java & C#.
In C# the concpet is just extended to struct (like Point, Rectangle,
etc....)
 
Lloyd Dupont said:
Again .. why again?
Particularly when this statment is PLAIN wrong!
How come you keeps repeating a false statment as a proof of you're right?

I would be curious to see your working java code?

For your information int, double, float, all simple type behave exactly the
same in Java & C#.
In C# the concpet is just extended to struct (like Point, Rectangle,
etc....)
For each native data type, Java has a class that can be used as a reference.
For example, look up the difference between int and Integer, or float and
Float. Java at least provides a wrapper for each value type so that it can
be used as an object.

I've never programmed in Java before, just repeating what others that have
worked with Java have told me. I'm sure Java has its own set of unique
problems and I'm not about to switch to it over this issue. The point is not
really what one language can do over another. Its about making the .NET
family languages the best they can be.

I have yet to hear any arguments as to why a reference-value type could not
be added to .NET for each current value type. Or, why this was not done in
the first place. You don't see the value of being able to treat value types
as references? Pretend for a minute that you are using my class. Which
would you rather do:

1. Use a native data type like an int and call an AddColumn function that
takes this value as a reference. You never have to worry about calling
another function to move the current value over to my class. This behavior
would work exactly the same way as other .NET reference objects by the way.
You would then be free to use an int in your code and would not have to deal
with the complexity of any wrapper classes.

2. Use a wrapper class that contains an int and has no other functionality.
You would then have to use syntax like the following every time the value
changes:

RefInt RHighPrice; // Defined once.
int HighPrice; // Defined once

RHighPrice.SetValue(HighPrice); // Called multiple times.

The wrapper class is a workaround to a problem. I'm simply asking for the
problem to be fixed. Imagine that there are 20 columns to this report.
Thats an extra 20 lines of code that the user would have to supply in order
to work with my class. What if they have 20 reports? That's 20 * 20 = 400
lines of extra code. And, what happens if he needs to do this in multiple
spots? Can you see why this is a problem now? Why should it have to be more
work to use a value type than a reference type?

I know how value types work. I don't know the reasons why it works this
way. Someone from Microsoft will have to explain it to me.

Bob Bryan
 
For each native data type, Java has a class that can be used as a reference.
For example, look up the difference between int and Integer, or float and
Float. Java at least provides a wrapper for each value type so that it can
be used as an object.
oh you mean these one? C# could do the same without the need to declare them.
example:
in C# you could write:
object o = 4;

you cannot in Java and you have to write
object o = new Integer(4);

but nothing prevent you from duplicating the Integer class in .NET.
and you will need to because Java's Integer are immutable (as String in both languages), so you can hold a reference to it, but you CAN'T modify its value.
I have yet to hear any arguments as to why a reference-value type could not
be added to .NET for each current value type.
As a matter of fact with 2.0 you could do that for all value type with one definition
class Ref<T> where T: struct
{
public Ref() {}
public Ref(T t) { Value = t; }

T Value;
}
Or, why this was not done in
the first place.
not really needed, again, int is also an object!
object o = 4;
1. Use a native data type like an int and call an AddColumn function that
takes this value as a reference. You never have to worry about calling
another function to move the current value over to my class. This behavior
would work exactly the same way as other .NET reference objects by the way.
You would then be free to use an int in your code and would not have to deal
with the complexity of any wrapper classes.
I see what you mean. For that there is 2 solution:
- you could use the suggested template above.
- you could do the opposite, hold a reference to the colunm, and modify its data
And common, none of these is overkill!!

What about the following : if you don't like value type : just don't use them!

Anyway I found this pattern dangerous. The value could change but no one will know!
Better to have event to notify interested person, as in the another generic exemple below
class Ref<T>
{
public Ref() {}
public Ref(T t) { val = t; }

T val;
T Value
{
get { return val; }
set
{
if(val == value)
return;

val = value;
if(ValueChanged != null)
ValueChanged(this, EventArgs.Empty);
}
}
public event EventHandler ValueChanged;
}

2. Use a wrapper class that contains an int and has no other functionality.
You would then have to use syntax like the following every time the value
changes:

RefInt RHighPrice; // Defined once.
int HighPrice; // Defined once

RHighPrice.SetValue(HighPrice); // Called multiple times.
1st, why so convoluted?
Ref<int> ri = new Ref<int>(SomeValue); // when 1st needed
ri.Value = SomeOtherValue; // called multiple time

it's as verbose as an int, don't you think?


2nd:
after reading you again and again I start to believe you are completely new to C# and need some time to be used to it.


3rd:
Anyway I would hardly use such pattern.
Anyway let's imagine one day I want to.
I won't make such an issue of it and just create my utility class.
After all this is a very marginal pattern.


The wrapper class is a workaround to a problem. I'm simply asking for the
problem to be fixed. Imagine that there are 20 columns to this report.
Thats an extra 20 lines of code that the user would have to supply in order
to work with my class. What if they have 20 reports? That's 20 * 20 = 400
lines of extra code. And, what happens if he needs to do this in multiple
spots? Can you see why this is a problem now? Why should it have to be more
work to use a value type than a reference type?

Something is plain wrong here..
It seems like you want something something to happen when the user change (multiple times) your value. (otherwise why care that much).
But, in your model, nothing will ever happend because no-one is ever notified!
do you see a problem now?

better hold a reference to the column and do something, like that
class Column
{
public Column(object data)
{
}
object data;
public object Data
{
get { return data; }
set
{
if(data == value)
return;

data = value;
// do someting, now?
}
}
}
Column c = new Column(4);
c.Data = 24; // the value change AND something happen
c.Data = "Today is a beautifull day"; // the value change AND something happen
c.Data = new DateTime(); // the value change AND something happen

I know how value types work. I don't know the reasons why it works this
way. Someone from Microsoft will have to explain it to me.
I explain you:
- Value type are much faster.
- Just create an Integer class and try to write a for loop with them, compare the perfomance....
- int are stored in register, etc...
- they don't need reference counting, they are (most of the time) pass by copy.
- using value type is a way to speed up your code a little bit.
- they are also never null (sometimes usefull)
- in short they are light weight object wrapper around memory zone

C# is almost a "system language" (cf http://channel9.msdn.com/ShowPost.aspx?PostID=68302), so it's why there are structs.

Anyway it's time to go to bed for me.
I suggest (kindly, hey! :-) you learn C# before commenting on its future ;-)
 
Bob,

Java has exactly the same distinction between value types and reference
types. While it's possible to have 'pure' OO languages where there is no
distinction, the industry seems to have decided that performance and other
issues make that approach unsuitable for a general purpose language.

Yes, Java has wrapper classes. They are necessary to solve certain cases
that C# handles by other means:

- returning value via method arguments - C# can pass parameters by reference
- converting values to and from object typ - C# provides boxing

So any use for the wrappers would be only be for the type of approach you
want to adopt - and generally most people don't seem to want to do that.
I've never seen anyone need to create a wrapper class. However you can if
you want to. Note. however, with the value type/reference type distinction,
you always have to create an object instance and assign the value to it,
which seems to be part of your complaint.

As for C++, yes you can freely create pointers to value types. However
there is no safety in this - if you use a pointer to a value type that was
allocated on the stack after the stack frame has gone, you will get a very
nasty bug, as anyone who has used C++ extensively will know to their cost.
Both C# and Java take the same view of removing this kind of dangerous
feature in the language. That's the clear design goal, and I doubt it will
change.

To be honest, it sounds like you are used to using a hammer, have been
handed a screwdriver, and are wondering why it's not very good for hitting
things with. Have another look at your design - there's probably an approach
which is more sympathetic to the language, and may well be a better design.

Or take look at the ADO.NET classes for some ideas. I'm not completely clear
from your description exactly what you are trying to do, but ADO.NET tends
to use and an object array to pass rows of data around. Boxing will allow
the assignment of various data types to the elements. And an array is a
reference type, so you can hang on to a reference to that, if you want to do
it that way.
 
Pointers are probably the number one reason people write unstable,
insecure
code in low-level languages.

Pointers are just one aspect of it. Once you know what you're doing though,
pointer mistakes are extremely rare. The real problem is achieving a state
where you "know what you're doing". Most programmers never do, and pointers
are just the tip of the iceberg.
 
I'm not going to start a flame war over this. I simply won't dignify any
response that suggests that I'm new to the language, don't know what I'm
doing, fitting a square peg in a round hole etc...

The issue I've described here is also not new. Others in the newsgroups
have also complained about this as well. Try doing a search...

Believe it or not, most psychologogists believe that when you put down
someone else, you are subconsciously talking about your own limitations.

Bob Bryan
 
It may have been designed this way, but its
not a good design. Sue me for saying that the emperor is not wearing clothes
if you want...

If you want Java, why not use Java?
Try asking 10 OO experts (not associated with Microsoft)
about this and listen to what they tell you.

Thanks, I've had enough years of exposure to OO. And not only in association
with Microsoft.

You keep saying "Java does not have this problem". That's because in Java an
integer is a reference type, allocated on the heap. That's incredibly
wasteful. You have the opinion that C# is badly design because of that - I'd
tend to ask what the heck Gosling was smoking when he decided to promote a
DWORD to the equivalent a heap-allocated struct with a vtable. The people
who designed C# wanted to get away from that and give a set of fast,
lightweight native types. If you find them lacking, then do what you were
doing to begin with - wrap them. After all, it's not like you're going to
take a perf hit from that *over Java* - you'll be writing Java code in C#.
More power to you. No one is stopping you from doing that. Or use Ruby. Use
Python or Perl. Use OCAML, Squeak, Malbolge, SmallTalk, LISP, etc.
Then again, are you saying that
suggestions for improvements to the framework is a bad idea?

No, you can suggest all you want. I'm just telling you *your suggestion* is
a bad idea, in my opinion. We can agree to disagree - and you can always
just use Java or some other "real" OO language that forces you to allocate x
bytes on the heap (along with the GC overhead) whenever you want to add 1+1.
It's not like you don't have choices.
 
Bob,

I presume you post is in response to mine.

If I've given offence, I'm sorry. No offence was intended. However I stand
by what I said - I don't think it was an unreasonable response to the words
you wrote.

Nigel Norris
 
Klaus H. Probst said:
You keep saying "Java does not have this problem". That's because in Java
an
integer is a reference type, allocated on the heap.

Nope - Java has the same model as C#. In the Java they are referred to as
'primitive types', and are not treated as reference types, just like C#. In
Java if you want to have reference to an int, you have to instantiate a
wrapper object yourself. C# does it auotomatically with boxing.
 
On 7/8/05 10:30 am, in article (e-mail address removed), "Lloyd

Java work the same, it's even worse!
while it is legal in C# to write
object o = 42;
it's illegal in Java.
what other modern language were you speaking of?

Just one slight correction - while Java does indeed work the same, the above
*does* work in Java (having changed object to Object) - as of Java 1.5/5.0.
It didn't before then.
 
Java work the same, it's even worse!
Just one slight correction - while Java does indeed work the same, the
above
*does* work in Java (having changed object to Object) - as of Java
1.5/5.0.
It didn't before then.
wouah, cool!
thanks John!

PS: Anyway I think it's too late for me, I've been infected by the .NET
bug.... May I R.I.P., uh Program I.P.
 
Back
Top