Member references and assignment order of evaluation - c#

Why does the following crash with a NullReferenceException on the statement a.b.c = LazyInitBAndReturnValue(a);?
class A {
public B b;
}
class B {
public int c;
public int other, various, fields;
}
class Program {
private static int LazyInitBAndReturnValue(A a)
{
if (a.b == null)
a.b = new B();
return 42;
}
static void Main(string[] args)
{
A a = new A();
a.b.c = LazyInitBAndReturnValue(a);
a.b.other = LazyInitBAndReturnValue(a);
a.b.various = LazyInitBAndReturnValue(a);
a.b.fields = LazyInitBAndReturnValue(a);
}
}
Assignment expressions are evaluated from right to left, so by the time we are assigning to a.b.c, a.b should not be null. Oddly enough, when the debugger breaks on the exception, it too shows a.b as initialized to a non-null value.

This is detailed in Section 7.13.1 of the C# spec.
The run-time processing of a simple assignment of the form x = y
consists of the following steps:
If x is classified as a variable:
x is evaluated to produce the variable.
y is evaluated and, if required, converted to the type of x through an implicit conversion (Section 6.1).
If the variable given by x is an array element of a reference-type, a run-time check is performed to ensure that the value
computed for y is compatible with the array instance of which x is an
element. The check succeeds if y is null, or if an implicit reference
conversion (Section 6.1.4) exists from the actual type of the instance
referenced by y to the actual element type of the array instance
containing x. Otherwise, a System.ArrayTypeMismatchException is
thrown.
The value resulting from the evaluation and conversion of y is stored into the location given by the evaluation of x.
If x is classified as a property or indexer access:
The instance expression (if x is not static) and the argument list (if x is an indexer access) associated with x are evaluated, and the results are used in the subsequent set accessor invocation.
y is evaluated and, if required, converted to the type of x through an implicit conversion (Section 6.1).
The set accessor of x is invoked with the value computed for y as its value argument.
I think the bottom section (if x is classified as a property or indexer access) provides a hint, but perhaps a C# expert can clarify.
A set accessor is generated first, then y is evaluated (triggering your breakpoint), then the set accessor is invoked, which causes a null reference exception. If I had to guess, I'd say the accessor points to the old value of b, which was null. When you update b, it doesn't update the accessor that it already created.

I realize this doesn't answer your question, but allowing something outside of class A to initialize a member belonging to class A in this fashion seems to me to break encapsulation. If B needs to be initialized on first use the "owner" of B should be the one to do that.
class A
{
private B _b;
public B b
{
get
{
_b = _b ?? new B();
return _b;
}
}
}

Related

Why implicit operator has to be static?

I have a class named FloatPlugIn. I want user to be able to do things like
FloatPlugIn x = new FloatPlugIn();
x.Minimum = -100;
x.Maximum = 100;
float y = 123;
x = y;
That is why I decided to add implicit operator to my class
public static implicit operator FloatPlugIn(float p)
{
return new FloatPlugIn() { Default = p };
}
Problem is that implicit operator has to be static that is why during conversion new instance of my class is created. As a result I am loosing all the information that was located inside of "old" instance.
Is there a way to fix that? I want float value to be applied to existing instance, not to completely replace it.
I don't think you're understanding what conversion does - it's not casting - it must create a new instance. It only makes sense to make it non-static if it were only updating the existing instance.
I think it's better in this case if you either use x.Default = y; or if you create a constructor that takes the float like this:
// Constructor
public FloatPlugIn(float p)
{
Default = p;
}
Usage:
float y = 123;
FloatPlugIn x = new FloatPlugIn(y);
The semantics of the assignment operator requires that behavior. In fact:
The assignment operator (=) stores the value of its right-hand operand in the storage location, property, or indexer denoted by its left-hand operand and returns the value as its result. The operands must be of the same type (or the right-hand operand must be implicitly convertible to the type of the left-hand operand).
It is not the purpose of the implicit conversion operator to modify a destination value—note that there may not be any such destination value, such as in case you pass the value to a parameter of a method.
I want float value to be added to existing instance, not to completely replace it.
If you want an addition (in whatever specific sense that would mean in your case), consider overriding the addition + operator, which in turn has effect on the addition assignment += operator. However, you won't eliminate the creation of a new FloatPlugIn instance anyway.
Consider you'd have the following method in FloatPlugIn, which would modify an existing instance:
public void Add(float f)
{
// do whatever 'addition' means in your case
}
Then the + operator should work like this:
public static FloatPlugIn operator +(FloatPlugIn a, float b)
{
FloatPlugIn result = a.Clone(); // here Clone() denotes any custom method that creates a copy of that instance
result.Add(b);
return b;
}
In your code, the following would work then:
FloatPlugIn x = new FloatPlugIn();
x.Minimum = -100;
x.Maximum = 100;
float y = 123;
x += y; // a new instance is created, but the 'addition' logic is preserved
Also, the same will intuitively work in case of passing a value to a method call:
ProcessMyFloatPlugin(x + 123.0f);
You can see that it is a really good idea to create a new instance of FloatPlugIn as a result of an operator. Otherwise, an in-place modification of x would be, in fact, a nasty side-effect, completely unexpected by any other developer. Note that if performance (avoiding dynamic memory allocations) is a concern, consider using structs.

