-
-
Notifications
You must be signed in to change notification settings - Fork 379
improve definition of assign expression behaviour #2881
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
Conversation
Thanks for your pull request and interest in making D better, @Alexibu! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. |
@ibuclaw @kinke @WalterBright do you guys agree? |
spec/expression.dd
Outdated
is exactly the same as: | ||
|
||
-------------- | ||
a = a op b |
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.
what if a
has side-effects?
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.
Isn't that the point? Whether or not a
has side effects, it would be evaluated once:
exp1 op= exp2;
=>
{
auto tmp1 = exp1;
auto tmp2 = exp2;
tmp1 = tmp1 op tmp2;
}
That is, unless exp1
resolves to a type with custom opAssign
, or opOpAssign
.
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.
what if
a
has side-effects?
Then in most cases, a
can't be an lvalue in an op= expression, unless the result of a
is a stable reference (iirc, *a op= b
)
spec/expression.dd
Outdated
a op= b | ||
-------------- | ||
|
||
is exactly the same as: |
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.
@thewilsonator I suppose this would be a more accurate wording:
is exactly the same as: | |
is rewritten to: |
Which would address the question of side effects.
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.
Is it though? I thought it would be rewritten to auto [ref] __tmp = a; __tmp = __tmp op b;
, the number of evaluation is important.
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.
Ah, I thought that was clear. Yeah, I guess it makes sense to specify this more accurately.
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.
One exception to that rewrite though is array concatenation.
a ~= b
// a = a ~ b;
Because evaluating a
changes its underlying size, so it would instead be conceptually
auto __tmp = b
extend(&a)[oldlen .. newlen] = __tmp;
Unless I'm failing to see a disconnect between the evaluation of a
and extending its size for the concatenation.
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.
Why does evaluating a
change its size ? Isn't the size change part of the execution of ~=
, not the evaluation of operands ?
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.
Because in a op= b
, operand a
can only be evaluated once. Separating the size change from the evaluation means you'll have to compute it twice.
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.
Is it though?
Nope, this is definitely wrong, see e.g. https://github.com/dlang/dmd/blob/a9e5b0db723f8edaf80df28f93257edf06d3f17b/test/runnable/evalorder.d#L59-L61.
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 translated that test for eval order to the ~=
operator:
auto mul11ret3(T)(ref T s)
{
s ~= 11;
return [3];
}
void main()
{
static auto test3(int[] val) { (val ~= 7) ~= mul11ret3(val); return val; }
assert(test3([2]) == [2,7,11,3]);
}
DMD fails with [2,11,7]
gdc 10.2 fails with core.exception.OutOfMemoryError.
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 translated that test for eval order to the
~=
operator:
gdc 10.2 fails with core.exception.OutOfMemoryError.
Excellent, that means garbage is passed as the destination slot in append(&dst, mul11ret3(val))
instead of the address to val
.
cc @JohanEngelen I know we had a couple of bugs w.r.t. this or sometime similar in LDC. |
So a little further down the page, you already have a section on assignment operator expressions, would it be better just to clarify the wording of that passage to avoid redundancy? |
The part about |
See: #1429 |
Yes. In particular, see @andralex 's comment:
This is a much clearer specification, as the text in this PR was rather baffling to me, and I had to study the examples to see what was going on. |
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.
See my comment.
Closed PR because #1429 will clarify. |
The spec appears to not specify that an assign expression must be evaluated after it's operands.
It also helps to define that it must do the same thing as an asignment of the binary operator.
I believe this is the intention of the language, so that it has the same operator behaviour as C++.
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97843