64

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.

Community
  • 1
  • 1
Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157
  • What if the constructors were private? Not saying it's an awesome idea.. but I guess that's one use case. – Simon Whitehead Feb 08 '13 at 02:52
  • It seems like a cheap alternative to an object? – Ross Bush Feb 08 '13 at 02:56
  • 3
    Any question that makes me go, "No way! Let's run this through LinqPad." is an awesome one in my book. – Kirk Woll Feb 08 '13 at 03:04
  • 1
    Seems like a perfect opportunity for @EricLippert to chime in on the justification of this feature. – Jonathon Reinhart Feb 08 '13 at 03:32
  • There is a spectrum, from "clearly desirable behaviour", to "possibly dodgy behaviour that still makes some sense", to "clearly undesirable behaviour". We try to make the latter into warnings or, better, errors. But stuff that is in the middle category you don't want to restrict unless there is a clear way to work around it. - Eric Lippert – Travis Gockel Feb 08 '13 at 03:34
  • 2
    I think I found a single use case. Within a method, you can this to 'zero' the struct. (+1 for posting this, cant believe after 11 years I still learn new c# stuff). Edit: It would be rather pointless to use this in the constructor. – leppie Feb 08 '13 at 04:38
  • Even more evil, you could use this (no pun) to zero any primitive array via a memory mapped struct ;p (But dont do that!) – leppie Feb 08 '13 at 04:40

3 Answers3

54

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.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • But even then `this` could have been made read-only to be consistent with reference types, allowing only assignments to its fields. Is there any use for being able to write to `this` directly, or it is just a somewhat less useful side-effect of treating `this` as an alias? – Daniel A.A. Pelsmaeker Feb 08 '13 at 09:40
  • 1
    @Virtlink For reference types, `readonly` makes the reference read only, but you can still modify its fields. But for value types, there is no reference, so `readonly` actually makes all the fields read only. So your proposal doesn't make much sense. – svick Feb 08 '13 at 10:58
  • @svick First: I didn't mean the `readonly` keyword. Second: `this` in value types is actually `ref this` or `out this` as I understand it, so it is actually a _reference_ (to the storage location of the value type). – Daniel A.A. Pelsmaeker Feb 08 '13 at 11:33
  • @Virtlink So you meant a special kind of read only that doesn't appear anywhere else and forbids you from setting all fields at once, but allows you to set them one by one? Why would something like that be useful? – svick Feb 08 '13 at 12:58
  • 4
    @Virtlink: Suppose the language design team adopted your proposal. What do you propose happens if someone calls `M(out this)` in the ctor? Should `this` be treated as *not a variable* in that case as well? – Eric Lippert Feb 08 '13 at 16:29
  • @EricLippert: I propose the same thing that happens when you try to do that on a reference type: "Cannot pass '' as a ref or out argument because it is read-only". Why would one want to do that? – Daniel A.A. Pelsmaeker Feb 13 '13 at 21:28
  • 2
    @Virtlink: You pass value types as out *because you want them to be initialized by the callee*. Suppose a ctor writer already had a method in hand that initializes a variable of that type correctly; why wouldn't they use it? – Eric Lippert Feb 13 '13 at 22:06
10

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.

Community
  • 1
  • 1
Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • There would actually be a fair number of usage cases for struct members which modify `this`, except that the willingness of C# and vb.net to allow (without any compiler diagnostic) the ineffectual invocation of such methods on read-only struct instances and the lack of any means of tagging which methods and properties can be invoked on read-only instances and which cannot means it's safer to use the comparatively ugly form `StructType.StaticMethod(ref theStruct)`, which the compiler will correctly disallow for read-only structures. – supercat Feb 10 '13 at 23:20
0

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.

supercat
  • 77,689
  • 9
  • 166
  • 211