Skip to content

New Tie-Breaker Rule for Resolving Ambiguity Between Overloads Which Differ By Refness of Arguments #170

Open
@AnthonyDGreen

Description

@AnthonyDGreen

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:

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.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions