Skip to content
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: Modify sequence expression to allow scope variables like "var x = { e is int y ? y : 0 }" #15651

Closed
qrli opened this issue Dec 3, 2016 · 12 comments

Comments

@qrli
Copy link

qrli commented Dec 3, 2016

Inspiration:
In current scoping rules, { } can be used to reduce scope of pattern variables and our vars like:

{ if (e is int y) { Use(y); } }
// y is not in scope here

But there is no easy way for expression statements:

var v = M(e is int y ? y : 0);
// v and y are both in scope here

{ var v = M(e is int y ? y : 0); }
// v and y are both not in scope here

If we can allow block effectively an expression, like sequence expression, then we can write:

var x = { e is int y ? y : 0 }
// x in scope but y is not here

This is inspired from discussion at #15538.

Detail Design
Base on sequence expression. I don't mind too much about ( ) vs { }, as long as it creates a scope for all variables created inside. But here we need to enclose one statement inside, so ( single_statement ) is ambiguous on whether it is a sequence expression or just redundent parenthesis. So I think { } is a better choice.

@alrz
Copy link
Contributor

alrz commented Dec 3, 2016

This'll be ambiguous in case of an array initializer.

int[] x = { e is int y ? y : 0 };

@qrli
Copy link
Author

qrli commented Dec 3, 2016

Yes, I'm just thinking about the array initializer case while I'm posting. Sequence expression can be unambiguously written with an extra semicolon, in case we really need to differentiate:

var x = { e is int y ? y : 0; };

Edit: Seriously, it is not ambigous to the compiler in your example. Because x is int[], so it cannot be a sequence expression here.

@qrli
Copy link
Author

qrli commented Dec 3, 2016

An possible ambiguous array initializer example:

object[] x = { e is object[] y ? y : new object[0] };

I think this is very rare case.

@alrz
Copy link
Contributor

alrz commented Dec 3, 2016

It's not. The ternary returns an array hence x will be a singleton array of another array (implicitly upcasted to object).

Ambiguity has nothing to do with rarity as it must be resolved in the compiler anyways.

@iam3yal
Copy link

iam3yal commented Dec 3, 2016

In addition to what @alrz said this is also inconsistent you use { } around blocks and then you switch gears and use it around expressions.

So if this should work var x = { e is int y ? y : 0 } then this should work too if ({e is int y}) { Use(y); }.

@qrli
Copy link
Author

qrli commented Dec 3, 2016

@eyalsk why do you think that way? { } always creates a scope in current c#, so if ({e is int y}) { Use(y); } obviously should not work. Even if we still use ( ) for sequence expression, if ((e is int y;)) { Use(y); } will not work either. The important part is not { }, but sequence expression has its own scope. Or do you think ( ) creating a scope is more intuitive?

For the other point, { } being either a block or a sequence expression: If C# continues to embrace functional style, they are the same thing in the end. But that's a different topic.

Without using { }, sequence expression still can be used. It just need to disumbiguous a bit for single content expression case, e.g.:

var x = (e is int y ? y : 0;); // note the semicolon inside parenthesis. A bit confusing though.

@iam3yal
Copy link

iam3yal commented Dec 3, 2016

@qrli

why do you think that way? { } always creates a scope in current c#

I know, I was referring to your suggestion.

if ({e is int y}) { Use(y); } obviously should not work

By your suggestion this should work!

For the other point, { } being either a block or a sequence expression: If C# continues to embrace functional style, they are the same thing in the end. But that's a different topic.

No, they aren't the same thing, there's a difference.

@qrli
Copy link
Author

qrli commented Dec 3, 2016

if ({e is int y}) { Use(y); } obviously should not work
By your suggestion this should work!

Sorry I cannot understand your logic. I said { } creates a scope. So y will not leak outside the { } at all. Why do you think it would?

@DavidArno
Copy link

DavidArno commented Dec 3, 2016

@alrz,

I don't think the following is ambiguous, other than to a potentially inexperienced reader of the code:

int[] x = { e is int y ? y : 0 };

It initiliases the x array with y or 0 and y leaks. To prevent it leaking, it would just need expressing as:

int[] x = { { e is int y ? y : 0 } };

What am I missing?

@eyalsk,

if ({e is int y}) { Use(y); }

Wouldn't work as I understand this suggestion as {e is int y} constrains y completely to the expression, ie it doesn't even leak into the if "body".

@iam3yal
Copy link

iam3yal commented Dec 3, 2016

@qrli

Sorry I cannot understand your logic. I said { } creates a scope. So y will not leak outside the { } at all. Why do you think it would?

Where in the world I said it would leak?

There's obviously a misunderstanding here, so let me try again.

What I'm saying is if you think this should work var x = { e is int y ? y : 0 } then all I'm saying is that when the curly braces are applied to any expression, anywhere! it should narrow the scope so if it's applied to an if statement like so:

if ({e is int y}) { Use(y); }

Then y wouldn't leak outside to the if statement.

I just think that it's nicer than wrapping the whole if statement with yet another block like this:

{ if (e is int y) { Use(y); } }

When I said the following:

By your suggestion this should work!

I meant that we should have only one way to narrow the scope of variables throughout the language.

@DavidArno

Wouldn't work as I understand this suggestion as {e is int y} constrains y completely to the expression, ie it doesn't even leak into the if "body".

Yeah I know but we need to have one way to do things so if it's possible to have these braces around the ternary operator then it might make sense to do the same and reuse it for everything else where we want to narrow the scope. 😄

@alrz
Copy link
Contributor

alrz commented Dec 3, 2016

@DavidArno It's still a valid array initializer.

int[,] x = { { e is int y ? y : 0 } };

Therefore, it's still ambiguous.

@CyrusNajmabadi
Copy link
Member

Closing this out. We're doing all language design now at dotnet/csharplang. If you're still interested in this idea let us know and we can migrate this over to a discussion in that repo. Thanks!

@CyrusNajmabadi CyrusNajmabadi closed this as not planned Won't fix, can't repro, duplicate, stale Nov 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants