| Thread overview | |||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
September 03, 2010 this as lvalue? | ||||
|---|---|---|---|---|
| ||||
I wouldn't have thought of "this" representing an lvalue. However, the following absurdity compiles and executes flawlessly. Just don't uncomment the assignment to y.i!
class Yikes
{
int i;
this() { this = null; }
}
void main()
{
auto y = new Yikes();
// y.i = 0;
}
Is this a bug in the compiler (v.2.047)? Am I missing something in thinking it shouldn't be?
| ||||
September 03, 2010 Re: this as lvalue? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to JMRyan | JMRyan: > Is this a bug in the compiler (v.2.047)? Am I missing something in thinking it shouldn't be? I think it's not a bug. It's not a common need, but a method may way want to swap this with another. In Phobos this is done on a struct, see: http://www.dsource.org/projects/phobos/browser/trunk/phobos/std/stdio.d#L324 Bye, bearophile | |||
September 03, 2010 Re: this as lvalue? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to JMRyan | On Friday 03 September 2010 13:22:51 JMRyan wrote:
> I wouldn't have thought of "this" representing an lvalue. However, the following absurdity compiles and executes flawlessly. Just don't uncomment the assignment to y.i!
>
> class Yikes
> {
> int i;
> this() { this = null; }
> }
>
>
> void main()
> {
> auto y = new Yikes();
> // y.i = 0;
> }
>
> Is this a bug in the compiler (v.2.047)? Am I missing something in
> thinking it shouldn't be?
Of course, this is an lvalue.
1. Think about a struct for a moment, rather than a class. It's a value type. Assigning to this inside a struct would change the struct's value. In some circumstances, it would make perfect sense to do this. Assigning it to the struct's init property to reset it would be a prime example.
2. Think about what a member function _really_ looks like. The member function printM() in this class here
class A
{
int _x;
void printMe()
{
writeln(x);
}
}
really looks like this
void printMe(A this, printMe())
{
writeln(this.x);
}
If you were to set this to null in printMe(), what would it do? Nothing. You just set a function parameter to null. Sure, after that, this be null _within that function_, but it shouldn't be null after that that because the actual object that this points to still exists, and when its reference gets passed to other member functions, those won't be null, because you just set the local variable to null. For instance, this program runs just fine:
import std.stdio;
class A
{
int _x;
this(int x)
{
_x = x;
}
void print()
{
writeln(_x);
}
void nullifyMe()
{
this = null;
}
}
void main()
{
auto a = new A(13);
a.print();
a.nullifyMe();
a.print();
}
It prints
13
13
Now, _your_ program bombs. However, I believe that that's because you assigned null to this in the _constructor_. My guess is that internally, your constructor looks something like this:
Yikes this(Yikes this)
{
this = null;
return this;
}
When this is called, its member variables (namely i) have been initialized, and its initial state is passed to the constructor to further do whatever stuff that you want your constructor to do. It then likely return null, which is what you get from new() and is what is assigned to your local variable y. So, y is then null. The Yikes object that you just created still exists. It's floating around in memory. It's just that you can't get at it. If you try this instead:
import std.stdio;
Yikes global;
class Yikes
{
int i;
this() { global = this; this = null; }
}
void main()
{
auto y = new Yikes();
global.i = 1;
writeln(global.i);
}
it works and prints 1. You could even get rid of the "auto y = " part.
So, this is most definitely an lvalue. It's a bit stupid to assign null to it - especially in the constructor - but it makes perfect sense that it works. And in some circumstances, it makes perfect sense to do so (though not with classes since all it would ever affect would be the local variable and any member functions that called from that member function).
- Jonathan M Davis
| |||
September 03, 2010 Re: this as lvalue? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | On 9/3/10 16:03 CDT, bearophile wrote:
> JMRyan:
>> Is this a bug in the compiler (v.2.047)? Am I missing something in
>> thinking it shouldn't be?
>
> I think it's not a bug. It's not a common need, but a method may way want to swap this with another. In Phobos this is done on a struct, see:
> http://www.dsource.org/projects/phobos/browser/trunk/phobos/std/stdio.d#L324
>
> Bye,
> bearophile
For classes this must be an rvalue.
Andrei
| |||
September 03, 2010 Re: this as lvalue? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Friday 03 September 2010 14:22:46 Andrei Alexandrescu wrote:
> On 9/3/10 16:03 CDT, bearophile wrote:
> > JMRyan:
> >> Is this a bug in the compiler (v.2.047)? Am I missing something in
> >> thinking it shouldn't be?
> >
> > I think it's not a bug. It's not a common need, but a method may way want to swap this with another. In Phobos this is done on a struct, see: http://www.dsource.org/projects/phobos/browser/trunk/phobos/std/stdio.d# L324
> >
> > Bye,
> > bearophile
>
> For classes this must be an rvalue.
>
> Andrei
There is no value in this being assignable in a class, but at the lower level of how the functions are actually declared underneath (with them taking this as an argument), it makes perfect sense that it would work. It certainly wouldn't be bad to disallow it though, since it's pointless and is just going to cause bugs, though generally not as bad as the ones in the OP's example (since he assigned to this in the constructor).
Still, I don't know how you could make it a true rvalue. You'd need the ability to pass a const reference to non-const data to do that, and D doesn't allow for that. The invisible this parameter, being a reference, is going to suffer from all of the issues with const that have been oft-discussed (though, generally what people want is a non-const reference to const data rather than a const reference to non-const data like you would need for this).
- Jonathan M Davis
| |||
September 03, 2010 Re: this as lvalue? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On 9/3/10 16:33 CDT, Jonathan M Davis wrote:
> Still, I don't know how you could make it a true rvalue.
It's very simple - make "this" the result of a hypothetical function call.
Andrei
| |||
September 03, 2010 Re: this as lvalue? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Friday 03 September 2010 14:38:27 Andrei Alexandrescu wrote:
> On 9/3/10 16:33 CDT, Jonathan M Davis wrote:
> > Still, I don't know how you could make it a true rvalue.
>
> It's very simple - make "this" the result of a hypothetical function call.
>
> Andrei
Ah, that would do it. Though you wouldn't want to _actually_ do that in the generated code given how poor the inliner is.
- Jonathan M Davis
| |||
September 03, 2010 Re: this as lvalue? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu:
> For classes this must be an rvalue.
OK. Why?
Bye,
bearophile
| |||
September 03, 2010 Re: this as lvalue? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | On 9/3/10 17:16 CDT, bearophile wrote:
> Andrei Alexandrescu:
>> For classes this must be an rvalue.
>
> OK. Why?
If you could change this from within a method you'd pretty much ruin everything about object orientation.
Andrei
| |||
September 03, 2010 Re: this as lvalue? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Friday 03 September 2010 15:18:25 Andrei Alexandrescu wrote:
> On 9/3/10 17:16 CDT, bearophile wrote:
> > Andrei Alexandrescu:
> >> For classes this must be an rvalue.
> >
> > OK. Why?
>
> If you could change this from within a method you'd pretty much ruin everything about object orientation.
>
> Andrei
On the bright side, except for the constructor, it should only change what happens in that one member function and anything member functions that are called from it (or called from something that's called from it), so it's not like it's going to break everything.
But really, it shouldn't work. There's no value to it. It just allows for bugs, even if you have to work at it to get them. I'm 99% certain that you can't reassign this in C++, C#, or Java, and I'd sooner expect someone to be surprised that it's possible that actually want to be able to. It's useful for structs, but for classes, it has no value. And as you say, it effectively breaks object orientation.
- Jonathan M Davis
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply