Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assign this keyword in C#

Main question is what are the implications of allowing the this keyword to be modified in regards to usefulness and memory; and why is this allowed in the C# language specifications?

The other questions/subparts can be answered or not if choose to do so. I thought answers to them would help clarify the answer to the main question.

I ran across this as an answer to What's the strangest corner case you've seen in C# or .NET?

public struct Teaser
{
    public void Foo()
    {
        this = new Teaser();
    }
}

I've been trying to wrap my head around why the C# language specifications would even allow this. Sub-part 1. is there anything that would justify having this be modifiable? Is it every useful?

One of the comments to that answer was

From CLR via C#: The reason they made this is because you can call the parameterless constructor of a struct in another constructor. If you only want to initialize one value of a struct and want the other values to be zero/null (default), you can write public Foo(int bar){this = new Foo(); specialVar = bar;}. This is not efficient and not really justified (specialVar is assigned twice), but just FYI. (That's the reason given in the book, I don't know why we shouldn't just do public Foo(int bar) : this())

Sub-part 2. I'm not sure I follow that reasoning. Can someone clarify what he meant? Maybe a concrete example of how it would be used?

EDIT (Disregard stack or heap main point is in regards to memory release or garbage collection. Instead of the int[] you could replace that with 262144 public int fields) Also from my understanding structs are created on the stack as opposed to the heap if this struct were to have a 1 Mb byte array field initialized as so

public int[] Mb = new int[262144];

Sub-part 3. does this ever get removed from the stack when Foo is called? To me it seems since the struct never went out of scope it would not be removed from the stack. Don't have time tonight to create a test case but maybe I will for this one tomorrow.

In the below code

Teaser t1 = new Teaser();
Teaser tPlaceHolder = t1;
t1.Foo();

Sub-part 4. Are t1 and tPlaceHolder occupying the same or different address space?

Sorry to bring up a 3 year old post but this one has really got my head scratching.

FYI first question on stackoverflow so if I got something wrong with the question kindly post a comment and I will edit.

After 2 days I'll put a bounty of 50 on this question even if I have a winner chosen in my mind already as I think the answer will require a reasonable amount of work to explain the questions.

like image 618
Dan P Avatar asked Apr 06 '12 02:04

Dan P


People also ask

What is the use of this keyword in C?

There can be 3 main usage of this keyword in C++. It can be used to pass current object as a parameter to another method. It can be used to refer current class instance variable. It can be used to declare indexers.

Can we assign to this pointer?

You can not. "this" is a hidden argument to every member function of a class and its type for an object of Class X is X* const. This clearly means that you can not assign a new vale to "this" as it is defined as a const. You can however modify the value pointed to by this.

Should you use this -> in C++?

While this is a totally subjective question, I think the general C++ community prefers not to have this-> . Its cluttering, and entirely not needed. Some people use it to differentiate between member variables and parameters.


1 Answers

First of all, I think you should start by examining if you're even asking the right question. Perhaps we should be asking, "Why would C# not allow assignment to this in a struct?"

Assigning to the this keyword in a reference type is potentially dangerous: you are overwriting a reference to the object who's method you are running; you could even be doing so within the constructor that is initializing that reference. Its not clear what the behavior of that ought to be. To avoid having to figure that out, since it is not generally useful, it's not allowed by the spec (or compiler).

Assigning to the this keyword in a value type, however, is well defined. Assignment of value types is a copy operation. The value of each field is recursively copied over from right to left side of the assignment. This is a perfectly safe operation on a structure, even in a constructor, because the original copy of the structure is still present, you are just changing its data. It is exactly equivalent to manually setting each field in the struct. Why should the spec or compiler forbid an operation that is well-defined and safe?

This, by the way, answers one of your sub-questions. Value type assignment is a deep copy operation, not a reference copy. Given this code:

Teaser t1 = new Teaser();
Teaser tPlaceHolder = t1;
t1.Foo();

You have allocated two copies of your Teaser structure, and copied the values of the fields in the first into the fields in the second. This is the nature of value types: two types that have identical fields are identical, just like two int variables that both contain 10 are identical, regardless of where they are "in memory".

Also, this is important and worth repeating: careful making assumptions about what goes on "the stack" vs "the heap". Value types end up on the heap all the time, depending on the context in which they are used. Short-lived (locally scoped) structs that are not closed over or otherwise lifted out of their scope are quite likely to get allocated onto the stack. But that is an unimportant implementation detail that you should neither care about nor rely on. The key is that they are value types, and behave as such.

As far as how useful assignment to this really is: not very. Specific use cases have been mentioned already. You can use it to mostly-initialize a structure with default values but specify a small number. Since you are required to set all fields before your constructor returns, this can save a lot of redundant code:

public struct Foo
{
  // Fields etc here.

  public Foo(int a)
  {
    this = new Foo();
    this.a = a;
  }
}

It can also be used to perform a quick swap operation:

public void SwapValues(MyStruct other)
{
  var temp = other;
  other = this;
  this = temp;
}

Beyond that, its just an interesting side-effect of the language and the way that structures and value types are implemented that you will most likely never need to know about.

like image 69
Michael Edenfield Avatar answered Oct 20 '22 22:10

Michael Edenfield