[Proposal]: [call local static functions in base constructor] #8619
Replies: 27 comments
-
|
Are there any other things ordinary static methods can do, but local static methods can't? It's probably worthwhile to collect a list of them all and try to do as many of them as possible in one go. |
Beta Was this translation helpful? Give feedback.
-
|
It surprises me that this isn't something we already support. I'm interested in championing this, specifically for |
Beta Was this translation helpful? Give feedback.
-
|
@333fred the reason this isn't supported is because of name lookup. I think it will be a breaking change to make local functions in scope in the base constructor. |
Beta Was this translation helpful? Give feedback.
-
|
e.g. using System;
Console.WriteLine(new Derived().A);
class Base
{
public int A;
protected Base(int a) => A = a;
}
class Derived : Base
{
public Derived() : base(GetInt())
{
static int GetInt() => 42;
}
static int GetInt() => 41;
}😢 |
Beta Was this translation helpful? Give feedback.
-
|
@YairHalberstadt I don't think it's a big deal. We can give the static methods at class level (i.e, the one returns 41 in your example) a priority when it's being called in |
Beta Was this translation helpful? Give feedback.
-
|
I think that would be concerning, because imaging I had this code: using System;
using static SomeClass;
class Base
{
public int A;
protected Base(int a) => A = a;
}
class Derived : Base
{
public Derived() : base(GetInt())
{
static int GetInt() => 42;
}
}This would work fine. Now somebody adds a |
Beta Was this translation helpful? Give feedback.
-
|
IMO I'd rather evaluate whether it's acceptable to take the source-breaking change and have only the local function be in scope, to keep it consistent with local functions in normal methods. What is the likelihood that someone is calling a static function in their base constructor call that happens to have the same name as a local function defined within that constructor? |
Beta Was this translation helpful? Give feedback.
-
|
If the breaking change were considered acceptable, would it be ideal to try and stuff this into C# 9 to limit the chance of anyone being broken by this? |
Beta Was this translation helpful? Give feedback.
-
|
Also would local functions and static local functions have different scope to limit the breakages? local functions were introduced 3 years ago, and static local functions only last year. Only static local functions are useful in base classes. Furthermore, would we want to do this for |
Beta Was this translation helpful? Give feedback.
-
In this case, I think a normal warning ("The call to '{0}' in base() is ambiguous between a static local function and a static method") could be added (keep the warning limited to calls in |
Beta Was this translation helpful? Give feedback.
-
IMO Yes. There is no reason for this to be allowed in |
Beta Was this translation helpful? Give feedback.
-
That would break existing code. |
Beta Was this translation helpful? Give feedback.
-
|
For context, currently when the C# compiler finds a local function in scope with a given name it immediately stops attempting to resolve that name in any other scope. That includes static members, imported static functions, etc. This is true even if the other members are a better match, or the local function isn't a match at all: |
Beta Was this translation helpful? Give feedback.
-
Even if it was, C# 9 is locked. This definitely couldn't make it in. Now, as to the breaking change, I fall in the camp of "the number of people who will be bitten by this is likely vanishingly small" camp, but I'm willing to discuss alternative overload resolution rules to make it work. |
Beta Was this translation helpful? Give feedback.
-
|
What about this? Seems like it should have the same lookup rules. class Derived : Base
{
public Derived() : base(x)
{
const int x = 0;
}
} |
Beta Was this translation helpful? Give feedback.
-
|
This issue is open for community contribution. To start with, needs an approved specification for how it would work, which can be posted here as a comment or have a PR made to the |
Beta Was this translation helpful? Give feedback.
-
|
I think there should be an error if a static local function is defined and a identically named type-level static method exists, as well, and a function with this name is called as part of base ctor call. This error should be raised at the base ctor call site.
Yes but 1) I doubt it has a significant real world impact because it's mostly limited to new code going forward, and 2) the concerns raised by others by suddenly binding to a different method because a base class was modified, etc., are serious enough that an error is warranted. |
Beta Was this translation helpful? Give feedback.
-
Why would it be limited to new code going forward? Wouldn't it affect existing code that already has written this? |
Beta Was this translation helpful? Give feedback.
-
|
My thinking was, the circumstance where 1) a static type-level method is in scope, 2) an identically named static local function is defined in child ctor, and 3) base ctor call uses the static method, is highly unlikely. I know, this is an empirical question, but I think even if we tried to write a tool which would look for this in publicly available codebases, we wouldn't find this much, if at all. |
Beta Was this translation helpful? Give feedback.
-
|
My point was that it's not limited to new code going forward. It may absolutely break existing code. I'm personally ok with that, i just want to categorize things properly :) |
Beta Was this translation helpful? Give feedback.
-
|
Oh yes, I never denied that it's impossible to break existing code, just that it's 1) unlikely and 2) kind of preferable. |
Beta Was this translation helpful? Give feedback.
-
|
I really wish this could be fixed. It feels like the feature And I don't understand the discussion about breaking changes. I would expect this feature is no different than the initial support of local functions? |
Beta Was this translation helpful? Give feedback.
-
The team is willing to accept community contributions on this proposal, including spec changes. But it does not seem to have bubbled up to the point where they are going to devote resources to address it themselves, aside from marshaling through the community contribution, which isn't insignificant.
The difference is that local functions didn't exist, so it was never possible to break the meaning of existing code since that code wasn't legal previously. In this case the local function syntax already exists, and it's possible for someone to have declared a static local function within the constructor yet have a call to a static member in the base constructor call. That would result in the meaning of the existing code silently changing. However, it seems that members of the language design team are fine with that. |
Beta Was this translation helpful? Give feedback.
-
Not necessarily. The local function could be used only if the name couldn't be matched to a method outside, for example. Then it wouldn't change existing code, but of course adding a method to the base class would take precedence over the local function, but considering a single Of course this too depends on the hypothetical concrete proposal. |
Beta Was this translation helpful? Give feedback.
-
That would make this one situation behave differently than local functions do in every other situation, which, IMO, is much less desirable. The team has already suggested that they're willing to accept the source breaking change in this scenario given the low likelihood that it will actually affect anybody, so I don't think it's necessary to consider ways to work around it. |
Beta Was this translation helpful? Give feedback.
-
|
Well this is also (to my knowledge) the only situation where local functions are used outside of the scope they are defined, so a different behaviour is not all that surprising. |
Beta Was this translation helpful? Give feedback.
-
I expect it's also extremely unlikely to have defined a local function with the same name as a member without having the intention to call it. Either way, the team seems totally fine with the potential for that source breaking change, that is not holding up the implementation of this feature. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
call local static functions in base constructor
Summary
Today to calculate parameters to be sent from derived class constructor to base constructor one has to define additional static method in derived class. It would be nice to use local static function instead.
Motivation
Not to litter class members scope with functions that should be encapsulated as local ones.
Example
Drawbacks
Alternatives
Unresolved questions
Design meetings
https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-26.md#static-local-functions-in-base-calls
https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-09-28.md#ungrouped
Beta Was this translation helpful? Give feedback.
All reactions