Changing the 'this' variable of value types
C#ThisValue TypeC# Problem Overview
Apparently you can change the this
value from anywhere in your struct (but not in classes):
struct Point
{
public Point(int x, int y)
{
this = new Point();
X = x; Y = y;
}
int X; int Y;
}
I've neither seen this before nor ever needed it. Why would one ever want to do that? Eric Lippert reminds us that a feature must be justified to be implemented. What great use case could justify this? Are there any scenarios where this is invaluable? I couldn't find any documentation on it1.
Also, for calling constructors there is already a better known alternative syntax, so this feature is sometimes redundant:
public Point(int x, int y)
: this()
{
X = x; Y = y;
}
I found this feature in an example in Jeffrey Richter's CLR via C# 4th edition.
1) Apparently it is in the C# specification.
C# Solutions
Solution 1 - C#
Good question!
Value types are, by definition, copied by value. If this
was not actually an alias to a storage location then the constructor would be initializing a copy rather than initializing the variable you intend to initialize. Which would make the constructor rather less useful! And similarly for methods; yes, mutable structs are evil but if you are going to make a mutable struct then again, this
has to be the variable that is being mutated, not a copy of its value.
The behaviour you are describing is a logical consequence of that design decision: since this
aliases a variable, you can assign to it, same as you can assign to any other variable.
It is somewhat odd to assign directly to this
like that, rather than assigning to its fields. It is even more odd to assign directly to this
and then overwrite 100% of that assignment!
An alternative design which would avoid making this
an alias to the receiver's storage would be to allocate this
off the short-term storage pool, initialize it in the ctor, and then return it by value. The down side of that approach is that it makes copy elision optimizations pretty much impossible, and it makes ctors and methods weirdly inconsistent.
Solution 2 - C#
> Also, I couldn't find any documentation on it.
Did you try looking in the C# spec? Because I can find documentation on it (7.6.7):
> - When this
is used in a primary-expression within an instance constructor of a struct, it is classified as a variable. The type of the variable is the instance type (§10.3.1) of the struct within which the usage occurs, and the variable represents the struct being constructed. The this
variable of an instance constructor of a struct behaves exactly the same as an out
parameter of the struct type—in particular, this means that the variable must be definitely assigned in every execution path of the instance constructor.
>
> - When this
is used in a primary-expression within an instance method or instance accessor of a struct, it is classified as a variable. The type of the variable is the instance type (§10.3.1) of the struct within which the usage occurs.
> - If the method or accessor is not an iterator (§10.14), the this
variable represents the struct for which the method or accessor was invoked, and behaves exactly the same as a ref
parameter of the struct type.
> - If the method or accessor is an iterator, the this
variable represents a copy of the struct for which the method or accessor was invoked, and behaves exactly the same as a value parameter of the struct type.
As to a use case for it, I can't immediately think of many - about the only thing I've got is if the values you want to assign in the constructor are expensive to compute, and you've got a cached value you want to copy into this
, it might be convenient.
Solution 3 - C#
A storage location of value type in an aggregation of storage locations comprising that type's public and private fields. Passing a value type an an ordinary (value) parameter will physically and semantically pass the contents of all its fields. Passing a value type as a ref
parameter is semantically pass the contents of all its fields, though a single "byref" is used to pass all of them.
Calling a method on a struct is equivalent to passing the struct (and thus all its fields) as a ref
parameter, except for one wrinkle: normally, neither C# nor vb.net will allow a read-only value to be passed as a ref
parameter. Both, however, will allow struct methods to be invoked on read-only values or temporary values. They do this by making a copy of all the struct (and thus all of its fields), and then passing that copy as a ref
parameter.
Because of this behavior, some people call mutable structs "evil", but the only thing that's evil is the fact that neither C# or vb.net defines any attribute to indicate whether a struct member or property should be invokable on things that can't be directly passed by ref
.