New Tie-Breaker Rule for Resolving Ambiguity Between Overloads Which Differ By Refness of Arguments
- Dominant language
- No language data
- Stars
- 328
- Forks
- 71
- PR merge metrics
- No merged PRs in 30d
Description
# Scenario
Unlike C#, VB doesn't use a keyword at the call-site to denote whether an argument is being passed `ByRef` or not. That's pretty reasonable given that ByRef was the default in VB6 and even C# drops the requirement to use `ref` when inter-operating with COM.
All that said, despite not being CLS-compliant from time to time one sees an API which includes overloads which differ only by the refness of one or more arguments. I'm not sure why they do this; perhaps it's a versioning thing--an initial version is published with a ByVal argument and later a ByRef one is added for performance.
This puts VB users in a bad spot if they encounter one of these bad-actors because VB can't distinguish these overloads at the call-site. I've run into it myself when using the Managed DirectX library and have seen at least one customer report about it.
**Note**: This proposal does NOT include allowing Visual Basic to define such overloads.
# Proposal
Given two methods `M` and `N` of equal specificity, and a pair of parameters `Mj` and `Nj` that match argument `Aj`,
* If `Aj` is classified as a variable or property access and `Mj` is a reference (`ByRef`) parameter and `Nj` is not, `Mj` is more specific than `Nj`.
* If `Aj` is classified as a value and `Mj` is a value (`ByVal`) parameter and `Nj` is not, `Mj` is more specific than `Nj`.
* If at least one `Mj` is more specific `Nj` and no `Nj` is more specific than `Mj`, `M` is more specific than `N`.
**Note**: This does not take into account whether the variable or property being accessed is read-only.
More plainly, prefer `ByRef` parameters when passing "r-values" (things that can be assigned to) and `ByVal` parameters when passing `l-values` (things which aren't storage locations).
This means given these overloads:
``` VB.NET
Sub M(ByVal p As Integer)
Sub M(ByRef p As Integer)
```
A user can force the compiler to pick the first overload by forcing the argument to be classified as a value (e.g. parenthesizing the expression).
A user can force the compiler to pick the second overload by manually copying the value into a local variable (which is what the compiler would have done anyway).
And without user intervention the compiler will pick the overload whose argument passing convention is most appropriate for the class of expression being passed.
# Alternatives
Add a `ByRef` modifier at the call-site. This has been requested before but was rejected due to concerns that some code would use it and some wouldn't and without strict enforcement (breaking change) it would cause more confusion than good as readers would erroneously assume code without the modifier wasn't passing `ByRef`.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.