C# declaration of variable

I started my journey with C# but I realised that I have some problems with some basic information about memory when it comes to declaration of variables. See if I am correct.
int x; // I declared variable of type int, which name is x. Compiler will provide memory for it but we dont have known value of it.
x=10; // Now memory location is still the same but value now kept there is 10;
public struct Point {
public int x, y;
}
Now I define a struct named Point. Beacuse struct is a value type, it again has reserved memory for it on the computer. Howewer x and y have no value.
Now Point p1 = new Point(); // what is happening here? Struct is not a reference type. So is this just initialization of Point variable with the default constructor without assigning values to x and y?
Second short question. When I write a code like:
int x = 10;
Can I say that I created instance of class integer which value is 10 and name x;
I would be grateful for help.
// what is happening here? Struct is not a reference type. So is this just initialization of Point variable with the default constructor without assigning values to x and y?
No; there are 4 possible scenarios here:
a class: the memory space is wiped to all 0s, then any custom constructor is invoked, which may also involve field initializers
a struct called without a custom constructor: the memory space is wiped to all 0s
a struct called with a custom constructor: the custom constructor is required to assign all the fields
a struct variable used without ever calling a constructor: this is actually a thing, but the calling code must write to all the fields before they can do anything else with it; since most structs do not expose their fields, this rarely works
Second short question. When i write a code like:
int x = 10;
Can i say that i created instance of class integer which value is 10 and name x; I would be grateful for help.
Not really, because in C# terms, int is not a class (it might be in IL terms). Simply: you have declared a local variable of type int with name x and assigned it the value 10, if this is in a method. If this is a class field, then: you have declared a private instance field of type int named x with a field-initializer giving it the value of 10.
Incidentally, you should avoid public fields in general, and mutable fields on structs. You might prefer:
public struct Point {
private readonly int x, y;
public int X { get { return x; } }
public int Y { get { return y; } }
public Point(int x, int y) { this.x = x; this.y = y'; }
}
This will avoid a huge range of problems.
In C# the default struct constructor sets the struct memory to 0, effectively setting all variables to their default values.
In case of ints, it will be 0. For reference types, it will result in null.
(in other words, for any type T it will be default(T)).
Note that when you write a custom constructor in a struct, you must initialize all member fields.
When you write
int x;
this is similar to
Point p1 = new Point(); (considering Point structure is already defined)
in both the cases all integer variables will have default value of 0 and not null, which is is basically what is used in C# to denote 'nothing' and can be assigned only to reference types.
As well, in c# everything is a class, so when you write
int x = 10;
you are creating an instance of class Int32, though the run time will handle this as value type instead of ref type, as special case.
Same is true for other basic types like, Long, DateTime and few others

Why does assignment to parameter not change object?

classes deal with the reference types and traditional data types deal with the value type just for example :
int i=5;
int j=i;
i=3 ; //then this will output i=3 and j=5 because they are in the different memory blocks .
Similarly if we talk about the object of a class say point class
class point
{
public int x,y;
void somefucnt(point p,int x)
{
Console.writeline("value of x is "+p.x);
x=22;
Console.writeline("value of x is "+p.x);
}
}
class someotherclass
{
static void Main(string [] args )
{
p1.x=10;
p1.somefunct(p1,p1.x);
}
}
Both console.write statements are printing 10 , despite ive changed x to some other value ? why is it so ?since p is just the reference to x so it should be updated by changing values of x . this thing is really confusing me alot .
The observed behavior has nothing to do with Value types vs Reference types - it has to do with the Evaluation of Strategy (or "calling conventions") when invoking a method.
Without ref/out, C# is always Call by Value1, which means re-assignments to parameters do not affect the caller bindings. As such, the re-assignment to the x parameter is independent of the argument value (or source of such value) - it doesn't matter if it's a Value type or a Reference type.
See Reference type still needs pass by ref? (on why caller does not see parameter re-assignment):
Everything is passed by value in C#. However, when you pass a reference type, the reference itself is being passed by value, i.e., a copy of the original reference is passed. So, you can change the state of object that the reference copy points to, but if you assign a new value to the reference [parameter] you are only changing what the [local variable] copy points to, not the original reference [in the argument expression].
And Passing reference type in C# (on why ref is not needed to mutate Reference types)
I.e. the address of the object is passed by value, but the address to the object and the object is the same. So when you call your method, the VM copies the reference; you're just changing a copy.
1 For references types, the phrasing "Call By Value [of the Reference]" or "Call by [Reference] Value" may help clear up the issue. Eric Lippert has written a popular article The Truth about Value Types which encourages treating reference values as a distinct concept from References (or instances of Reference types).
void somefucnt(point p,int x){
Console.writeline("value of x is "+p.x);
x=22;
Console.writeline("value of x is "+p.x);
}
Here, the x=22 won´t change p.x but the parameter x of (point p,int x)
Normally, your assumtion about values/references is ok (if I understood it correctly).
Tip: Google for c# this instead of passing a object to it´s own method
You change the value of the parameter (x), not the value of p.x, value types are passed by value unless you use the ref keyword.
Like in your first example, there is no relationship between i and j as well as the parameter x, and p1.x.Each variable has it's own space in the memory.So changing one of them doesn't affect to the other.
You have two different variables named x in the somefucnt function. One is the member variable x which you are trying to change, the other is the function input parameter in void somefucnt(point p, int x). When you say x = 22, the input parameter x is changed instead of the member variable x.
If you change the line x = 22 to this.x = 22 then it should work as you expect.
Side note:
A good practice to avoid confusion is to always have class members private and name them as _x. Otherwise, have public auto properties in CamelCase, like this:
public int X { get; set; }
These methods avoid ambiguity between class variables and function input variables.

Implicit conversion with null-coalescing operator

I discovered a strange behaviour of my program and after futher analysis, I was able to find that there is probably something wrong either in my C# knowledge or somewhere else. I beleive it's my mistake but I cannot find an answer anywhere...
public class B
{
public static implicit operator B(A values)
{
return null;
}
}
public class A { }
public class Program
{
static void Main(string[] args)
{
A a = new A();
B b = a ?? new B();
//b = null ... is it wrong that I expect b to be B() ?
}
}
The variable "b" in this code is evaluated to null. I don't get why is it null.
I googled and found a response in this question - Implicit casting of Null-Coalescing operator result - with the official specification.
But following this specification, I can't find the reason why "b" is null :( Maybe I'm reading it wrong in which case I apologize for spamming.
If A exists and is not a nullable type or a reference type, a compile-time error occurs.
...that's not the case.
If b is a dynamic expression, the result type is dynamic. At run-time, a is first evaluated. If a is not null, a is converted to dynamic, and this becomes the result. Otherwise, b is evaluated, and this becomes the result.
...that's also not the case.
Otherwise, if A exists and is a nullable type and an implicit conversion exists from b to A0, the result type is A0. At run-time, a is first evaluated. If a is not null, a is unwrapped to type A0, and this becomes the result. Otherwise, b is evaluated and converted to type A0, and this becomes the result.
...A exists, implicit conversion from b to A0 does not exist.
Otherwise, if A exists and an implicit conversion exists from b to A, the result type is A. At run-time, a is first evaluated. If a is not null, a becomes the result. Otherwise, b is evaluated and converted to type A, and this becomes the result.
...A exists, implicit conversion from b to A does not exist.
Otherwise, if b has a type B and an implicit conversion exists from a to B, the result type is B. At run-time, a is first evaluated. If a is not null, a is unwrapped to type A0 (if A exists and is nullable) and converted to type B, and this becomes the result. Otherwise, b is evaluated and becomes the result.
...b has a type B and implicit conversion exists from a to B.
a is evaluated into null. Therefore, b should be evaluated and b should be the result.
Otherwise, a and b are incompatible, and a compile-time error occurs.
Does not happen
Am I missing something please?
Why did you expect the null-coalescing operator to return new B()? a is not null, so a ?? new B() evaluates to a.
Now that we know that a will be returned, we need to determine the type of the result (T) and whether we need to cast a to T.
• Otherwise, if b has a type B and an implicit conversion exists from
a to B, the result type is B. At run-time, a is first evaluated. If a
is not null, a is unwrapped to type A0 (if A exists and is nullable)
and converted to type B, and this becomes the result. Otherwise, b is
evaluated and becomes the result.
An implicit conversion exists from A to B, so B is the result type of the expression. Which means a will be implicitly casted to B. And your implicit operator returns null.
In fact, if you write var b = a ?? new B(); (notice the var), you'll see that the compiler infers B to be the type returned by the expression.
Otherwise, if b has a type B and an implicit conversion exists from a
to B, the result type is B. At run-time, a is first evaluated. If a is
not null, a is unwrapped to type A0 (if A exists and is nullable) and
converted to type B, and this becomes the result. Otherwise, b is
evaluated and becomes the result.
...b has a type B and implicit conversion exists from a to B. a is
evaluated into null. Therefore, b should be evaluated and b should be
the result.
You're interpreting this one wrong. Nothing says that a to B conversion is done before null check is performed. It states that null check is done before the conversion!
Your case fits to that:
If a is not null, a is unwrapped to type A0 (if A exists and is
nullable) and converted to type B, and this becomes the
result.
Well, the specification says (I change to x and y for less confusion here):
• Otherwise, if y has a type Y and an implicit conversion exists from x to Y, the result type is Y. At run-time, x is first evaluated. If x is not null, x is unwrapped to type X0 (if X exists and is nullable) and converted to type Y, and this becomes the result. Otherwise, y is evaluated and becomes the result.
This happens. First, the left-hand side x, which is just a, is checked for null. But it is not null in itself. Then the left-hand side is to be used. The implicit conversion is then run. Its result of type B is ... null.
Note that this is different from:
A a = new A();
B b = (B)a ?? new B();
In this case the left operand is an expression (x) which is null in itself, and the result becomes the right-hand side (y).
Maybe implicit conversions between reference types should return null (if and) only if the original is null, as a good practice?
I guess the guys who wrote the spec could have done it like this (but did not):
• Otherwise, if y has a type Y and an implicit conversion exists from x to Y, the result type is Y. At run-time, x is first evaluated and converted to type Y. If the output of that conversion is not null, that output becomes the result. Otherwise, y is evaluated and becomes the result.
Maybe that would have been more intuitive? It would have forced the runtime to call your implicit conversion no matter if the input to the conversion were null or not. That should not be too expensive if typical implementations quickly determined that null → null.
The part we need to look at is the compile-time type of the null-coalescing expression.
Otherwise, if b has a type B and an implicit conversion exists from a to B, the result type is B. At run-time, a is first evaluated. If a is not null, a is unwrapped to type A0 (if A exists and is nullable) and converted to type B, and this becomes the result. Otherwise, b is evaluated and becomes the result.
To put this into pseudocode:
public Tuple<Type, object> NullCoalesce<TA, TB>(TA a, TB b)
{
...
else if (a is TB) // pseudocode alert, this won't work in actual C#
{
Type type = typeof(TB);
object result;
if (a != null)
{
result = (TB)a; // in your example, this resolves to null
}
else
{
result = b;
}
return new Tuple<Type, object>(type, result);
}
...
}

C# struct and class variable value

i know that struct is of value type and class is reference type but when i execute the following code why im getting the two different answer
can any one explain a bit
[struct|class] values {
public int x, y;
public values (int x, int y) {
this.x = x;
this.y = y;
}
}
values v = new values(12, 13);
object o = v;
v.x = 2;
Console.WriteLine(((values)o).x);
Outputs
when
it is class : output is 2
it is struct :output is 12
Can any one explain me?
Thanks
The one line that behaves very differently for struct or class is
object o = v;
When Values is a reference type, o becomes a copy of the reference v. There still is only 1 instance of Values.
When Values is a value type, o becomes a reference to the boxed copy of the instance itself. In this case the assignment creates a 2nd instance and you execute v.x = 2 on the original. The copy is not affected.
Your example includes boxing and that is an unnecessary complication, when you use values o = v; you will get the same output. The line then creates a normal copy (2nd instance) without boxing.
To sum it up: the main difference between value and reference type is in copy semantics. You will notice different behaviour in simple assignments (x = y) and in parameter passing (foo(x)).
You can expect gotchas with mutable value types. As an exercise, see what f.Myvalue.x = 2; does with Values as class or struct with
class Foo { public Values MyValue { get; set; } }
When you use a structure and you assign it (or use it as a parameter of a method), you have a brand new copy of your structure.
Whereas, with a class, you assign a reference to the class.
Key line is
object o = v;
When values is struct (or value-type), it causes boxing values. According this (following that link, you can find exactly your question at end :))
Boxing a value of a value-type consists of allocating an object
instance and copying the value-type value into that instance.
So, your value in v is copied. When you unboxing here
Console.WriteLine(((values)o).x);
you get original v value, not v after
v.x = 2;
So, answer for struct (or value-types) is 12.
For class (or reference-types) it's very simple. You are not boxing, just cast to object, so next you are working with this original v and change it value.
Given
SomeStruct s1, s2, s3;
Object o1;
... s1 gets a value somehow, then...
s2 = s1; // Q1
o1 = s1; // Q2
s3 = (SomeStruct)o1; // Q3
statement Q1 will mutate structure s2 by overwriting all of its public and private fields with the values of the corresponding fields in s1. Statement Q2 will generate a new heap object which will act as though it contains a field of type SomeStruct, and will modify that field by overwriting all of its fields with the corresponding fields in s1. Statement Q3 will check whether o1 contains a "boxed" SomeStruct and, if so, will overwrite all the fields of s3 with the corresponding ones from the boxed object.
Note that boxed structures are not usually modified while they sit within heap objects. If one were to say:
var temp = (SomeStruct)o1;
temp.someField = Whatever;
o1 = temp;
that sequence would create a new heap object which would hold a modified copy of the original structure, but the original boxed structure would remain as it was. There are, however, ways a structure within a boxed object can be modified. One should in most cases avoid using such techniques, but one should be aware there's no such thing as a non-trivial immutable structure (a struct with no fields would be immutable, but not very useful). In general, if one wants to be able to refer to a mutable instance of a structure type, it's best to encapsulate it within a simple class object, e.g.
class ExposedFieldHolder<T>
{
public T Value;
public ExposedFieldHolder(T v) {Value = v;}
}
and if one wants to have an immutable instance, one should encapsulate it in an immutable class object
class ImmutableHolder<T>
{
T value;
public T Value { get { return value; } ;
public ImmutableHolder(T v) {value = v;}
override public bool Equals(Object o) {
var other = o as ImmutableHolder<T>;
if (!other) return false;
return Object.Equals(value,other.value);
}
override public int GetHashCode() { return Object.GetHashCode(value); }
}

Categories

Resources