-
Notifications
You must be signed in to change notification settings - Fork 676
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Clarify confusing wording in Classes > Instance variables #5849
Conversation
Visit the preview URL for this PR (updated for commit ad8a59b): |
@@ -11,6 +11,6 @@ class Point { | |||
// OK, can access `this` in `late` initializer: | |||
late double? z = this.x; | |||
|
|||
// OK, `this.fieldName` is a parameter declaration, not an expression: | |||
// OK, parameter declarations can access `this` because they're not expressions: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I liked the original better
These initializing formal parameters are not accessing this
. It's just that their syntax contains the word this
, which is used for its similarity to a variable initializer in the initializer list (which can be written as this.x = y
, and that this
is also not accessing anything, it's just a way to denote the variables that it's initializing.)
In short: this this.x
is OK because it's not accessing the object being created, the this
is part of a parameter declaration, it's not an expression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the difference can be seen as small. However, I also think the difference is important.
It's a little bit like the distinction between i = 1;
as it occurs in the declaration var i = 1;
vs. as it occurs in the expression statement i = 1;
. It's exactly the same text, but it is a completely different underlying structure. In the declaration, i
introduces a variable declaration into the current scope; in the statement, i
is a reference to a variable or setter which is looked up in the enclosing scopes. In the declaration, the static type of the right hand side is used to infer a declared type for the new variable; in the statement, it is checked that the static type of the right hand side is assignable to the assignment target on the left hand side. The differences are deep and detailed because those two occurrences of i = 1
are just not the same thing.
The same is true for this.fieldName
when it occurs as an expression and when it occurs as a parameter declaration.
I think it's helpful to readers to denote the actual underlying structure explicitly, especially in situations where there is a clash with some other underlying structure. In the given situation, the whole point we're trying to make is that the rules that apply to the expression this.fieldName
(for instance, when it occurs as an initializing expression in a late instance variable declaration) are simply irrelevant to the parameter declaration this.fieldName
.
So the parameter declaration does not contain the word this
as a subexpression, and hence we're not "accessing this
" in a way which is comparable to an expression evaluation at the point where the word this
is encountered. Instead, the parameter declaration this.fieldName
contains the text this.
as a kind of infrastructure with no meaning in itself, just like the word for
in a for
statement. There is no "thing" at run time that corresponds to the word for
in that for
statement, we just put the word for
at the beginning of a for
statement because that allows us to recognize the entire for
statement as such. So you can't say 1 + for
or for.toString
because for
is a fixed syntactic element in a bigger structure (the for
statement as a whole), it isn't a "thing" in its own right.
This is important because the semantics of an initializing formal like this.fieldName
is narrow and specific. We are going to store the actual argument in the memory cells representing the instance variable fieldName
of the object which is denoted by this
in an expression, but we don't have the freedom that actual expressions have. For instance, we can't declare a parameter as this.fieldName.methodName(42).otherFieldName
or as someOtherObject.fieldName
, which would be perfectly fine as expressions (assuming that the types match up such that methodName
exists, etc).
So if we're saying "this.fieldName
is a parameter declaration" then we have explicitly and directly indicated the nature of this particular occurrence of the text this.fieldName
.
In contrast, if we're saying "parameter declarations can access this
" then we have blurred the line between expressions and parameter declarations because it sounds like the parameter declaration can do expression-like things such as "accessing this
". That's the reason why the previous version of the text avoids talking about that occurrence of this.
as an "access". It's just infrastructure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you both for the explanations, really interesting stuff!
Since the original made more sense and since the issue is just a matter of confusion over fieldName
, I think something like this might make it clearer that there is no missing field fieldName
and that it's just a place holder:
// OK, `this.<field>` is a parameter declaration, not an expression:
Or
// OK, `this.x` and `this.y` are parameter declarations, not expressions:
I think the latter is clearest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Fixes #5824