Meaning of "this" for a struct (C#) - c#

According to MSDN (Section 11.3.6 of the C# spec):
Within an instance constructor of a
struct, this corresponds to an out
parameter of the struct type, and
within an instance function member of
a struct, this corresponds to a ref
parameter of the struct type. In both
cases, this is classified as a
variable, and it is possible to modify
the entire struct for which the
function member was invoked by
assigning to this or by passing this
as a ref or out parameter.
I don't get it. How is this different for a struct than for a class? Code examples are appreciated

Eric Lippert had a fabulous post on mutating readonly structs a while back that will really help clarify the issue for you. There's even a code example, and a quiz!
The salient point is that structs obey value semantics and classes do not and so this must mean something different for the two. this is readonly for a class, but not for a struct. The following code is legal
struct Point {
public int x;
public int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public void DoGoTime() {
GoTime(ref this);
}
public static void GoTime(ref Point p) {
p.x = 100;
p.y = 100;
}
}
but is not if "struct" is replaced by "class."

When you're dealing with structs, you're dealing with value types.
In a class, "this" is a reference to the current instance. This lets you mutate the class instance by setting properties/fields on the class.
However, if you're in a struct, things act differently. When you're in a struct's method, "this" lets you mutate the struct. However, if you're using this in a method, you're almost always dealing with a copy of the "original" struct.
For example:
struct Test
{
int i;
void Mutate() {
this.i += 1;
}
}
When you use this:
void MutateTest(Test instance)
{
instance.Mutate();
}
{
Test test = new Test();
test.i = 3;
Console.WriteLine(test.i); // Writes 3
test.Mutate(); // test.i is now 4
Console.WriteLine(test.i); // Writes 4
MutateTest(test); // MutateTest works on a copy.. "this" is only part of the copy itself
Console.WriteLine(test.i); // Writes 4 still
}
Now, the stranger part - this is valid, and what that quote was saying:
struct Test
{
public Test(int value)
{
this.i = value;
}
int i;
void Mutate(int newValue) {
this = new Test(newValue); // This wouldn't work with classes
}
}
///
{
Test test = new Test();
test.i = 3;
Console.WriteLine(test.i); // Writes 3
test.Mutate(4);
Console.WriteLine(test.i); // Writes 4

Jason's answer and Eric's post show one aspect of this which is interesting... but there's another which is even more alarming:
You can reassign this within a method, even if the type is otherwise immutable.
To demonstrate it, we'll use a struct which is stored in a non-readonly variable, but which contains a readonly field:
using System;
public struct LooksImmutable
{
private readonly int value;
public int Value { get { return value; } }
public LooksImmutable(int value)
{
this.value = value;
}
public void GoCrazy()
{
this = new LooksImmutable(value + 1);
}
}
public class Test
{
static void Main()
{
LooksImmutable x = new LooksImmutable(5);
Console.WriteLine(x.Value);
x.GoCrazy();
Console.WriteLine(x.Value);
}
}

Related

Pointers are unsafe but I don't understand ref

I want a singleton Problem with a "square" 2x2.
I want to be able to refer to the case by row.
I want to be able to refer to the row by case.
I know I could easily do this in C++ with pointers but it seems like a bad habit to do.
I don't understand how to link my "row" and my "case" together.
The same logic will be there for column but isn't describe in the code
The goal is so changing the value of a Case would affect the value reffered in the Row. How can I achieve this without pointer and with Ref?
class Program
{
static void Main(string[] args)
{
Problem.Instance().Show();
Problem.Instance().Change();
Problem.Instance().Show();
}
public class Problem
{
private Case[] cases = null;
private Row[] rows = null;
// same logic with private Column[] columns = null;
static Problem instance = null;
private Problem()
{
cases = new Case[4];
rows = new Row[2];
int i = 0;
for (i = 0; i < 4; i++)
cases[i] = new Case();
for (i = 0; i < 2; i++)
rows[i] = new Row(i);
}
public static Problem Instance()
{
if (instance == null)
instance = new Problem();
return instance;
}
public Case LinkToRow(int i, ref Row r)
{
cases[i].LinkToRow(r);
return cases[i];
}
public void Show()
{
rows[0].Show();
}
public void Change()
{
cases[0].Change();
cases[1].Change();
}
}
public class Row
{
private Case[] ref cases = null;
public Row(int i)
{
ref Row r = this;
cases = new Case[2];
cases[0] = Problem.Instance().LinkToRow(0, ref r);
cases[1] = Problem.Instance().LinkToRow(1, ref r);
}
public void Show()
{
Console.WriteLine("{0},{1}", cases[0].Val, cases[1].Val);
}
}
public class Case
{
private int val;
private ref Row r = null;
public Case()
{
}
public void LinkToRow(Row rr)
{
r = rr;
}
public int Val { get { return val; } }
public void Change()
{
val++;
}
}
}
In C#, private Row r = null; declares a rebindable reference to an instance of Row. ref is illegal there and not needed.
In C++, private: Row r; would be an instance of Row, not a reference. C++ is a different language with very different rules. C# classes can't "be on the stack"; they're always dynamically allocated, and the only way you can manipulate one is via a reference.
In C#, your private Row r; is already a reference. A C# reference is kind of like a pointer that you don't have to (and can't) explicitly dereference. Because it's always dereferenced, you can't do pointer arithmetic either. They're subject to many of the same polite fictions ("let's make them pretend it's not a pointer") as C++ references. Just take out ref.
A C# struct (e.g. System.DateTime) is more like a stack instance of a C++ class. This is very different from the C++ struct/class distinction.
The C# ref keyword is a different animal. Nothing to do with references.
In C#, the example below illustrates what the ref keyword is for: Passing references by reference instead of by value. That sounds like I'm pulling your leg but I'm not.
To explain it in terms of C++ semantics, passing a C# reference "by value" is like passing a pointer. You can change the object the caller's pointer points at, but you can't change the caller's pointer itself. You have only the value of the caller's pointer.
Passing a C# reference by reference is like passing in a pointer to a pointer: You can set (*p)->Foo = 3;, and you can also set *p = new Bar(); (I'm rusty on C/C++, corrections welcomed).
public static void F()
{
String x = "original value";
FByValue(x);
Console.WriteLine(x);
FByReference(ref x);
Console.WriteLine(x);
}
public static void FByValue(String s)
{
s = "different value for local copy of parameter only";
}
public static void FByReference(ref String s)
{
s = "different value for caller's copy, thanks to ref keyword";
}
ref works only with parameters, never ever with fields; see MSDN for more detail.
Lastly: FByValue() and FByReference() would have identical semantics with int instead of String.
In C# there is a difference between value types and references.
First, there is nothing wrong with pointers in C/C++, that's how the language works and, that's how the hardware works as well. They can just be confusing to the new user.
In C#, the definition of structures and classes is different than C++:
if you define your data structures as struct or as class.
A struct is an object that gets copied around as it is passed from calls to calls. A class on the other hand gets its pointer passed around, similar to a C++ pointer, so if you have references to class instances in C#, you're really referencing the same object, and changes done at one place will be reflected everywhere you hold a reference to that object.

Why should we initialize a struct before passing it to a function?

Consider this code:
MyStruct j;
j.I = 3;
Console.WriteLine(j.I);
Now see this method:
public static void StructMod(MyStruct ms)
{
ms.I += 100;
Console.WriteLine(ms.I);
}
When we pass MyStruct to the method, should we initialize it before passing it? I.e.:
MyStruct j = new MyStruct()
Unless struct is value type?
Yes, it is.
First line from MSDN:
A struct type is a value type...
As with individual variables, a struct must be fully initialized before it can be used. Consider:
struct Foo
{
public int Bar;
public int Pop;
}
class Program
{
static void Main(string[] args) {
Foo f;
f.Bar = 3;
test(f); // ERROR: Use of unassigned local variable 'f'
}
static void test(Foo f) {
Console.WriteLine("{0}", f.Bar);
}
}
The solution here is to either initialize .Bar, or simply call the Foo constructor f = new Foo() which initializes all members to their default values.
This is the same logic behind the "Field ... must be fully assigned before control is returned to the caller" error that you get when adding parameterized constructors to structs.
After a little testing, it seems that either way you declare it, it's being initialized.
One reason to call new ... would be to execute code in the constructor, if any.
Take this sample from MSDN, for example:
public struct CoOrds
{
public int x, y;
public CoOrds(int p1, int p2)
{
x = p1;
y = p2;
}
}
You could just do this, and use c, but then x and y will be 0.
CoOrds c;
Alternatively, you could do this, and then x and y start off with values.
CoOrds c = new CoOrds(5,3);
(This would be more useful if the ctor did something more interesting.)
If you want the struct to have a particular value, then initialize it to that value.
If you want the struct to be initialized to its default value, then you don't need to explicitly initialize it. However, it might still be best to do so for the sake of readability if the struct's default value is non-obvious.
As a side note: Mutable structs are really bad; the entire scenario you propose in your example is a code smell. See Why are mutable structs “evil”?
The same behavior could be achieved more safely with an immutable struct like so
struct MyStruct
{
public readonly int I;
public MyStruct(int i_initial)
{
I = i_initial;
}
}
MyStruct j = new MyStruct(3);
public static void StructMod(MyStruct ms)
{
Console.WriteLine(ms.I + 100);
}
In particular, note that from the caller's point of view this function's behavior will be exactly the same as the one in the question, because structs are passed by value the same way that primitives like int are. If the "Mod" in StructMod is there because you expect this function to modify the value, then that's a good concrete example of why it's generally better for mutable types to be objects and not structs.

Access method via instance and static

Is it possible to create a class that has a method definition where the method can be accessed statically, and also be accessed via an instance of the class, without having to have two separate names for the method or a separate set of arguments to distinguish the methods as two different methods.
i.e.
public class MyClass
{
public static int GetMyInt()
{
return 1;
}
}
...
MyClass classInst = new MyClass();
int i = MyClass.GetMyInt();
int x = classInst.GetMyInt();
Is this possible in C#? If so, how so?
No. A method is static or is not.
I don't a valid use case you want to allow calling a static method against an instance of a class.
I dont think you can have the cake and eat the cake too.
Static (methods which are called through class) and non-static (methods which are called through instance of class ) are two opposite sides of a coin.
So either it is static or non-static but not both
A static (or class) method is by definition different from an instance method.
An instance method is only accessible when you create an instance of that class;
A static method is always accessible, since it doesn't require class instanciation (provided it is public), at least always accessible within the class itself. You should know, however, that if you have a static variable, any changes made to that variable will affect the class, and have an impact everywhere that variable is used on the application.
eg.
...
static int lastId;
public static int getLastId(){
return lastId++;
}
This is a way you may control an autonumber on a class, since whenever you call getLastId, lastId will be incremented and that is valid for all the application.
edit
the sample code illustrates what happens with a static variable. That said, you should know that overloading is supported on c#. What you cannot have is a pair of methods with the same name tag and the same set and type of parameters.
for eg., this builds ok.
public static int getValue()
{
return 1;
}
public int getValue(int x)
{
return x * 1;
}
but this will throw an error:
public static int getValue(int z)
{
return 1;
}
public int getValue(int x)
{
return x * 1;
}
that is true independently of wether there is a static method or not. This will also generate a compile time error:
public int getValue(int z)
{
return 1;
}
public int getValue(int x)
{
return x * 1;
}
even this will give you an error:
public string getValue(int z)
{
return 1;
}
public int getValue(int x)
{
return x * 1;
}
so, yes, you may have a static method with the same name tag of an instance method, but you may not have the same set and type of parameters.
If you want both static an instance methods to have the same behaviour, then why do you need the intance method really? The static method will do the trick (considering you know the consequences of having a static method and its implications).
Nope. But you can wrap it. But will have to give it a new signature.
public int getMyInt()
{
return GetMyInt();
}

Why is this method Impure?

I read this answer: https://stackoverflow.com/a/9928643/16241
But I obviously don't understand it because I can't figure out why my method is impure. (The method in question is ToExactLocation()).
public struct ScreenLocation
{
public ScreenLocation(int x, int y):this()
{
X = x;
Y = y;
}
public int X { get; set; }
public int Y { get; set; }
public ExactLocation ToExactLocation()
{
return new ExactLocation {X = this.X, Y = this.Y};
}
// Other stuff
}
Incase you need it here is the exact location struct:
public struct ExactLocation
{
public double X { get; set; }
public double Y { get; set; }
// Various Operator Overloads, but no constructor
}
And this is how I call it:
someScreenLocation = MethodThatGivesAScreenLocation();
if (DestinationLocation == someScreenLocation.ToExactLocation())
{
// Do stuff
}
When I do that, ReSharper flags it with "Impure Method is called for readonly field of value type."
Why is it saying that? And what can I do to make it go away?
It's not pure because it does not return a value dependent only on its input. When the value of X or Y changes so does the return value of ToExactLocation, i.e., its output depends on internal, mutable state.
Additionally, the setters for X or Y in ExactLocation may mutate the input. The getters of ScreenLocation may as well.
someScreenLocation is a readonly field and is a value type. You are calling ToExactLocation on a value, i.e., a readonly field. When you access a reaodnly value type a copy is created as to avoid mutating the value itself. However, your call may mutate that value, which, in many cases, is not what you want as you will be mutating a copy. This is why you get a warning.
In this case, you can ignore it, but I would avoid mutable value types in general.
EDIT:
Let me attempt to simplify...
struct Point
{
int X;
int Y;
bool Mutate() { X++; Y++; }
}
class Foo
{
public readonly Point P;
Foo()
{
P = new Point();
P.Mutate(); // impure function on readonly value type
}
}
When Mutate() is called, a copy of P is created and passed along with the method. Any mutation of P's internal state will be irrelevant as it mutates a copy.
One of the conditions of a Pure Method is that its output (return value) is wholly dependent on its input (arguments).
Your .ToExactLocation() method is not pure, because its output depends both on the input arguments and also on the current value of a mutable struct.
Resharper doesn't like this, because mutable structs are bad (don't use them). I expect the error would go away if you either changed your code to use a class instead of a struct or redesigned the struct so the the .X and .Y members could only be set by the constructor.
Reading the answer, I found out that pure functions are necessarily like functions in mathematics. f(x) = x^2 + 2x + 10 will always return 10 if x is 0.
So ToExactLocation() must return the same values each time it is called, regardless changes to object since initial creation, for it to be called "pure".
There are 2 meaning of "pure function": one theoretical (no side effects/no dependency on mutable state) and another is what ReSharper thinks about functions.
From theoretical point of view your function is not pure because it depends on mutable state. Sample:
var someScreenLocation = new ScreenLocation(1,1);
var locationOne = someScreenLocation.ToExactLocation();
var locationTwo = someScreenLocation.ToExactLocation();
someScreenLocation.X = 3;
var locationThree = someScreenLocation.ToExactLocation();
For method to be pure it can change its result only based on input (not at all as in this case since there is no arguments). But you can clearly observe that locationOne and locationTwo are the same (good sign so far), but unfortunately locationThree is different even if the input (arguments to the function) still the same.
You can make it theoretically pure by making X and Y readonly (and adding constructor).
Even after the change ReSharper will still think it is not pure - to convince it you can use Pure attribute to mark it as pure.
Note that ReSharper marks usage of "impure" functions even in constructor of the class with readonly field. Sample below shows ReSharper warnings:
struct Point
{
public int X;
public int Y;
public Point(int x, int y){X = x;Y = y;}
public void Mutate(){X++;}
public Point TheoreticallyPure(){return new Point(1, 1);}
[Pure] public Point MarkedPure(){ return new Point(1, 1);}
}
class WithReadonlyField
{
public readonly Point P;
public WithReadonlyField()
{
P = new Point();
P.TheoreticallyPure(); // impure function on readonly value type
P.MarkedPure(); // return value of pure not used
P.Mutate(); // impure function on readonly value type - modifies P.
P = new Point().MarkedPure(); // ok to modify P multiple times.
}
public void NormalMethod()
{
P.Mutate(); // impure function on readonly value type, no changes to P
}
}
C# allows modification of readonly fields up to the end of constructor, but ReSharper marks usages of all "impure" functions there too (Note that Mutate function in constructor actually changes value of readonly field P, unlike in NormalMethod where it has no effect).
"readonly... assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class"
Most likely this behavior of ReSharper is for consistency and to avoid cases where moving perfectly valid code changes behavior completely.
It would be better to model this as a static method (on either class) and would get rid of the impure warning. Explanation omitted, as the other answers covers the why already.
Example:
public static ExactLocation ToExactLocation(ScreenLocation loc)
{
return new ExactLocation {X = loc.X, Y = loc.Y};
}
or use an extension method
public static ExactLocation ToExactLocation(this ScreenLocation loc)
{
return new ExactLocation {X = loc.X, Y = loc.Y};
}
Not really sure about the cause, and I'd put this as a comment if it would format correctly...
Wouldn't you want something like:
var someScreenLocation = MethodThatGivesAScreenLocation();
if (DestinationLocation.X == someScreenLocation.ToExactLocation().X &&
DestinationLocation.Y == someScreenLocation.ToExactLocation().Y)
{
// Do stuff
}

Why does setting the property in the constructor of a struct not work?

I have following code which is not allowed (error below), why?
struct A
{
private int b;
public A(int x)
{
B = x;
}
public int B
{
get { return b; }
set { b=value; }
}
}
I receive the following error:
The 'this' object cannot be used before all of its fields are assigned
to Field 'Test.x' must be fully assigned before control is returned
to the caller
A struct's variables all have to be definitely assigned before you can use any methods or properties. There are two possible fixes here:
1) You can explicitly call the parameterless constructor:
public A(int x) : this()
{
B = x;
}
2) You can use the field instead of the property:
public A(int x)
{
b = x;
}
Of course the second option only works in your current form - you have to use the first option if you want to change your struct to use an automatic property.
However, importantly, you now have a mutable struct. This is almost always a very bad idea. I would strongly urge you to use something like this instead:
struct A
{
private readonly int b;
public A(int x)
{
b = x;
}
public int B { get { return b; } }
}
EDIT: More details of why the original code doesn't work...
From section 11.3.8 of the C# spec:
If the struct instance constructor doesn't specify a constructor initializer, the this variable corresponds to an out parameter of the struct type
Now initially that won't be definitely assigned, which means you can't execute any member function (including property setters) until all the firsts of the struct being constructed have been definitely assigned. The compiler doesn't know or try to take account of the fact that the property setter doesn't try to read from another field. It's all in aid of avoiding reading from fields which haven't been definitely assigned.
Change your constructor to:
public A(int x) :
this()
{
B = x;
}
As to "why", refer to 11.3.8 Constructors and 5.3 Definite assignment.

Categories

Resources