-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Spec for ref local reassignment. #963
Conversation
So you could reassign Hadn't thought about that; but makes sense as is the chain For writable ref int currentRef = ref oldRef;
ref currentRef = ref newRef; // reassign For As per declaration+init? ref readonly int currentRef = ref readonly oldRef;
ref readonly currentRef = ref readonly newRef; // reassign Or is ref readonly int currentRef = ref readonly oldRef;
ref currentRef = ref readonly newRef; // reassign
ref currentRef = ref newRef; // auto-convert writable ref to readonly ref in reassign? |
@benaadams Per OP the reassignment the syntax is |
The left side being
That works |
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
I'd suggest adding an example or two.
@benaadams It's not obvious, but I think the |
|
||
When the left operand binds to an `out` parameter, it is an error if that `out` parameter has not been definitely assigned at at the beginning of the ref assignment operator. | ||
|
||
If the left operand is a writeable ref (i.e. it designates anything other than a `ref readonly` local or `in` parameter), then the right operand may not be a `ref readonly` local or parameter. |
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’d just say “must be a writeable lvalue”. That would cover fields (except readonly), ref/val locals (except readonly), ref ternaries (when both branches are writeable), etc...
We state same requirements when passing by ‘ref’.
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.
Will do.
@@ -0,0 +1,27 @@ | |||
# Ref Local Reassignment | |||
|
|||
In C# 7.2, we add support for rebinding the referent of a ref local variable or a ref parameter. |
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.
There is nothing technically wrong with rebinding ref parameters. I guess - why not. Similarly as we allow assigning to byval params.
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.
Could it cause confusion? I assume it would be detaching from the passed ref; but it may be assumed that its changing the passed ref (in the callee) rather than just the local parameter ref?
Unless it actually is ofc... :)
i.e.
I assume its changing a byval pointer (copy of pointer to reference) p*
or &val
the param itself
rather than a byref pointer (reference to pointer to reference) &p*
or p**
the callee's passed reference
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.
Caller will see no effects from/after param rebinding by callee. But that could be the reason why callee does this...
It will not be the most common feature to use - like assignments to ordinary parameters, but nothing is wrong with it technically.
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.
Maybe I'm just over thinking it :)
People don't think changing a non-ref param changes it in callee and its not a ref ref
or &ref
type.
Also is probably handy so you have a starter ref
that you then change rather than having to introduce a local copy that you then modify.
e.g.
ref T FindFrom(ref T current)
{
ref var local = ref current;
while (!local.IsCorrect)
{
local = ref _array[local.Next];
}
return ref local;
}
would be better as
ref T FindFrom(ref T current)
{
while (!current.IsCorrect)
{
current = ref _array[current.Next];
}
return ref current;
}
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.
Though in practice it would be more like
static T NotFound;
T[] _array;
ref T FindFrom(ref T current, out bool success)
{
var maxSteps = _array.Length;
success = true;
do
{
if (current.IsCorrect)
{
return ref current;
}
else if (current.Next < 0)
{
break;
}
current = ref _array[current.Next];
maxSteps--;
} while (maxSteps > 0);
success = false;
return ref NotFound;
}
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.
Also need to clarify position on rebinding of ‘this’ in struct methods. In theory all the arguments for allowing rebinding of ref parameters apply to ‘this’ in a struct.
So is the ‘this = ref something’ allowed in a struct method?
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.
Just as "this" in a class acts like a parameter, it cannot be assigned, "this" in a struct acts like a ref parameter, but cannot be rebound. I'll add that to the spec.
|
||
The safety rules for this operator are: | ||
|
||
- For a ref reassignment `e1 = ref e2`, the *ref-safe-to-escape* of `e2` must be at least as wide a scope as the *ref-safe-to-escape* of `e1`. |
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.
When ref local declared with no initializer it has the “returnable” level, right?
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.
If I recall correctly, we decided to defer supporting "ref local declared with no initializer" to some future revision.
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.
That would work too.
Although I think the need will arise quickly. Perhaps as soon as we start testing this :)
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
Some clarifying suggestions.
Here is a proposed spec for ref local reassignment
/cc @dotnet/ldm @dotnet/roslyn-compiler @agocke