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

Proposal: out var declaration #6183

Closed
gafter opened this Issue Oct 20, 2015 · 53 comments

Comments

@gafter
Member

gafter commented Oct 20, 2015

This feature would allow a variable be declared at the same time that is it passed as an out parameter:

argument-value:
    out type identifier

A variable declared this way is read-only and scoped to the enclosing statement. More specifically, the scope will be the same as for a pattern-variable introduced via pattern-matching.

You should be able to use the contextual keyword var for the variable's type, in which case the specification for overload resolution would have to be modified to account for that possibility.

@gafter gafter self-assigned this Oct 20, 2015

@gafter gafter added this to the C# 7 and VB 15 milestone Oct 20, 2015

@bbarry

This comment has been minimized.

Show comment
Hide comment
@bbarry

bbarry Oct 20, 2015

To clarify:

A variable declared this way is read-only and scoped to the enclosing statement.

if (int.TryParse(input, out var value)) 
{
    // value here - readonly
}
else
{
    // value not in scope
}
// value not in scope

...

bool test = int.TryParse(input, out var value);
// value not in scope

bbarry commented Oct 20, 2015

To clarify:

A variable declared this way is read-only and scoped to the enclosing statement.

if (int.TryParse(input, out var value)) 
{
    // value here - readonly
}
else
{
    // value not in scope
}
// value not in scope

...

bool test = int.TryParse(input, out var value);
// value not in scope
@orthoxerox

This comment has been minimized.

Show comment
Hide comment
@orthoxerox

orthoxerox Oct 20, 2015

Contributor

Do we really need this with struct tuples and nullables? Why not enhance the stdlib with int? Int.TryParse(string input) and (int quotient, int remainder) Math.DivRem(int dividend, int divisor) instead?

Contributor

orthoxerox commented Oct 20, 2015

Do we really need this with struct tuples and nullables? Why not enhance the stdlib with int? Int.TryParse(string input) and (int quotient, int remainder) Math.DivRem(int dividend, int divisor) instead?

@FunctionalFirst

This comment has been minimized.

Show comment
Hide comment
@FunctionalFirst

FunctionalFirst Oct 20, 2015

What about using tuples to capture out parameters as in F#?

let (b, dt) = System.DateTime.TryParse("12-20-04 12:21:00")

FunctionalFirst commented Oct 20, 2015

What about using tuples to capture out parameters as in F#?

let (b, dt) = System.DateTime.TryParse("12-20-04 12:21:00")
@vladd

This comment has been minimized.

Show comment
Hide comment
@vladd

vladd Oct 20, 2015

@gafter Do I understand the use case right:

var r = int.tryParse(str, out var n);

makes r non-readonly and n readonly? If so, both of them are "just function output arguments", why the difference?

vladd commented Oct 20, 2015

@gafter Do I understand the use case right:

var r = int.tryParse(str, out var n);

makes r non-readonly and n readonly? If so, both of them are "just function output arguments", why the difference?

@alrz

This comment has been minimized.

Show comment
Hide comment
@alrz

alrz Oct 20, 2015

Contributor

@FunctionalFirst That would totally change method invocation semantics for any value. However, with #6067 you can deconstruct the out variable right away.

Contributor

alrz commented Oct 20, 2015

@FunctionalFirst That would totally change method invocation semantics for any value. However, with #6067 you can deconstruct the out variable right away.

@FunctionalFirst

This comment has been minimized.

Show comment
Hide comment
@FunctionalFirst

FunctionalFirst Oct 20, 2015

@alrz Only for methods with out parameters, and it's a good change as it improves the locality of return values. You can also deconstruct the tuple right away with pattern matching.

FunctionalFirst commented Oct 20, 2015

@alrz Only for methods with out parameters, and it's a good change as it improves the locality of return values. You can also deconstruct the tuple right away with pattern matching.

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Oct 20, 2015

Member

@bbarry Not quite. The variable will be scoped to the "then" clause only (not the "else" clause) because that's the way pattern variables work. But correct: "out variables" in a local variable initializer do not escape to the enclosing scope. If you want it in the enclosing scope you know where to declare it.

@orthoxerox We do no intend to revisit every existing API that uses out parameters, change the recommendation for designing APIs, nor deprecate out parameters

@vladd You did not declare r as having any special relation to a method invocation. It is an ordinary local variable placed into the enclosing scope. n, on the other hand, is defined by reference to the method invocation (the grammar ties it to argument-value) and is not placed into the enclosing scope. If you want it mutable or in the enclosing scope, you know where to declare it.

