Why is assignment to 'this' not allowed in java?
Asked Answered
P

7

24

The error I get from the compiler is "The left hand side of an assignment must be a variable". My use case is deep copying, but is not really relevant.

In C++, one can assign to *this.

The question is not how to circumvent assignment to this. It's very simple, but rather what rationale is there behind the decision not to make this a variable.

Are the reasons technical or conceptual?

My guess so far - the possibility of rebuilding an Object in a random method is error-prone (conceptual), but technically possible.

Please restrain from variations of "because java specs say so". I would like to know the reason for the decision.

Prefecture answered 2/11, 2011 at 11:32 Comment(6)
Just because in C++ it is possible to alter this, it doesn't mean you should to it. Creating a new variable would do the same, without causing any mess.Artema
Why the downvote? Is there anything unconstructive?Prefecture
I wonder what the semantics of this = xy; should be. What do you think it should do?Manchineel
@Hanno provided xy is of the right type, the reference of this would be set to xy, making the "original" object gc-eligiblePrefecture
Altering all other references to this object throughout the application at the same time? - Note that if this actually was a variable it would be private to each object and assigning a value to it would not be visible to the environment.Manchineel
@Hanno you're right. It would only make sense if you could replace the object without changing it's reference (like it's done in C++)Prefecture
P
15

In C++, one can assign to *this

Yes, but you can't do this = something in C++, which I actually believe is a closer match for what you're asking about on the Java side here.

[...] what rationale is there behind the decision not to make this a variable.

I would say clarity / readability.

this was chosen to be a reserved word, probably since it's not passed as an explicit argument to a method. Using it as an ordinary parameter and being able to reassign a new value to it, would mess up readability severely.

In fact, many people argue that you shouldn't change argument-variables at all, for this very reason.

Are the reasons technical or conceptual?

Mostly conceptual I would presume. A few technical quirks would arise though. If you could reassign a value to this, you could completely hide instance variables behind local variables for example.

My guess so far - the possibility of rebuilding an Object in a random method is error-prone (conceptual), but technically possible.

I'm not sure I understand this statement fully, but yes, error prone is probably the primary reason behind the decision to make it a keyword and not a variable.

Powerful answered 2/11, 2011 at 11:46 Comment(1)
Clearest answer so far. Thank youPrefecture
M
5

because this is final,

this is keyword, not a variable. and you can't assign something to keyword. now for a min consider if it were a reference variable in design spec..and see the example below

and it holds implicit reference to the object calling method. and it is used for reference purpose only, now consider you assign something to this so won't it break everything ?

Example

consider the following code from String class (Note: below code contains compilation error it is just to demonstrate OP the situation)

   public CharSequence subSequence(int beginIndex, int endIndex) {
      //if you assign something here
       this = "XYZ"  ;
       // you can imagine the zoombie situation here
      return this.substring(beginIndex, endIndex);
   }
Malachi answered 2/11, 2011 at 11:34 Comment(9)
like in C++, maybe? i'm not aware of how it is done, but it is apparently possible. I can easily imagine situation where it would not break anything. Maybe you could elaborate on the technical side?Prefecture
@JigarJoshi, from where did you get that this is final? I've never heard this before.Powerful
this isn't even a variable. It's a keyword.Terris
@Xavi yes <!---------------->Malachi
@Jigar IMO the example does not hold - it is perfectly legal (even if wrong) to reassign a variable in it's getter and get unexpected results. I'm not arguing in favor of reassigning this, just being curious.Prefecture
If this was indeed designed to be a variable, your snippet would type-check, and work as "expected". The question here is why it was not designed to be a variable. Your example (and whole answer) fails to address this completely.Powerful
well if it were the variable and that too non final and we could assign the new reference to it. it would not throw any error/exception but it would break the code. the only thing would be then trust that the method we are calling doesn't change this and the purpose for which this is in Java would not be satisfiedMalachi
If it was a variable, it would (obviously) be a local variable.Powerful
and it would obviously final too :) , your answers describe it well though. thanksMalachi
H
5

Are the reasons technical or conceptual?

IMO, conceptual.

The this keyword is a short hand for "the reference to the object whose method you are currently executing". You can't change what that object is. It simply makes no sense in the Java execution model.

Since it makes no sense for this to change, there is no sense in making it a variable.

(Note that in C++ you are assigning to *this, not this. And in Java there is no * operator and no real equivalent to it.)


