References to value types...
Ian wrote a comment about being about to return references to value types.
Basically, he's asking for a way to build a collection of value types so that they can easily be modified, and to do this, he'd like the indexer to be able to return a reference rather than a value.
This restriction shows up from time to time, usually when somebody wants to write code like (example from Ian):
List<MyStruct> vec = new List<MyStruct>();
vec.Add(new MyStruct(10, 20));
vec[0].X += 1; // Error!
Because
vec[0]
gets a copy of the value stored at vec[0] and puts it in a temporary local, being able to modify the X property on that temporary copy is a useless thing to do, so the language prohibits it.
So why won't C# let you get the reference to a value? Well, it's all because of the presence of the garbage collector. If you had a reference (aka internal pointer) somewhere into the middle of an array, any movement of the array as part of a GC would mean that the reference would be invalid.
It might be possible to add a construct to a system that would say "this is an internal pointer, and if you move the outer object, you need to update the inner pointer as well, but that would mean that the reference to the value would not be a simple pointer, but a reference to another object which encapsulated the inner pointer (so the GC could find it), which pretty much defeats the purpose of being able to do this.
In C++, the programmer owns the memory, and gets to choose how things get created, deleted, and moved around. In C#, the GC owns the memory, and the programmer just gets to borrow it for a short period of time. Working in the C# world requires a different mindset, and until you internalize it, things are likely to seem a bit weird.
The meta message is around using structs in C#. In a word, don't use structs unless you're forced to use them - and by forced I mean that you need to do interop, or you've looked at your profiling data and realized that you really need to reduce the number of objects that you have around. In other words, they shouldn't be the default choice - there are a lot of disadvantages and gotchas with structs, though a few of those will go away when Whidbey shows up.
And if you do use structs, see if you can make them immutable. That hides most of the ugly cases.
Hope that makes sense
Comments
Anonymous
February 11, 2005
I always make my structs immutable. Once you start thinking of structs as immutable objects (which is very consistent with the very notion of a value type), it makes everything easier.
Is it useful to mention the solution of the above problem?
List<MyStruct> vec = new List<MyStruct>();
vec.Add(new MyStruct(10, 20));
vec[0] = new MyStruct(vec[0].X + 1, vec[0].Y);Anonymous
February 11, 2005
Making structs immutable can make them even more ugly. If you only have two pieces of data, it is not two bad. But once you have to copy several properties into the constructor, to change one, it is not so good.
Also, making structs immutable is pointless if you are using structs for performance reasons. Usually we need to use an array of structs, and need the ability to change one property in each struct in the array. If you have to create a new one and copy it in, instead of changing in memory, you have wasted cycles that will not be picked up by the primitive optimizer.Anonymous
February 11, 2005
So how does C# get around this problem with a regular array? Is it simply because the array is allocated on the stack? If so, could one create a struct that's a custom collection and not a reference object?Anonymous
February 11, 2005
So how does the .NET Garbage collector get around this problem with a regular array?
Is it simply because the array is also allocated on the stack rather than the heap?
If so, could one create a struct that's a custom collection and not a reference object?Anonymous
February 11, 2005
Heh - I was just about to post the same question as Philip Haack...
But I'd like to add to what he says. Regular arrays are not created on the stack. They're objects on the managed heap. (Otherwise you wouldn't be able to return arrays from functions, or store references to them in fields.)
So given that the IL opcode you use to retrieve an element from a value type array:
ldelema
returns an pointer to the element you asked for, surely that would be an interior pointer?
So apparently the CLR already supports the use of managed interior pointers into arrays because that's how arrays work.
What's special about arrays that lets this work?
Moreover, isn't this what interior pointers are all about:
http://www.voidnish.com/articles/ShowArticle.aspx?code=interiorpointers
My understanding is that interior pointers are what C++/CLI uses to solve exactly this problem. So why don't we have interior pointer support in C#?Anonymous
February 12, 2005
[http://www.google456.com google排名]
[http://www.blgang.net/ 玻璃钢]
[http://www.huojiawang.com 货架]
[http://www.google456.com/blg/ 玻璃钢]
[http://mhblg.51.net/ 玻璃钢]
[http://www.google456.com/huojia/ 货架]
[http://www.hxairlines.com/fjp.htm 飞机票]
[http://www.vbzx.net vb]Anonymous
February 13, 2005
structs would be very useful if the "Dispose" method was called automatically at block exit. In this way we could easily implement deterministic finalization, without the "using" keyword.Anonymous
February 13, 2005
When we allocate an array of structs there is no managed pointers to those structs.
if we had managed pointers to a struct in an array it would invalidate the main purpose of that scheisse - ability to allocate a big chunk of memory at once
otherwise GC would move tham as it wants
so just use classes if you need lvalueAnonymous
February 14, 2005
The comment has been removedAnonymous
February 14, 2005
Since interior pointers already exist (or will for 2.0, if they don't already) I don't understand the problem. It's a long-standing crapness of C# that it can't do this.Anonymous
February 14, 2005
The comment has been removedAnonymous
February 14, 2005
The comment has been removedAnonymous
February 15, 2005
To me, structs look more and more like a bad idea. Wouldn't C# be a better language without them? Then we would not have these funny restrictions.
I can't see where structs supports the 'simplicity' model. Some other things are not simple anymore. Or is there a difference between 'obvious' and 'simple'?Anonymous
February 17, 2005
Thomas Eyde:
You need the 'struct' type to do P/Invoke.Anonymous
February 17, 2005
Not to mention that without structs DateTime and Decimal would be a LOT more heavyweight than they need to be.
If all structs that weren't internal and used only for P/Invoke were correctly made immutable, then you wouldn't notice any difference when using them.
That's why Decimal feels like int...because it's immutable. Once you make it mutable you have to worry about references to structs.
(Oh, and structs such as List<T>.Enumerator are fine too...even they aren't really immutable--but few people even touch the enumerator directly).Anonymous
February 18, 2005
No structs? Please don't even think about it. Regardsless of how fast the GC becomes, stack and register based data is faster, simply because it cannot be aliased (modified in multiple places simultaneously). This means optimizers, perhaps even more in the future, can make temporary structs really fly.
Without structs you can forget about fast math or graphics libraries.Anonymous
February 21, 2005
Seeing as it's possible to return a managed pointer in IL and MC++, I see no point in not extending the use of the ref keyword to support this in C# also.
public static ref int First(int[] array)
{ return ref array[0]; }
static void Main(string[] args)
{
int[] array = new int[] { 0, 1, 2 };
ref int val = First(array);
val = 10;
Console.WriteLine(array[0] == 10);
}Anonymous
February 23, 2005
The comment has been removedAnonymous
February 24, 2005
Can somebody help this newbie understand the difference between a mutable and immutable struct, by way of a concrete example in C#?
Thanks.Anonymous
February 24, 2005
Not a problem as this is already caught by the compiler. Try this little one out:
public EventHandler F(ref int someInt)
{
EventHandler dlg = delegate
{
someInt = 20;
};
return dlg;
}
The compiler already handles managed pointers at the local scope and in fact needs to. In the above function I'm declaring that I have a managed pointer in the parameters. This is a local variable that is explicitly a managed pointer.
I'm not allowed to do the same thing myself unless it's a parameter, which is an arbitrary constraint. Notice that the only difference between what we have now and what I propose is that I can declare a ref in scope to receive a managed pointer.
I do not believe that references to local variables should be allowed, as the following is just a waste. We could have just used numberOne anywhere we plan on using numberTwo.
int numberOne = 300;
ref int numberTwo = ref numberOne;
numberTwo 2 = 400; // now numberOne == 400
I believe that the ref keyword, should be used only for receiving "ref returns", or receiving references to heap members. Example:
ref MyBigDataBlock data = largeBlockCache.GetBlock(12);
// etc..
MyBigStruct[] myArray = new MyBigStruct[30];
for(int i = 0; i < myArray.Length; i++)
{
// need ref in front of myArray[i] just as if we we're passing it to function
// that had a ref parameter.
ref MyBigStruct temp = ref myArray[i];
temp.SomeInitializer();
temp.SomeFloat = 2316738.3225;
// etc..
}
Just like ref parameters though a ref declared locally can only be assigned at creation, which means it's impossible to assigning it to a new managed pointer. Example:
string[] names = new string[10];
ref string firstName = ref names[0];
firstName = "Bob" // names[0] is now "Bob"
firstName = ref names[1] // error wrong type, cannot convert string reference to string
Not that I advocate having everything in C++/CLI be in C# but, I would at least like a way to access the values returned as managed pointers, especially since it can be verified CLR. Anytime I can switch somethings from C++/CLI to C# and still not need the UnmanagedCode security, I'm a happy man.
Just to be clear, I'm dead set on this not being a CLS compliant
feature.Anonymous
February 24, 2005
Imutable struct:
struct SquareInt
{
private int _sqValue;
public SquareInt(int value) { _sqValue = value * value; }
public int Value { get { return _sqValue; } }
}
Notice that SquareInt can only be assigned a value at creation. Even though _sqValue isn't readonly.
That's imutable, means if you what another one with a different value, you best create a new one.
Strings, on the other hand, are not structs but, are still imutable because you cannot change it's value. You can say:
string word = "dog";
word[2] = 't';
Doesn't work, cause theres noway to change it once it's been created.Anonymous
February 27, 2005
The comment has been removedAnonymous
May 30, 2009
PingBack from http://outdoorceilingfansite.info/story.php?id=20789Anonymous
June 15, 2009
PingBack from http://einternetmarketingtools.info/story.php?id=22249