-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Name Lookup for Wildcards #14862
Comments
/cc @dotnet/ldm @jcouv @AlekseyTs @jaredpar @VSadov |
To clarify, if there are no ambiguous overloads of a method declaring //given
void M(out int x) { x = 123; }
// all are equivalent statements? (assuming no variable _ in scope)
M(out var _);
M(out int _);
M(out _);
While I do think that this is an improvement on the original proposal I still there that there is too much room for ambiguity and the potential for accidentally overwriting legally declared fields/variables: void Foo() {
M(out _); // intended to throw away result
}
private int _; // oops, just added this field and changed the meaning of my program! I'd argue that for void Foo() {
M(out var _); // no ambiguity, definitely a wildcard
} As for deconstruction, I'd argue that the use of private int _;
void Foo() {
{
int o, _;
(o, _) = e; // compiler error, cannot deconstruct into _
(o, var _) = e; // no ambiguity, definitely a wildcard
}
{
int o;
(o, _) = e; // no _ in scope, definitely a wildcard
}
} I acknowledge that this is a hard-line approach, but in my opinion it's worth being a little more obnoxiously stricter in order to avoid the potential that any legit variable/field is overwritten. For people who don't use the |
@HaloFour For private / protected / external @gafter Do we need wildcards in typeswitch at all ? imo, it is useless here Can you explain why characters #, @, $, % can't be used for wildcards ? While presented alternative approach is simpler, I would stick with previous proposal which is bit more complex, but more aligned with rules for other variables. |
Providing the user a way to avoid declaring an identifier allows us to warn when the declared identifier is unused.
We don't think any of those are an improvement over |
Shouldn't that 0.01% of developers who are currently actually using
Yeah, not sure why we need two ways: if (o is int _) {} if (o is int) {} |
That isn't a typeswitch. In the context of an if (o is (int x, int y) _) {} // test for the type ValueTuple<int, int>; nothing placed in scope
if (o is (int x, int y) {} // test for any tuple whose value contains two integers; places x and y in scope |
It makes sense in such situations I guess. Although the names are probably not relevant in first case: if (o is (int, int) _) {} or if (o is (int _, int _) _) {} |
Also why not this? if (o is (int, int)) {} |
Hey, that's my word! 😁 The only thing worse than a slightly more verbose improvement is a syntax that can accidentally lead the developer into a subtle runtime bug. Allowing deconstruction into an existing Note that this would apply specifically to deconstructing into existing variables which I expect will be a minority case. For people using declaration deconstruction syntax you'd only need
It's my opinion that a warning wouldn't be sufficient. You could add a
I tend to agree. The closest I might suggest is
You know that the most active "abusers" would be those Fortune 50s with massive code bases that have every other MS VP on speed dial and would call them up screaming if they even suspected that their builds might break. There are some threads on the coreclr repo sharing some interesting stories of just this sort of thing happening with updates to .NET impacting internals that nobody should have ever relied on anyway, updates that had to be rolled back. Anyhow, MS made |
And they are rushing to use C# vNext? And they will scream you say? Did it help e.g. save Silverlight? Based on what Microsoft is generally doing, enterprise is irrelevant. Unless it uses Node.js with Git and hosts it on Azure. |
But these characters do not conflict with any name, and there won't be needed any tricks to avoid ambiguities. Doesn't this outweigh 'low profile' of _ ? |
This is also why the team has refused to add any new warnings to the compiler for existing code. Can't risk breaking some build that happens to be riddled with awful code. https://github.com/dotnet/corefx/issues/1420#issuecomment-96430564
Who knows, maybe Microsoft could stand to be significantly more abusive towards their customer base. It seems to work for Apple. |
@HaloFour more abusive than the whole Sinofski fiasco? https://blog.ailon.org/how-one-announcement-destroyed-the-net-ecosystem-on-windows-19fb2ad1aa39#.2b9c211pz Renaming a method is kind of easier than switching a GUI framework. |
Let's keep the conversation on topic. Thanks :)
Currently we don't think so. "_" as a wildcard fits into how people are generally using that identifier already today. So we think it's nice to be able to just codify that concept, even if it means we do need to put in the due diligence to make sure we don't break any existing code. |
@CyrusNajmabadi sorry, I'll stop now :). |
Regarding the new proposals, I think @HaloFour has nicely summarised what I also see as a better solution than @gafter is proposing. I too think we need very strict - There is one use-case that's missing from both the OP and @HaloFour's post. I think is important to clarify that following extra wildcard case should also be supported: _ = e; // wildcard, but not explicitly covered by @gafter's 2nd case |
How about using if (o is int ~)
{
M(out int ~);
}
(int x, int ~) = e;
M(out ~);
(o, ~) = e;
(int x, ~) = e; It is almost as low profile as |
|
What makes And to echo @HaloFour's point, it doesn't suddenly change meaning when you are working elsewhere. |
If you were considering other symbols, I'd suggest That said, I like
|
as mentioned already, we are trying to avoid using other symbols. There's no end to the number of syntacticly unambiguous options we have if we go with something else. But that's not the goal here. The goals are:
It's similar to the issue we had when we introduced generics into the language. We could have gone with different syntax than To that end specified above, '_' is an ideal wildcard character. It just needs to be added to the language in a careful manner as we view back compat as a very high bar. |
Compiler post error only for technically incorrect statements, which is not case here.
This is asking for breaking compatibility, because "Code like var _ = 123; and M(out _) would suddenly take on a completely new meaning." (citation of your post). Every dev must learn every new feature, and be responsible while creating code. Team and compiler should not take responsibility for irresponsible devs. There are already features that can introduce 'subtle ambiguities' that are much more serious than changing value of some 'do not care' variable. |
This would make that the case here. The compiler already does this in numerous examples today. For example, requiring a
No it wouldn't. That would mean exactly what it has meant in C# 1.0 through C# 6.0. In fact, it would also mean the same thing that it means based on the proposed changes in this proposal.
It's called the "pit of success". The language does have the responsibility of providing an environment that leads developers towards success. The C# team has invoked it on numerous occasions already.
Name 'em. Specifically those that don't cause compiler errors and introduce subtle value changes. |
Note that I believe that based on the reconsidered rules above that the following would already fail to compile: void M(out string s) { s = "456"; }
var _ = 123;
M(out _); // CS1503: cannot convert from "out int" to "out string" |
but now correctly code
will fail to compile with your second rule. |
You misunderstand. That code would compile just fine, as it does today. What wouldn't compile is |
So, there is no need for error. Some devs may protect themselves by placing |
What's the reason for |
@alrz Not sure but maybe it's slightly less work? I mean otherwise, this introduces a special case, just a hunch. :) However, I agree, |
@alrz @eyalsk Yes, |
@MattGertz The compiler work is all done. The language specification may require spec text to be written, which is why this LanguageDesign issue is still open. |
Issue moved to dotnet/csharplang #364 via ZenHub |
We are considering a number of small changes to deconstruction, out variables, and pattern-matching to allow the use of wildcards where one could declare a variable, but the user has no intention of using the value captured in that variable. Here we discuss an open issue around name lookup, and propose a resolution.
The summary of this proposal is that the use of a wildcard has no effect on name lookup elsewhere in the code.
Original (LDM) approach
The original approach described by LDM was that the lookup of the identifier
_
would treat it as a wildcard if nothing were found:multiple declarations of the identifier
_
in the same scope would cause_
to be considered a wildcard:Existing cases, where the identifier is declared once, would still introduce a variable named
_
:Criticism of the this approach
This approach treats an unbound identifier
_
as a wildcard, a single definition of_
as causing_
to bind to that definition, and multiple definitions again treating the use of_
as a wildcard. It requires careful definition of what "multiple definitions" are. Would a declaration of_
in an outer scope, and redeclaration in an inner scope cause a use to be a wildcard?There are corresponding implementation difficulties that may make this approach unattractive.
Proposed alternative
The proposed alternative is that
_
in the following contexts would always be treated as a wildcard, and would have no effect on name lookup elsewhere:_
as an expression as an out argument, or as a variable in the left-hand-side of a deconstruction, would be bound to a variable of that name. If no variable of that name is found, it is treated as a wildcard. This is similar to the treatment ofvar
as a type.This is much simpler to implement and I believe much easier to explain.
The text was updated successfully, but these errors were encountered: