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: switch when #13401

Closed
alrz opened this issue Aug 26, 2016 · 0 comments
Closed

Proposal: switch when #13401

alrz opened this issue Aug 26, 2016 · 0 comments

Comments

@alrz
Copy link
Member

alrz commented Aug 26, 2016

Proposal: switch when

Take the following code as a simple example,

if (!RepositoryPermissionService.HasCreatePermission(User.Id()))
{
    return UnauthorizedResult();
}
if (!TryCreateOnPush(repositoryName))
{
    return UnauthorizedResult();
}

To prevent code duplication, one might combine the two if's like this:

if (!RepositoryPermissionService.HasCreatePermission(User.Id()) ||
    !TryCreateOnPush(repositoryName))
{
    return UnauthorizedResult();
}

But now the readability has significantly worsened (if you ask me!).

As an alternative, we could use a switch construct which does not accept a particular expression to match against,

switch
{
  when !RepositoryPermissionService.HasCreatePermission(User.Id()):
  when !TryCreateOnPush(repositoryName):
    return UnauthorizedResult();
}

However, there is one disadvantage to this approach compared to a simple if statement. switch requires break in each switch-section. While there were lengthy discussions on this matter, I want to take the risk and suggest to not require break in switch sections in presence of a single block. This way, it feels far more natural and better than if else overall.

switch
{
  when Condition1():
  {    
  }
  when Condition2():
  {    
  }
  default:
  {
  }
}

This can be also helpful with #11293:

void Test(Expression<..> expr) {
  var body = expr.Body;
  switch {
    when body.Member(out *, out "Length"): {}
    when body.Member(out *, out string memberName): {}
  }  
}

Note: Member extension method is defined as follow (#13400).

 public static bool Member(this Expression @this, out Expression expr, out string memberName) {
  return @this is MemberExpression { Expression: out expr, Member: { Name: out memberName } }
}

This approach works fine. But there are some parts that can be still improved.

While this example could be written via if else statements, we are actually matching against a particular expression i.e. expr.Body but since methods can't be called in patterns, we are needed to use the when clause.

Alternatively, we could relax recursive patterns to also look up for member and extension methods of the static type of the target expression in addition to types (#9005):

void Test(Expression<..> expr) {
  switch(expr.Body) {
    case Member(*, "Length"): {}
    case Member(*, string memberName): {}
  }  
}

The problem is now we can't pass expressions to this method, for example what if we had the following extension method?

public static bool IsMatch(this string @this, string regex, out string[] captures) {
  // ...
}

I've suggested to use out to inject patterns inside expressions (#11293). Likewise, we can use in to inject expressions inside patterns (suggested by @DavidArno).

switch
{
  when str.IsMatch("regex", out { "abc", "def" } ): {} // assuming array patterns
}  

// compared to

switch(str)
{
   case IsMatch(in "regex", { "abc", "def" } ): {} 
}  

etc.

@alrz alrz changed the title ### Proposal: switch when Proposal: switch when Aug 26, 2016
@alrz alrz closed this as completed Mar 21, 2017
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

2 participants