Member

gafter commented Oct 20, 2015

@bbarry Not quite. The variable will be scoped to the "then" clause only (not the "else" clause) because that's the way pattern variables work. But correct: "out variables" in a local variable initializer do not escape to the enclosing scope. If you want it in the enclosing scope you know where to declare it.

@orthoxerox We do no intend to revisit every existing API that uses out parameters, change the recommendation for designing APIs, nor deprecate out parameters

@vladd You did not declare r as having any special relation to a method invocation. It is an ordinary local variable placed into the enclosing scope. n, on the other hand, is defined by reference to the method invocation (the grammar ties it to argument-value) and is not placed into the enclosing scope. If you want it mutable or in the enclosing scope, you know where to declare it.

@HaloFour

This comment has been minimized.

Show comment
Hide comment
@HaloFour

HaloFour Oct 20, 2015

@gafter Do the same scoping rules apply to conditional operations? Probably wouldn't matter much unless another out declaration was used in the false expression.

HaloFour commented Oct 20, 2015

@gafter Do the same scoping rules apply to conditional operations? Probably wouldn't matter much unless another out declaration was used in the false expression.

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Oct 21, 2015

Member

@HaloFour If you declare a pattern variable or an out variable in the condition of a ternary expression, it will be in scope throughout the enclosing statement (unless it is part of the condition of an if statement, in which case it won't be available in the else clause). However, in the case of a pattern variable, it is likely not to be definitely assigned within the third clause of the ternary expression:

string s = "123";
var result = int.TryParse(s, out var value)
    ? value // OK, in scope
    : value; // OK, but according to the spec for TryParse, always zero here.

compare this to

object o = 123;
var result = o is int value
    ? value // OK, in scope
    : value; // error: in scope, but not definitely assigned
Member

gafter commented Oct 21, 2015

@HaloFour If you declare a pattern variable or an out variable in the condition of a ternary expression, it will be in scope throughout the enclosing statement (unless it is part of the condition of an if statement, in which case it won't be available in the else clause). However, in the case of a pattern variable, it is likely not to be definitely assigned within the third clause of the ternary expression:

string s = "123";
var result = int.TryParse(s, out var value)
    ? value // OK, in scope
    : value; // OK, but according to the spec for TryParse, always zero here.

compare this to

object o = 123;
var result = o is int value
    ? value // OK, in scope
    : value; // error: in scope, but not definitely assigned
@paulomorgado

This comment has been minimized.

Show comment
Hide comment
@paulomorgado

paulomorgado Oct 21, 2015

Aren't the "then" and the else two branches of the same if statement?

So, this:

var result = ThisOrThat("123", out var value)
    ? value
    : value;

will not be the same as:

int result;
if (ThisOrThat("123", out var value))
{
    result = value;
}
else
{
    result = value;
}

I'm not worried about all the refactorings out there because this will be a new case. But it doesn't make sense to me.

paulomorgado commented Oct 21, 2015

Aren't the "then" and the else two branches of the same if statement?

So, this:

var result = ThisOrThat("123", out var value)
    ? value
    : value;

will not be the same as:

int result;
if (ThisOrThat("123", out var value))
{
    result = value;
}
else
{
    result = value;
}

I'm not worried about all the refactorings out there because this will be a new case. But it doesn't make sense to me.

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Oct 21, 2015

Member

@paulomorgado Yes and yes.

The reason for this rule is that we expect people to often write code like

if (o is FooNode node && node.Whatever) { ... code using node ... } else
if (Something && o is BarNode node) { ... code using node ... } else
if (o is BazNode node) { ... code using node ... }

and we don't want to force them to have to think up new names for every node. This trick doesn't work in the ternary expression because the scope is expanded to the enclosing statement.

Also we don't want different but overlapping scoping rules for pattern variables and these "out" variables.

And anyway Swift does it this way (for pattern variables) so it must be right 😉

Member

gafter commented Oct 21, 2015

@paulomorgado Yes and yes.

The reason for this rule is that we expect people to often write code like

if (o is FooNode node && node.Whatever) { ... code using node ... } else
if (Something && o is BarNode node) { ... code using node ... } else
if (o is BazNode node) { ... code using node ... }

and we don't want to force them to have to think up new names for every node. This trick doesn't work in the ternary expression because the scope is expanded to the enclosing statement.

Also we don't want different but overlapping scoping rules for pattern variables and these "out" variables.

And anyway Swift does it this way (for pattern variables) so it must be right 😉

@paulomorgado

This comment has been minimized.

Show comment
Hide comment
@paulomorgado

paulomorgado Oct 21, 2015

@gafter, isn't that use case covered by pattern matching constructs like match and switch?

paulomorgado commented Oct 21, 2015

@gafter, isn't that use case covered by pattern matching constructs like match and switch?

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Oct 21, 2015

Member

@paulomorgado No, not always, including in this example where the second if condition starts with a boolean expression.

Member

gafter commented Oct 21, 2015

@paulomorgado No, not always, including in this example where the second if condition starts with a boolean expression.

@orthoxerox

This comment has been minimized.

Show comment
Hide comment
@orthoxerox

orthoxerox Oct 21, 2015

Contributor

@gafter: We do no intend to revisit every existing API that uses out parameters, change the recommendation for designing APIs, nor deprecate out parameters

Why not? Why implement better syntactic constructs and then keep using the old ones? out parameters are worse than proper return values from all standpoints. I'm not talking about removing the old APIs or even deprecating them in the next version, but about providing a more fluent alternative.

Contributor

orthoxerox commented Oct 21, 2015

@gafter: We do no intend to revisit every existing API that uses out parameters, change the recommendation for designing APIs, nor deprecate out parameters

Why not? Why implement better syntactic constructs and then keep using the old ones? out parameters are worse than proper return values from all standpoints. I'm not talking about removing the old APIs or even deprecating them in the next version, but about providing a more fluent alternative.

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Oct 21, 2015

Member

@orthoxerox Because there is lots of code using the recommended style, and we'd prefer not to jerk our customers around from one fad to another. I imagine some API authors may want to provide alternatives, but I also expect that we may elect to do as F# does and treat out parameters as tuple results, in which case API authors won't have anything to change.

Member

gafter commented Oct 21, 2015

@orthoxerox Because there is lots of code using the recommended style, and we'd prefer not to jerk our customers around from one fad to another. I imagine some API authors may want to provide alternatives, but I also expect that we may elect to do as F# does and treat out parameters as tuple results, in which case API authors won't have anything to change.

@vladd

This comment has been minimized.

Show comment
Hide comment
@vladd

vladd Oct 21, 2015

@gafter Point about scope taken, but again, why the immutability? Which advantage does it bring? This and let-expressions in LINQ seem to be the only places where readonlyness is implicit.

vladd commented Oct 21, 2015

@gafter Point about scope taken, but again, why the immutability? Which advantage does it bring? This and let-expressions in LINQ seem to be the only places where readonlyness is implicit.

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Oct 21, 2015

Member

@vladd This would be consistent with all range variables in LINQ, and all pattern variables. Given the limited scope, there isn't a lot of value in being able to mutate them. This is also consistent with a theme in a bunch of proposed features to make it easier to do things that are safe, rather than making the unsafe things easier to do than the safe alternatives.

Member

gafter commented Oct 21, 2015

@vladd This would be consistent with all range variables in LINQ, and all pattern variables. Given the limited scope, there isn't a lot of value in being able to mutate them. This is also consistent with a theme in a bunch of proposed features to make it easier to do things that are safe, rather than making the unsafe things easier to do than the safe alternatives.

@paulomorgado

This comment has been minimized.

Show comment
Hide comment
@paulomorgado

paulomorgado Oct 22, 2015

@gafter,

@paulomorgado No, not always, including in this example where the second if condition starts with a boolean expression.

Oops! Missed that when I wrote it.

I think we have two distinct cases here.

On one hand, we have a condition where a variable is definitely assigned after its evaluation:

(ThisOrThat("123", out var value))

And the other hand a condition where a variable is only definitely assign if the condition is true:

(o is BazNode node)

Besides the fact that this difference might be hard to specify and/or implement, wouldn't you agree with me that the variable is expected to be in scope of the else in the first case but not in the second case?

You might even argue that this:

(o is Something(out a, out b))

although having an implementation similar to the first case, falls semantically on the second case.

The bottom like is that I feel the, in the first case, the scope of value should be the if statement. And I don't see any restrictions or caveats of being that way that are not present today.

On the other hand, I think that any variable declared on the scope of a pattern matching construct (switch or match) should be scoped to that branch.

paulomorgado commented Oct 22, 2015

@gafter,

@paulomorgado No, not always, including in this example where the second if condition starts with a boolean expression.

Oops! Missed that when I wrote it.

I think we have two distinct cases here.

On one hand, we have a condition where a variable is definitely assigned after its evaluation:

(ThisOrThat("123", out var value))

And the other hand a condition where a variable is only definitely assign if the condition is true:

(o is BazNode node)

Besides the fact that this difference might be hard to specify and/or implement, wouldn't you agree with me that the variable is expected to be in scope of the else in the first case but not in the second case?

You might even argue that this:

(o is Something(out a, out b))

although having an implementation similar to the first case, falls semantically on the second case.

The bottom like is that I feel the, in the first case, the scope of value should be the if statement. And I don't see any restrictions or caveats of being that way that are not present today.

On the other hand, I think that any variable declared on the scope of a pattern matching construct (switch or match) should be scoped to that branch.

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Oct 22, 2015

Member

@paulomorgado We prefer not to have separate scoping rules for the two cases. If it comes to that we'd probably prefer to drop this feature.

Member

gafter commented Oct 22, 2015

@paulomorgado We prefer not to have separate scoping rules for the two cases. If it comes to that we'd probably prefer to drop this feature.

@leppie

This comment has been minimized.

Show comment
Hide comment
@leppie

leppie Oct 22, 2015

Contributor

Something seems missing here with regards to scoping.

Also the continuous mention of if/then/else is just confusing as every example assumes some a boolean return value.

What about all the other cases?

Examples:

DivMod(num, den, out var div, out var mod); 

Foo(Bar(out var baz), baz); 

I can't see how any of this would work if variable is not scoped to the enclosing scope.

Contributor

leppie commented Oct 22, 2015

Something seems missing here with regards to scoping.

Also the continuous mention of if/then/else is just confusing as every example assumes some a boolean return value.

What about all the other cases?

Examples:

DivMod(num, den, out var div, out var mod); 

Foo(Bar(out var baz), baz); 

I can't see how any of this would work if variable is not scoped to the enclosing scope.

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Oct 22, 2015

Member

If you want the variable to be in scope in the enclosing block, then you declare it in the enclosing block.

Member

gafter commented Oct 22, 2015

If you want the variable to be in scope in the enclosing block, then you declare it in the enclosing block.

@leppie

This comment has been minimized.

Show comment
Hide comment
@leppie

leppie Oct 22, 2015

Contributor

@gafter:

So in the first statement both div and mod will not be accessible, but still compile? If so, would the following (non-sensical statement) be allowed?

DivMod(num, den, out var _, out var _); 

And in the 2nd statement, it would be a compiler error?

Contributor

leppie commented Oct 22, 2015

@gafter:

So in the first statement both div and mod will not be accessible, but still compile? If so, would the following (non-sensical statement) be allowed?

DivMod(num, den, out var _, out var _); 

And in the 2nd statement, it would be a compiler error?

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Oct 22, 2015

Member

You cannot use the same name (_) to declare two different variables in the same scope. But there is no problem with your example Foo(Bar(out var baz), baz); as the scope of baz is the enclosing statement.

Member

gafter commented Oct 22, 2015

You cannot use the same name (_) to declare two different variables in the same scope. But there is no problem with your example Foo(Bar(out var baz), baz); as the scope of baz is the enclosing statement.

@gafter gafter referenced this issue Oct 27, 2015

Merged

Pattern Matching #4882

31 of 49 tasks complete
@AdamSpeight2008

This comment has been minimized.

Show comment
Hide comment
@AdamSpeight2008

AdamSpeight2008 May 26, 2016

Contributor

#11566
Can you clarify this?

  • There is a proposal pending LDM decision: An out variable may not be referenced before the close parenthesis of the invocation in which it is defined:

The out variable can not be referred to, within the other parameters of the method.

    M(out x, x = 3, 0); // error

Is the proposal the equivalent to the following?

M( out x, x = 3)
// Equivalent to 
int x; 
M( out x , x = 3 )

If so, then to referred to restriction, isn't a restriction.


Is the **our variableaccessible with then other branches of theif`?

If M(out x, "FOO" ) Then
' ...
Else If m = 0 Then
 ' ...
Else
  Console.Write(x)
End If
Contributor

AdamSpeight2008 commented May 26, 2016

#11566
Can you clarify this?

  • There is a proposal pending LDM decision: An out variable may not be referenced before the close parenthesis of the invocation in which it is defined:

The out variable can not be referred to, within the other parameters of the method.

    M(out x, x = 3, 0); // error

Is the proposal the equivalent to the following?

M( out x, x = 3)
// Equivalent to 
int x; 
M( out x , x = 3 )

If so, then to referred to restriction, isn't a restriction.


Is the **our variableaccessible with then other branches of theif`?

If M(out x, "FOO" ) Then
' ...
Else If m = 0 Then
 ' ...
Else
  Console.Write(x)
End If
@AlekseyTs

This comment has been minimized.

Show comment
Hide comment
@AlekseyTs

AlekseyTs May 26, 2016

Contributor

Yes, the proposal would make this

M(out int x, x = 3, 0); // error

or this

M1(out int x, M2(M3(out x), x))

an error.

The tentative plan is to use the same scoping rules as for pattern variables, which could be found here https://github.com/dotnet/roslyn/blob/features/outvar/docs/features/patterns.md

Contributor

AlekseyTs commented May 26, 2016

Yes, the proposal would make this

M(out int x, x = 3, 0); // error

or this

M1(out int x, M2(M3(out x), x))

an error.

The tentative plan is to use the same scoping rules as for pattern variables, which could be found here https://github.com/dotnet/roslyn/blob/features/outvar/docs/features/patterns.md

@AdamSpeight2008

This comment has been minimized.

Show comment
Hide comment
@AdamSpeight2008

AdamSpeight2008 May 26, 2016

Contributor

If the out variable is gets defined into a scope local to the statement / expression.
Does that mean it overloads one that is already defined?
Or would that also be an error?

Contributor

AdamSpeight2008 commented May 26, 2016

If the out variable is gets defined into a scope local to the statement / expression.
Does that mean it overloads one that is already defined?
Or would that also be an error?

@Thaina

This comment has been minimized.

Show comment
Hide comment
@Thaina

Thaina Jun 8, 2016

Is it possible to use only var at out var

Because if we just use var at function parameter it should be obvious that it is used for out so we could drop out and just use var instead of full out var

so

int.TryParse("10",var i);

Also I would like to have ref var like this

void RefParse(string number,ref int i)
{
    int n;
    if(int.TryParse(number,out n))    // i would be default value if string cannot be parsed
        i = n;
}

// `ref var` difference from `out var` by = symbol
RefParse("10",var i = 0);

Thaina commented Jun 8, 2016

Is it possible to use only var at out var

Because if we just use var at function parameter it should be obvious that it is used for out so we could drop out and just use var instead of full out var

so

int.TryParse("10",var i);

Also I would like to have ref var like this

void RefParse(string number,ref int i)
{
    int n;
    if(int.TryParse(number,out n))    // i would be default value if string cannot be parsed
        i = n;
}

// `ref var` difference from `out var` by = symbol
RefParse("10",var i = 0);
@Phrohdoh

This comment has been minimized.

Show comment
Hide comment
@Phrohdoh

Phrohdoh Jun 8, 2016

Contributor

But RefParse doesn't have an out parameter so using var there doesn't make sense even with your example. Right?

Contributor

Phrohdoh commented Jun 8, 2016

But RefParse doesn't have an out parameter so using var there doesn't make sense even with your example. Right?

@Thaina

This comment has been minimized.

Show comment
Hide comment
@Thaina

Thaina Jun 8, 2016

@Phrohdoh That's what I said // 'ref var' difference from 'out var' by = symbol so both use the same var but of ref you need to declare value while out is not

Thaina commented Jun 8, 2016

@Phrohdoh That's what I said // 'ref var' difference from 'out var' by = symbol so both use the same var but of ref you need to declare value while out is not

@ghost

This comment has been minimized.

Show comment
Hide comment
@ghost

ghost Aug 23, 2016

@gafter, a little off-topic set of questions about the syntax you wrote above:

o is BazNode node

is this a valid C# syntax? since which version? Is it equivalent to:

BazNode node = null;
if(o is BasNode) node = new BazNode()

?

What if when BazNode has no ctor accepting zero params, would that magical syntax fail?

ghost commented Aug 23, 2016

@gafter, a little off-topic set of questions about the syntax you wrote above:

o is BazNode node

is this a valid C# syntax? since which version? Is it equivalent to:

BazNode node = null;
if(o is BasNode) node = new BazNode()

?

What if when BazNode has no ctor accepting zero params, would that magical syntax fail?

@Thaina

This comment has been minimized.

Show comment
Hide comment
@Thaina

Thaina Aug 23, 2016

@jasonwilliams200OK No and No.

It is not valid yet. They are some people here proposed to let it valid in next version (but I am on against faction)

And what it is doing is more like this

if(o is BasNode)
{
   BazNode node = o as BasNode;
   // use node here
}

The purpose is to use object in if scope as short as possible

Thaina commented Aug 23, 2016

@jasonwilliams200OK No and No.

It is not valid yet. They are some people here proposed to let it valid in next version (but I am on against faction)

And what it is doing is more like this

if(o is BasNode)
{
   BazNode node = o as BasNode;
   // use node here
}

The purpose is to use object in if scope as short as possible

@AdamSpeight2008

This comment has been minimized.

Show comment
Hide comment
@AdamSpeight2008

AdamSpeight2008 Aug 23, 2016

Contributor

@jasonwilliams200OK Think of if as introducing the variable into scope, with value as if it was of that type.

Contributor

AdamSpeight2008 commented Aug 23, 2016

@jasonwilliams200OK Think of if as introducing the variable into scope, with value as if it was of that type.

@Opiumtm

This comment has been minimized.

Show comment
Hide comment
@Opiumtm

Opiumtm Sep 23, 2016

As upcoming feature "pattern matching" is allowing * pattern (match anything), it would be applicable to use same literal for out parameter that isn't interesting and should be ignored.

Example:

Before:

int a;
int b; // variable b isn't used but declared only to store out-result

SomeMethod(out a, out b);
return a;

After:

int a;
SomeMethod(out a, out *);  // "out *" is indicating that second out parameter isn't used.

// another example - we are simply testing variable "s" can be parsed to integer, out parameter value
// is ignored
var s = "12";
if (int.TryParse(s, out *) 
{
    Console.WriteLine($"{s} is integer");
}

Opiumtm commented Sep 23, 2016

As upcoming feature "pattern matching" is allowing * pattern (match anything), it would be applicable to use same literal for out parameter that isn't interesting and should be ignored.

Example:

Before:

int a;
int b; // variable b isn't used but declared only to store out-result

SomeMethod(out a, out b);
return a;

After:

int a;
SomeMethod(out a, out *);  // "out *" is indicating that second out parameter isn't used.

// another example - we are simply testing variable "s" can be parsed to integer, out parameter value
// is ignored
var s = "12";
if (int.TryParse(s, out *) 
{
    Console.WriteLine($"{s} is integer");
}
@HaloFour

This comment has been minimized.

Show comment
Hide comment
@HaloFour

HaloFour Sep 23, 2016

@Opiumtm

That's planned, although it may not make C# 7.0. Could be in a minor release, though:

https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/

HaloFour commented Sep 23, 2016

@Opiumtm

That's planned, although it may not make C# 7.0. Could be in a minor release, though:

https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/

@BruceWilliams

This comment has been minimized.

Show comment
Hide comment
@BruceWilliams

BruceWilliams Oct 5, 2016

I just saw this feature mentioned on an MSDN blog, and my first thought when I saw this:
p.GetCoordinates(out var x, out var y);
Was - why type the 'var'? Would there be some additional ambiguity or something if we just accepted:
p.GetCoordinates(out x, out y);
To mean the same thing?

BruceWilliams commented Oct 5, 2016

I just saw this feature mentioned on an MSDN blog, and my first thought when I saw this:
p.GetCoordinates(out var x, out var y);
Was - why type the 'var'? Would there be some additional ambiguity or something if we just accepted:
p.GetCoordinates(out x, out y);
To mean the same thing?

@HaloFour

This comment has been minimized.

Show comment
Hide comment
@HaloFour

HaloFour Oct 5, 2016

@BruceWilliams

The syntax out <identifier> is already legal syntax. If the compiler were changed so that it would create a new variable if one wasn't already in scope that could lead to issues where a typo would result in accidentally create a new out declaration variable than populate the existing variable.

Also, the syntax is really out <type> <identifier>. var may be used in place of the type where there is no ambiguity, but since methods can overload on out parameters if the type was implied it would never be possible to resolve that ambiguity:

void Foo(out int x) { ... }
void Foo(out string x) { ... }

Foo(out x); // is x an int or a string?

HaloFour commented Oct 5, 2016

@BruceWilliams

The syntax out <identifier> is already legal syntax. If the compiler were changed so that it would create a new variable if one wasn't already in scope that could lead to issues where a typo would result in accidentally create a new out declaration variable than populate the existing variable.

Also, the syntax is really out <type> <identifier>. var may be used in place of the type where there is no ambiguity, but since methods can overload on out parameters if the type was implied it would never be possible to resolve that ambiguity:

void Foo(out int x) { ... }
void Foo(out string x) { ... }

Foo(out x); // is x an int or a string?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment