Closed gafter closed 8 years ago
@qrli Your idea is neat But it not satisfied the proposal to do some work and log something before return or throw
@Thaina Perhaps
let int.TryParse(s, out var parsedValue) else { Log.Something(); return; }
I don't like this idea that variables can start escaping their scope (or what it looks like their scope should be) if certain keywords were used... I think it makes the code more difficult to read.
I'm not sure it deserves a new language keyword / construct just to avoid having to write
int parsedValue;
if (!int.TryParse(s, out parsedValue))
return;
// Do something with parsedValue
Now that the language has Tuples, why don't we instead argue that methods with out parameters now appear to return Tuples? (FYI this is what FSharp does.) After all, the only reason out parameters exist is because the language didn't have tuples from the beginning. For example, calls to Int32.TryParse would become:
var (success, parsedValue) = int.TryParse(s);
if(!success) return;
// Do something with parsedValue
So much cleaner and easier to understand, especially with pattern matching (if I can take a guess at the syntax:
switch(int.TryParse(s))
{
case (false, *) : return;
case (true, parsedValue) : // Do something with parsedValue
}
@Richiban
Per #12597 the conversation is probably mostly moot. Now the scope will sometimes leak out into their enclosing scope based on which constructs you use:
if (!int.TryParse(s, out int parsedValue))
return;
// use parsedValue here
I personally don't agree with it. It's inconsistent with existing C# behavior, it's inconsistent with itself and it's inconsistent with the rest of the C-family of languages. I'd rather the team did nothing at all and if the user intended to "leak" the scope that they would declare the variable separately, just as you demonstrated.
@HaloFour that's a shame...
By the way,
I personally don't disagree with it
did you mean "I personally don't agree with it"?
@Richiban
did you mean "I personally don't agree with it"?
That I did.
Closing, as this is no longer useful with the new scoping rules.
When reviewing the scoping rules for
out
variables and pattern variables, the LDM discovered that there is sometimes an unfortunate interaction with a pattern of coding that we call the guard pattern. The guard pattern is a coding pattern where you test for the exceptional conditions early, handle them, and then bypass the rest of a method by returning, the rest of a loop by continuing, etc. The idea is to not have to deeply nest the "normal" control path. You'd write code like this:To take advantage of the
out var
feature, and avoid having to write the type of theout
variable, you'd like to writebut that doesn't work because
parsedValue
isn't in scope in the enclosing statement. Similar issues arise when using pattern-matching:(The
@
here assumes that tuple patterns are preceded by an@
character)but that doesn't work because
key
andvalue
aren't in scope after theif
statement.Swift addresses this category of issue by introducing the
guard
statement. Translating that into the concepts we've been proposing for C# with tuples and pattern-matching, the equivalent construct would be a new kind of statement:A
guard
statement is like an inverted if statement, or an if statement without a "then" block. It has the following semantics:false
.true
.This would allow you to handle the previous examples as follows:
/cc @dotnet/ldm