Local functions doesn't support method overloading #3112
Replies: 4 comments 8 replies
-
This was the decision back in 2015:
So I can assume that the team would be open to it given enough use cases. But I personally disagree that it should be done because method overloading exists. Method overload resolution is probably the most complicated part of the C# compiler and it's even difficult for developers to follow given the breadth of the rules when it comes to potential implicit conversions. It's trivial to give each local function a distinct name and it makes it much easier to follow that code. It's not like you can expose those functions in a public surface where overloading might provide improved ergonomics. I'd have to see actual use cases where overloading on local functions makes an actual difference but I suspect that such code would have various design smells and be overly complicated. |
Beta Was this translation helpful? Give feedback.
-
The current situation when I found this: I had some conversion methods in local functions. The output was the same (int), and the input was ISomething or a Guid which identifies one kind of ISomething. Why? Because the business and speed requirements. The conversions was unique in context of the whole project even in the class. It belonged to one specific method. Something like this: IEnumerable<SomeResult> GenerateResult(
ISomething object
IReadOnlyDictionary<Guid, IOtherThing> related) // Guid was identifier of ISomethings
)
{
// some peraparations and other operations
foreach (var relatedItem in related /* not necessary directly iteration*/)
{
// ...other code
yield return new SomeResult(
// ...
something1: GetSomeDerivatedInfo(object),
something2: GetSomeDerivatedInfo(relatedItem),
// ...
)
}
int GetSomeDerivatedInfo(Guid)
{
// call some external stuffs and do things
}
int GetSomeDerivatedInfo(IOtherThing)
{
// works with IOtherThing, different error handling, etc.
}
} Yes, pattern matching can be used here too, but then I've lost the strict typing instantly because the common type between Guid and ISomething is object. |
Beta Was this translation helpful? Give feedback.
-
A couple of thoughts. First, I do think we're open to overloading on local functions; there's no particular reason why it shouldn't work, and people are often surprised that it isn't there. It's just relatively easy for a developer to work around since everything is, well, local, so we haven't been particularly strongly motivated to prioritize looking at it. For the same reason, though, I don't think it would be particularly complicated to do. Overload resolution is complex, yes, but not more so here than elsewhere; in fact because there is no inheritance chain to consider it is probably a bit simpler. For the top-level statements scenario, I agree that it feels different but I don't think it is different: Here as elsewhere, the local functions are only available to the immediately adjacent code. However: When we added top-level statements we were careful to protect the design space, so that top level local functions could later become full-fledged top level function declarations; ones that can have accessibility, live in namespaces and be imported by other assemblies. At that point it really is different, and the arguments for overloading become stronger - the functions can now be part of an API surface area. All in all I probably feel that having overloading apply uniformly across the places in the language where functions/methods can be declared is probably "simpler" than special casing certain contexts like we do today. I'm just not convinced that it competes favorably against other things we currently have on the docket, priority-wise. Finally, let me also add a "slippery slope" argument: Why stop at overloaded functions? Why not add local properties? Events? Indexers? Etc. What's a natural point to stop, and why? |
Beta Was this translation helpful? Give feedback.
-
This problem also extends to local functions and member functions: public class Program
{
static void Main(string[] args)
{
A("hi");
A(42); // Argument 1: cannot convert from 'int' to 'string'
void A(string s) { }
}
static void A(int i) { }
} I find it's sometimes useful to have a local function delegate to a member function, and pass captured variables along. This reduces/simplifies the argument list for the caller of the local function. It's most useful when the same local function needs to be called many times. However, this can't be achieved with overloading as the following example shows, which requires introducing a contrived name for one of the functions when they represent the same concept. public class Program
{
static void Main(string[] args)
{
bool b = true;
A("hi");
void A(string s) => A(s, b); //No overload for method 'A' takes 2 arguments
}
static void A(string s, bool b) { }
} |
Beta Was this translation helpful? Give feedback.
-
Method overloading is part of C#. But local functions doesn't support it. IMHO the following code should compile and work:
Beta Was this translation helpful? Give feedback.
All reactions