If you take the view that you could change the target object for a method in mid flight, then here are some counter questions.

  • What is the use of doing this? What problems would this (hypothetical) linguistic feature help you solve ... that can't be solved in a more easy-to-understand way?

  • How would you deal with mutexes? For instance, what would happen if you assign to this in the middle of a synchronized method ... and does the proposed semantic make sense? (The problem is that you either end up executing in synchronized method on an object that you don't have a lock on ... or you have to unlock the old this and lock the new this with the complications that that entails. And besides, how does this make sense in terms of what mutexes are designed to achieve?)

  • How would you make sense of something like this:

    class Animal {
        foo(Animal other) {
           this = other;
           // At this point we could be executing the overridden
           // Animal version of the foo method ... on a Llama.  
        }
    }
    
    class Llama {
        foo(Animal other) {
        }
    }
    

    Sure you can ascribe a semantic to this but:

    • you've broken encapsulation of the subclass in a way that is hard to understand, and
    • you've not actually achieved anything particularly useful.

If you try seriously to answer these questions, I expect you'll come to the conclusion that it would have been a bad idea to implement this. (But if you do have satisfactory answers, I'd encourage you to write them up and post them as your own Answer to your Question!)

But in reality, I doubt that the Java designers even gave this idea more than a moment's consideration. (And rightly so, IMO)


The *this = ... form of C++ is really just a shorthand for a sequence of assignments of the the attributes of the current object. We can already do that in Java ... with a sequence of normal assignments. There is certainly no need for new syntax to support this. (How often does a class reinitialize itself from the state of another class?)

I note that you commented thus:

I wonder what the semantics of this = xy; should be. What do you think it should do? – JimmyB Nov 2 '11 at 12:18

Provided xy is of the right type, the reference of this would be set to xy, making the "original" object gc-eligible - kostja Nov 2 '11 at 12:24

That won't work.

  1. The value of this is (effectively) passed by value to the method when the method is invoked. The callee doesn't know where the this reference came from.

  2. Even if it did, that's only one place where the reference is held. Unless null is assigned in all places, the object cannot be eligible of garbage collection.

Ignoring the fact that this is technically impossible, I do not think that your idea would be useful OR conducive to writing readable / maintainable code. Consider this:

public class MyClass {
    public void kill(MyClass other) {
        this = other;
    }
}

MyClass mine = new MyClass();

....

mine.kill(new MyClass());

// 'mine' is now null!

Why would you want to do that? Supposing that the method name was something innocuous rather than kill, would you expect the method to be able to zap the value of mine?

I don't. In fact, I think that this would be a misfeature: useless and dangerous.

Even without these nasty "make it unreachable" semantics, I don't actually see any good use-cases for modifying this.

Hukill answered 2/11, 2011 at 11:50 Comment(2)
Thanks, Stephen. After the edit, you answer makes great sense to me. The assignment to *this in C++ is different semantically, but I can't even figure out an answer to the second and third of your questions for the C++ variant. For the first one - "deep copying an object in the copy constructor, using a utility that returns a copy", but of course there are many other ways to accomplish that.Prefecture
For the second question; The proposed semantics would (I'm assuming) be that this had the behavior of a local variable, and the language already allows you to synchronize on non-final variables, so I see no surprises there. For the third question: Again, assume you take that exact code, replace this with this2, and in the top you do Animal this2 = this;, and there you have the proposed semantics. (Yes, it would be hard to read.)Powerful
E
3

this isn't even a variable. It's a keyword, as defined in the Java Language Specification:

When used as a primary expression, the keyword this denotes a value that is a reference to the object for which the instance method was invoked (§15.12), or to the object being constructed

So, it's not possible as it's not possible to assign a value to while.

Empurple answered 2/11, 2011 at 11:42 Comment(0)
A
1

The this in Java is a part of the language, a key word, not a simple variable. It was made for accessing an object from one of its methods, not another object. Assigning another object to it would cause a mess. If you want to save another objects reference in your object, just create a new variable.

The reason is just conceptual. this was made for accessing an Object itself, for example to return it in a method. Like I said, it would cause a mess if you would assign another reference to it. Tell me a reason why altering this would make sense.

Artema answered 2/11, 2011 at 11:38 Comment(2)
The question is rather about the rationale, not about the specsPrefecture
I can only provide a use case, not a reason - deep copying an object in the copy constructor, using a utility that returns a copy. Sure you could clone outside the ctor, so no valid reason there. I was just curiousPrefecture
H
1

Assigning to (*this) in C++ performs a copy operation -- treating the object as a value-type.

Java does not use the concept of a value-type for classes. Object assignment is always by-reference.

To copy an object as if it were a value-type: How do I copy an object in Java?


The terminology used for Java is confusing though: Is Java “pass-by-reference” or “pass-by-value”

Answer: Java passes references by value. (from here)

In other words, because Java never treats non-primitives as value-types, every class-type variable is a reference (effectively a pointer).

So when I say, "object assignment is always by-reference", it might be more technically accurate to phrase that as "object assignment is always by the value of the reference".

The practical implication of the distinction drawn by Java always being pass-by-value is embodied in the question "How do I make my swap function in java?", and its answer: You can't. Languages such as C and C++ are able to provide swap functions because they, unlike Java, allow you to assign from any variable by using a reference to that variable -- thus allowing you to change its value (if non-const) without changing the contents of the object that it previously referenced.

It could make your head spin to try to think this all the way through, but here goes nothing...

  • Java class-type variables are always "references" which are effectively pointers.
  • Java pointers are primitive types.
  • Java assignment is always by the value of the underlying primitive (the pointer in this case).
  • Java simply has no mechanism equivalent to C/C++ pass-by-reference that would allow you to indirectly modify a free-standing primitive type, which may be a "pointer" such as this.

Additionally, it is interesting to note that C++ actually has two different syntaxes for pass-by-reference. One is based on explicit pointers, and was inherited from the C language. The other is based on the C++ reference-type operator &. [There is also the C++ smart pointer form of reference management, but that is more akin to Java-like semantics -- where the references themselves are passed by value.]

Note: In the above discussion assign-by and pass-by are generally interchangeable terminology. Underlying any assignment, is a conceptual operator function that performs the assignment based on the right-hand-side object being passed in.


So coming back to the original question: If you could assign to this in Java, that would imply changing the value of the reference held by this. That is actually equivalent to assigning directly to this in C++, which is not legal in that language either.

In both Java and C++, this is effectively a pointer that cannot be modified. Java seems different because it uses the . operator to dereference the pointer -- which, if you're used to C++ syntax, gives you the impression that it isn't one.

You can, of course, write something in Java that is similar to a C++ copy constructor, but unlike with C++, there is no way of getting around the fact that the implementation will need to be supplied in terms of an explicit member-wise initialization. [In C++ you can avoid this, ultimately, only because the compiler will provide a member-wise implementation of the assignment operator for you.]

The Java limitation that you can't copy to this as a whole is sort-of artificial though. You can achieve exactly the same result by writing it out member-wise, but the language just doesn't have a natural way of specifying such an operation to be performed on a this -- the C++ syntax, (*this) doesn't have an analogue in Java. And, in fact, there is no built-in operation in Java that reassigns the contents of any existing object -- even if it's not referred to as this. [Such an operation is probably more important for stack-based objects such as are common in C++.]


Regarding the use-case of performing a deep copy: It's complicated in Java.

For C++, a value-type-oriented language. The semantic intention of assignment is generally obvious. If I say a=b, I typically want a to become and independent clone of b, containing an equal value. C++ does this automatically for assignment, and there are plans to automate the process, also, for the comparison.

For Java, and other reference-oriented languages, copying an object, in a generic sense, has ambiguous meaning. Primitives aside, Java doesn't differentiate between value-types and reference-types, so copying an object has to consider every nested class-type member (including those of the parent) and decide, on a case-by-case basis, if that member object should be copied or just referenced. If left to default implementations, there is a very good chance that result would not be what you want. Comparing objects for equality in Java suffers from the same ambiguities.

Based on all of this, the answer to the underlying question: why can't I copy an object by some simple, automatically generated, operation on this, is that fundamentally, Java doesn't have a clear notion of what it means to copy an object.


One last point, to answer the literal question:

What rationale is there behind the decision not to make this a variable?

It would simply be pointless to do so. The value of this is just a pointer that has been passed to a function, and if you were able to change the value of this, it could not directly affect whatever object, or reference, was used to invoke that method. After all, Java is pass-by-value.

Harpist answered 23/5, 2018 at 17:24 Comment(5)
C++ passes this by value also.Harpist
Language comparison on Wikipedia: value type and reference typeHarpist
Due the ambiguities discussed above, comparing collections may do the wrong thing if you haven't implemented hashCode() and equals() for the contained class. This little gotcha is what inspired my deep interest in Java's assignment and comparison operations.Harpist
How do you make a deep copy of an objectHarpist
In Java, even 'String' is not a value-type. How many bugs have been introduced because the obvious method of simple string comparison turns out to be incorrect? I'm sure that I have introduced this error many times over the years. if ( a == "hello" ) will never do anything useful -- why does this even compile? I wonder if this language choice is inevitable given Java's pass-by-value-of-reference semantics.Harpist
H
0

Assigning to *this in C++ isn't equivalent to assigning this in Java. Assigning this is, and it isn't legal in either language.

Hertzog answered 3/11, 2011 at 1:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.