I have two similar structs in C#, each one holds an integer, but the latter has get/set accessors implemented.
Why do I have to initialize the Y struct with new operator prior to assigning the a field? Is y still a value type when I init it with new?
public struct X
{
public int a;
}
public struct Y
{
public int a { get; set; }
}
class Program
{
static void Main(string[] args)
{
X x;
x.a = 1;
Y y;
y.a = 2; // << compile error "unused local variable" here
Y y2 = new Y();
y2.a = 3;
}
}
The reason one is valid while the other is not is that you cannot call methods on uninitialised objects. Property setters are methods too.
public struct X
{
public int a;
public void setA(int value)
{ this.a = value; }
}
public struct Y
{
public int a { get; set; }
}
class Program
{
static void Main(string[] args)
{
X x;
x.setA(1); // A: error
x.a = 2; // B: okay
Y y;
y.a = 3; // C: equivalent to A
}
}
The reason that is not allowed is that the property setter could observe the uninitialised state of the object. The caller does not know whether the property setter merely sets a field, or does more than that.
In first case you just assigning field. It doesn't involve actual using of structure, just setting value into memory (struct address + field offset on stack).
In second case you calling method set_a(int value), but fail because variable is uninitialized.
In third case constructor initializes it for you, so using variable is ok.
Update: Here comes the specification!
"12.3 Definite assignment" (page 122 of ecma-334).
A struct-type variable is considered definitely assigned if each of its instance variables is considered definitely assigned
This is covered in the C# specification section 5.3 dealing with "Definite Assignment":
a struct-type variable is considered definitely assigned if each of its instance variables is considered definitely assigned.
and:
An initially unassigned variable (Section 5.3.2) is considered definitely assigned at a given location if all possible execution paths leading to that location contain at least one of the following:
* A simple assignment (Section 7.13.1) in which the variable is the left operand.
* ...
As such, this also works:
void Main()
{
X x;
x.a = 1;
x.b = 2;
x.Dump();
}
public struct X
{
public int a;
public int b;
}
You can test this in LINQPad.
Note that there is no way for the compiler to prove that the struct-type variable is considered definitely assigned if you call code on it, and that's what you're doing with a property. As such, before you can use a property on the struct-type variable, it has to be definitely assigned.
The new operator for value types runs the specified constructor. Unlike with reference types, this is optional, so if you don't use new, the default constructor is implicitly run (you cannot specify your own default constructor, so it always has the effect of giving the default value to the fields for their types).
As for why the compiler error, I'm not really sure. Interestingly, in the C# Interactive window,
public struct Y
{
public int a { get; set; }
}
Y test;
test.a = 5;
works just fine.
Related
I'm trying to learn operators overloading and i found code like this:
public static ComplexNumber operator -(ComplexNumber x) {
ComplexNumber y;
y.re = -x.re;
y.im = -x.im;
return y;
}
and I wonder why we do not initialize the y like this: ComplexNumber y = new ComplexNumber().
As I said in the comments: it's probably (virtually certainly) a struct.
See for example this snippet:
When you create a struct object using the New operator, it gets created and the appropriate constructor is called. Unlike classes, structs can be instantiated without using the New operator. If you do not use New, the fields will remain unassigned and the object cannot be used until all the fields are initialized.
You can test this for yourself easily:
void Main()
{
X x;
x.blabla = 5;
Console.WriteLine (x.blabla);
}
public struct X {
public int blabla;
}
The following code is illegal:
public struct MyStruct
{
public MyStruct(int a, int b)
{
this.a = a;
this.b = b;
}
public int a;
public int b;
}
//now I want to cache for whatever reason the default value of MyStruct
MyStruct defaultValue;
...
if (foo != defaultValue) //use of unassigned variable...
The way things should be done is obviously:
MyStruct defaultValue = default(MyStruct) //or new MyStruct();
...
if (foo != defaultValue) //compiler is happy
But the following is also allowed (I didn't know this and stumbled upon it by accident):
MyStruct defaultValue;
defaultValue.a = 0;
defaultValue.b = 0;
...
if (foo != defaultValue) //legal
I guess the compiler verifies that all fields of the struct have been initialized and therefore allows this code to compile. Still I find it confusing with how the rest of the language works. After all, you are basically using an unassigned variable in the C# way of seeing things.
Things get even more confusing if you consider the following code:
public struct MyStruct
{
public MyStruct(int a, int b)
{
this.a = a;
this.b = b;
this.c = (a + b).ToString();
}
public int a;
public int b;
internal string c;
}
The following code is illegal becuase in this case we haven't assigned all visible fields:
MyStruct defaultValue;
defaultValue.a = 0;
defaultValue.b = 0;
...
if (foo != defaultValue) //use of unassigned variable...
Visible is the key word here, because if MyStruct were to be defined in a referenced assembly then c is not visible and the compiler will not complain and the previous code would be perfectly valid. Confusing again.
Can somebdoy please explain why its allowed to initialize a struct in C# in such manner? Why not disallow it completely so there is a more unified experience when dealing with any type of value in the language?
EDIT 1: I made a mistake in the last example. The compiler will be happy only if the not visible field is of reference type. Even more confusing. Is this last case a known bug in the compiler or is there a sane reason for it to work the way it does?
Changed last example to a valid case.
EDIT 2: I'm still a litte befuddled with how value-type initialization works. Why isn't the following allowed for instance:
struct MyStruct
{
public int A { get; set; } //Auto-implemented property
public int B { get; set; } //Auto-implemented property
}
MyStruct defaultValue;
defaultValue.A = 0; //use of unassigned variable...
defaultValue.B = 0;
The way I see it, there is little doubt that all fields MyStruct are initialized. I can see the reasoning of why this wouldn't be allowed if properties were not auto-implemented as it is arguably possible that the setters do not garantee that all fields are set. But in auto-implemented properties the compiler knows with 100% certainty that the fields will be set if the properties are (after all its code that the compiler generates for you).
Finally, a small theoretical case with evidently no practical use:
struct MyUselessStruct
{
}
MyUselessStruct defaultValue;
Console.WriteLine(defaultValue.ToString()); //hehe did I get away with using an unassigned variable?
Then why isn't this allowed:
Object object;
if (object == null) .... //use of unassigned variable
I find both cases similar in concept and I'd expect them both to work the same way in C#. I still don't understand why this seemingly useless differentiation in the way value-type variables can be initialized and what is it's practical use (on top of the inconsistencies I explained in the first part of my question)
The spec explicitly allows this; 12.3 in ECMA334v4
A struct-type variable is considered definitely assigned if each of its instance variables is considered definitely assigned.
However, mutable structs are evil. So I strongly suggest you DO NOT do this.
Make the fields private readonly, set them via a custom constructor, and access them via a get-only property:
public struct MyStruct
{
public MyStruct(int a, int b)
{
this.a = a;
this.b = b;
}
public int A { get { return a; } }
public int B { get { return b; } }
private readonly int a, b;
internal int C { get { return a + b; } }
}
Consider the Foo struct as follows:
struct Foo
{
public float X;
public float Y;
public Foo(float x, float y)
{
this.X = x;
this.Y = y;
}
public void Change(float x)
{
this.X = x;
}
}
I understand modifying the field in the constructor, that's perfectly logical to me and my understanding of structs as value, number-like immutable types.
However, since one can't do:
Foo bar = new Foo(1, 2);
bar.X = 5;
Why can one use:
Foo bar = new Foo(1, 2);
bar.Change(5);
EDIT: If structs are mutable, then why can't they be modified when in a list or returned from a property?
Cannot modify expression because it is not a variable
Since one cannot do
Foo bar = new Foo(1, 2);
bar.X = 5;
Why can one use:
Foo bar = new Foo(1, 2);
bar.Change(5);
Your original question actually cannot be answered because it is predicated on a completely false assumption. Both code samples are perfectly legal, and so the question about why one is illegal is nonsensical. Let's move on to your follow-up question:
If structs are mutable, then why can't they be modified when in a list or returned from a property?
Because variables are mutable and values are immutable.
That's why they're called "variables", after all, because they can change.
When you say "bar.X = 5", "bar" is a local variable. Variables are allowed to change.
When you say "bar.Change(5)", "bar" is a local variable. Variables are allowed to change.
When you say "myArray[123].X = 5", "myArray[123]" is an array element and an array element is a variable. Variables are allowed to change.
When you say "myDictionary[123].X = 5", "myDictionary[123]" is not a variable. The value is returned from the dictionary, not a reference to the storage location. Since that is a value, not a variable, there is nothing there that can change, so the compiler does not allow it to change.
A subtle point is that when you attempt to change a field, the receiver must be a variable. If it is not a variable, it makes no sense; you are clearly attempting to mutate a variable and there's nothing there to mutate. When you call a method, the receiver must be a variable but what if you have a value? The method might not attempt to mutate anything, and so should be allowed to succeed. What the compiler actually does if the receiver of a method call on a struct is not a variable, then it makes a new temporary local variable and calls the method with that variable. So if you say: "myDictionary[123].Change(5);" that is the same as saying
var temp = myDictionary[123];
temp.Change(5);
Here "temp" is a variable, and the mutating method is allowed to change the temporary copy.
Is that now clear? The key takeaway here is variables can change.
You've made a key mistaken assumption.
.NET structs are mutable. You can absolutely perform bar.X = 5;.
You should design structs to be immutable, but by the code you have provided, they are mutable.
Have a look at this question for a description of where mutable structs can get your into trouble.
Immutability of structs
In common, all C# structs are not immutable, even readonly ones. So you can't design your structs as immutable at all.
All structs are mutable, just like in C++ :)
Immutability means that data structures ate immutable at language level, that is not true for C#.
I will show you how to break immutability rule using legal C# syntax, please note that NotReallyImmutableFoo.X is declared as a readonly field.
Cheers ;)
namespace test
{
public unsafe struct MutableFoo
{
public int Id;
public float X;
public MutableFoo(int id, float x) { Id = id; X = x; }
public void Change(float x)
{
unsafe
{
fixed (MutableFoo* self = &(this))
{
MutabilityHelper.Rewrite(self, x);
}
}
}
}
public struct NotReallyImmutableFoo
{
public long Id;
public readonly float X;
public NotReallyImmutableFoo(long id, float x) { Id = id; X = x; }
public void Change(float x)
{
unsafe
{
fixed (NotReallyImmutableFoo* self = &(this))
{
MutabilityHelper.Rewrite(self, x);
}
}
}
}
// this calls breaks up the immutability rule, because we are modifying structures itself
public static class MutabilityHelper
{
struct MutableFooPrototype
{
int Id;
float X;
public void Rewrite(float value)
{
X = value;
}
}
struct NotReallyImmutableFooPrototype
{
long Id;
float X;
public void Rewrite(float value)
{
X = value;
}
}
public static unsafe void Rewrite(NotReallyImmutableFoo* obj, float value)
{
NotReallyImmutableFooPrototype* p_obj = (NotReallyImmutableFooPrototype*)(*(&obj));
p_obj->Rewrite(value);
}
public static unsafe void Rewrite(MutableFoo* obj, float value)
{
MutableFooPrototype* p_obj = (MutableFooPrototype*)(*(&obj));
p_obj->Rewrite(value);
}
}
class Program
{
static void Main(string[] args)
{
MutableFoo foo = new MutableFoo(0, 2);
foo.X = 3; // X is writeable
foo.Change(5); // write X using pointer prototyping
NotReallyImmutableFoo nrifoo = new NotReallyImmutableFoo(0, 2);
// error CS0191
//nrifoo.X = 3; // X is not writeable
nrifoo.Change(3); // anyway, write X using pointer prototyping
}
}
}
Structures in .net combine piecewise mutability with shallow-copy-on-assignment semantics as well as the ability to pass by value-assignment or by reference. There is no convention in .net, however, by which classes would be expected to expose properties by reference, nor do any .net language compilers provide a convenient means of doing so. It would be possible for a language to provide such a feature, with certain limitations, by recognizing that something like:
somePoint.X = 5;
could be written as:
void SetXToFive(ref Point it) {it.X = 5;}
...
SetXToFive(ref somePoint);
allowing the code which manipulates the Point (by setting its X field to 5) from the code which has access to it. If an object which would have a property of type Point then exposes a routine which accepts a delegate to a method like the above, code that wants to set field X of that property to 5 could pass that routine a delegate to SetXToFive, which the routine could then call with whatever storage location holds the Point in question.
Note that one advantage over such an approach, compared with simply exposing a reference to the thing to be manipulated, is that the owner of the Point would know when the code that was manipulating it had finished. Without some compiler supper, the approach would generally be more of a nuisance than a benefit, but with compiler support the semantics could be made much cleaner than would be possible via any other means.
I am trying to understand how to assign by "reference" to a class field in C#.
I have the following example to consider:
public class X
{
public X()
{
string example = "X";
new Y(ref example);
new Z(ref example);
System.Diagnostics.Debug.WriteLine(example);
}
}
public class Y
{
public Y( ref string example )
{
example += " (Updated By Y)";
}
}
public class Z
{
private string _Example;
public Z(ref string example)
{
this._Example = example;
this._Example += " (Updated By Z)";
}
}
var x = new X();
When running the above code the output is:
X (Updated By Y)
And not:
X (Updated By Y) (Updated By Z)
As I had hoped.
It seems that assigning a "ref parameter" to a field loses the reference.
Is there a way to keep hold of the reference when assigning to a field?
As others have noted, you cannot have a field of "ref to variable" type. However, just knowing that you cannot do it is probably unsatisfying; you probably also want to know first, why not, and second, how to get around this restriction.
The reason why is because there are only three possibilities:
1) Disallow fields of ref type
2) Allow unsafe fields of ref type
3) Do not use the temporary storage pool for local variables (aka "the stack")
Suppose we allowed fields of ref type. Then you could do
public ref int x;
void M()
{
int y = 123;
this.x = ref y;
}
and now y can be accessed after M completes. This means that either we're in case (2) -- accessing this.x will crash and die horribly because the storage for y no longer exists -- or we're in case (3), and the local y is stored on the garbage collected heap, not the temporary memory pool.
We like the optimization that local variables be stored on the temporary pool even if they are being passed by ref, and we hate the idea that you could leave a time bomb around that could make your program crash and die later. Therefore, option one it is: no ref fields.
Note that for local variables that are closed-over variables of anonymous functions we choose option (3); those local variables are not allocated out of the temporary pool.
Which then brings us to the second question: how do you get around it? If the reason you want a ref field is to make a getter and setter of another variable, that's perfectly legal:
sealed class Ref<T>
{
private readonly Func<T> getter;
private readonly Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value { get { return getter(); } set { setter(value); } }
}
...
Ref<int> x;
void M()
{
int y = 123;
x = new Ref<int>(()=>y, z=>{y=z;});
x.Value = 456;
Console.WriteLine(y); // 456 -- setting x.Value changes y.
}
And there you go. y is stored on the gc heap, and x is an object that has the ability to get and set y.
Note that the CLR does support ref locals and ref returning methods, though C# does not. Perhaps a hypothetical future version of C# will support these features; I have prototyped it and it works well. However, this is not real high on the priority list, so I wouldn't get my hopes up.
UPDATE: The feature mentioned in the paragraph above was finally implemented for real in C# 7. However, you still cannot store a ref in a field.
No. ref is purely a calling convention. You can't use it to qualify a field. In Z, _Example gets set to the value of the string reference passed in. You then assign a new string reference to it using +=. You never assign to example, so the ref has no effect.
The only work-around for what you want is to have a shared mutable wrapper object (an array or a hypothetical StringWrapper) that contains the reference (a string here). Generally, if you need this, you can find a larger mutable object for the classes to share.
public class StringWrapper
{
public string s;
public StringWrapper(string s)
{
this.s = s;
}
public string ToString()
{
return s;
}
}
public class X
{
public X()
{
StringWrapper example = new StringWrapper("X");
new Z(example)
System.Diagnostics.Debug.WriteLine( example );
}
}
public class Z
{
private StringWrapper _Example;
public Z( StringWrapper example )
{
this._Example = example;
this._Example.s += " (Updated By Z)";
}
}
You forgot to update the reference in the Z class:
public class Z {
private string _Example;
public Z(ref string example) {
example = this._Example += " (Updated By Z)";
}
}
Output: X (Updated By Y) (Updated By Z)
Point to keep in mind is that the += operator for a string calls the String.Concat() method. Which creates a new string object, it doesn't update the value of a string. String objects are immutable, the string class doesn't have any methods or fields that lets you change the value. Very different from the default behavior of a regular reference type.
So if you use a string method or operator, you always have to assign the return value back to a variable. This is pretty natural syntax, value types behave the same way. Your code would be very similar if you used an int instead of a string.
I was wondering how one could store a reference to an object in .net.
That is, I would like something like the following code (note, of course, that the following code may be way off from how to actually do it):
class Test
{
private /*reference to*/ Object a;
public Test(ref int a)
{
this.a = a;
this.a = ((int)this.a) + 1;
}
public Object getA() { return this.a; }
}
/*
* ...
*/
static void Main(string[] args)
{
int a;
a=3;
Test t = new Test(ref a);
Console.WriteLine(a);
Console.WriteLine(t.getA());
Console.ReadKey();
}
To produce the following output:
4
4
Ideally, I would like to do this without writing a wrapper class around the integer.
In other words, I think I want pointers in .Net.
You cannot store references to variables in .NET, period. You can store references to objects, but not references to variables.
The reason is that if you were allowed to store references to arbitrary variables then you could store references to local variables. If you can store references to local variables then the runtime cannot use the optimization of storing local variables on the short-lived memory pool, aka, the stack.
Now, even if you could do that, the operation you are describing is not typesafe for a different reason. You have a (very badly named) field variable "a" of type "reference to object variable" and a (very badly and confusingly named) local variable "a" of type "reference to int variable". Even if you could store a reference to a variable it doesn't make any sense to store a reference to an int variable in something of type "reference to object variable" because those two types are logically not compatible. The operations you can perform on them are different; a reference to an object variable can have a string written into it; a reference to an int variable cannot.
Perhaps I am misunderstanding but wouldn't a variable such as the integer above be boxed into an object which could then be stored as a reference?
You are confusing references to objects with references to variables. It is confusing that we use the same terminology for what is really two different things.
Yes, boxing turns a value type, like int, into a reference type, like object. That has ABSOLUTELY NOTHING WHATSOEVER to do with references to variables.
When you make a ref to a variable you are making an alias for that variable. When you say
void M(ref int y) { y = 123; }
...
int x = 0;
M(ref x);
you are saying "x and y are two different names for the same variable".
Now, if what you want to do is represent the notion of "I have captured a variable and I want to be able to read and write it" then use delegates:
class Ref<T>
{
private Func<T> getter;
private Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value
{
get { return getter(); }
set { setter(value); }
}
}
...
int abc = 123;
var refabc = new Ref<int>(()=>abc, x=>{abc=x;});
... now you can pass around refabc, store it in a field, and so on
refabc.Value = 456;
Console.WriteLine(abc); // 456
Console.WriteLine(refabc.Value); // 456
Make sense?
C# has no concept of a reference variable akin to C++'s int& a. There are workarounds. One is to use closures:
class Test
{
private Func<int> get_a;
private Action<int> set_a;
public Test(Func<int> get_a, Action<int> set_a)
{
this.get_a = get_a;
this.set_a = set_a;
this.set_a(this.get_a() + 1);
}
public Object getA() { return this.get_a(); }
}
/*
* ...
*/
static void Main(string[] args)
{
int a;
a=3;
Test t = new Test(() => a, n => { a = n; });
Console.WriteLine(a);
Console.WriteLine(t.getA());
Console.ReadKey();
}
I'm not in front of VS, so please excuse any embarrassing faux pas.