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

Let us put braces in case labels with implicit break #1378

Closed
nvmkpk opened this issue Mar 14, 2018 · 25 comments
Closed

Let us put braces in case labels with implicit break #1378

nvmkpk opened this issue Mar 14, 2018 · 25 comments

Comments

@nvmkpk
Copy link

nvmkpk commented Mar 14, 2018

I want to write something like:

switch (someVariable)
{
    case someConstant:
    {
    }

    case someOtherConstant:
    ....
}

We can do it right now but there are two issues in it:

  1. The braces will be indented at one level more than the case statement.
  2. We still need to put break statement either as last statement inside the brace or outside right after closing brace making it look ugly.

This also allows us to declare variables inside the brace without needing to expose them outside the case block.

@HaloFour
Copy link
Contributor

Allowing for the break statement to be omitted would be inconsistent and confusing.

@CyrusNajmabadi
Copy link
Member

The braces will be indented at one level more than the case statement.

there is a formatting option for this:

image

@CyrusNajmabadi
Copy link
Member

I'm not sure i get this part;

We still need to put break statement either as last statement inside the brace or outside right after closing brace making it look ugly.

nothing seems ugly about either of those forms to me.

@qrli
Copy link

qrli commented Mar 15, 2018

The default indention formatting behavior of VS works nicely if you put break inside brace. The indention only happens if your break is outside.

            switch (v)
            {
                case 1:
                {
                    Foo();
                    break;
                }
                case 2:
                    {
                        Bar();
                    }
                    break;
            }

break being required is already a sailed ship. When match expression come, I'd expect switch statement being used less, so not so bothering anymore.

@kameko
Copy link

kameko commented Mar 15, 2018

It's funny, I was just about to propose this and I saw someone did just 9 hours ago, albeit the way the proposal is presented is awful.

I personally dislike how scope is shared between cases in a switch. I always use brackets in every case to avoid scope being shared, which is consistent with how I always use brackets with if and other bracket-optional statements.
With that in mind, I thought, it would make sense to have the compiler implicitly add break; in a case statement only if: The entire body of the case was inside brackets, there was no explicit break;, and maybe additionally that all cases were like that.
My reasoning for this is, no other bracket bodies need a keyword to end them. There's no endclass; before or after the closing bracket of a class, etc., so why does it have to be the same for switches? Why enforce that if the switch is written to look like an if/else chain anyway? I think it's a little unsightly.

That's my personal reasoning for it. It's not that big of a deal, and I don't know how much work it would be to add that feature, but if it's reasonable, then I don't think it would be inconsistent at all, especially if the "only if all cases do not have an explicit break;" option is enforced.

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented Mar 15, 2018

My reasoning for this is, no other bracket bodies need a keyword to end them.

That's because there's no concept of 'fallthrough' in any other constructs. On the other hand, C# adopts 'switch' from its C heritage, and 'fallthrough' is absolutely a core part of that system. As such, C# wanted to be extremely explicit in the code to make it clear when fallthrough was happening, and when it was not. As such, fallthrough can only happen if you have:

case A: // absolutely no code.  only fallthrough
case B:

Contrast that with 'break' (or some other flow construct) in all other cases, which clearly that fallthrough is not happening.

With that in mind, I thought, it would make sense to have the compiler implicitly add break; in a case statement only if: The entire body of the case was inside brackets, there was no explicit break;

The problem with that is that then you can have:

switch (expr) {
  case a:
  {
    // stuff
  }
  case b:
  {
   // more stuff
  }
}

To anyone with a C 'switch' background (C, C++, Java, etc) this could be very confusing. It would very much look like to them that fallthrough was occurring.

@CyrusNajmabadi
Copy link
Member

then I don't think it would be inconsistent at all,

It would be inconsistent with how switch-without-breaks works for several other languages c# shares a lineage with.

@kameko
Copy link

kameko commented Mar 15, 2018

Is there actually a reason to continue this "C-style language compatibility" any further anymore? It made sense during C#'s first decade of existence when it was being adopted by the world, but now it's a mainstay language with it's own quirks and features. Okay, the syntax breaks syntax recognition, what about lambdas? Or even the fact that C# switches don't allow fallthoughts, or they use goto instead of fallthrough? (which I especially dislike due to all the people who say "goto is evil" and mistake that goto usage for it's classical purpose, but that's too late to change now)

If this really is an issue, what if we added an optional syntax feature to switch so that, in order to use the implicit break; feature, the switch would have to be formatted as so: switch break { ... }. I would force the reader to realize this isn't a normal switch and thus realize there may be some syntactic differences along with it. It also adds no extra keywords and does not break existing code. Heck, you can even make it switch implicit break { ... }, still adds no extra keywords because implicit is already a keyword.

@CyrusNajmabadi
Copy link
Member

Is there actually a reason to continue this "C-style language compatibility" any further anymore?

The opposite must be asserted. Is there a good enough reason to move away from the decisions the language has made, and has served it well for all this time. Changes are expensive. They require a massive amount of effort both from within the team, and externally as well. All changes must justify themselves with the overall net benefit (which includes assessing the problems inherent with them).

@CyrusNajmabadi
Copy link
Member

Or even the fact that C# switches don't allow fallthoughts,

C# switches allow fallthrough. They allow implicit fallthrough when it is obvious and there's no chance of confusion. i.e.

case A: // absolutely no code.  only fallthrough
case B:

THey also allow explicit fallthrough for the non-obvious cases. This gives the power and flexibility of the C-heritage switch-statements, while also addressing a major weakness of them (i.e. accidental implicit fallthrough in complex cases).

@CyrusNajmabadi
Copy link
Member

If this really is an issue, what if we added an optional syntax feature to switch so that, in order to use the implicit break; feature, the switch would have to be formatted as so: switch break { ... }

You're welcome to propose such a thing. If someone on the LDM wants to champion it, it may go somewhere. However, in my personal opinion, there are a lot more important fish to fry. :)

--

Here's my take on it:

I personally don't see the current situation with switch/case/break is problematic enough to warrant a change here. What is far more important are issues like: "how do i use 'switch' in an expression context?" or "how do i find out if i'm not exhaustively switching?" or "how can i switch over things other than types/ints?". These issues are the one that actually dramatically effect how i can use 'switch' to solve problems. Whether or not i have to specify 'breaks' in my switch doesn't actually appreciably change the utility or power of switches, and so it doesn't really end up substantively impacting as much as other proposals would.

@kameko
Copy link

kameko commented Mar 15, 2018

I was ignoring the case of an empty case, in which case the implicit break; would not qualify, but I understand.

My primary concern was if this was too large of a change that the effort gone into it would outweigh the benefit. If you're suggesting I properly propose switch implicit break { ... } I will consider doing that, thank you.
I know this isn't a big problem, I hardly care about it myself. But it sure would be a nice change. At the core of my issue with how switch works at the moment, I just hate how it shares scope between cases, but it's too late to change that now.

@CyrusNajmabadi
Copy link
Member

Sounds good to me.

@nvmkpk
Copy link
Author

nvmkpk commented Mar 15, 2018

I personally don't see the current situation with switch/case/break is problematic enough to warrant a change here.

Only problem with current situation is scope sharing. No other code construct does that.

Whether or not i have to specify 'breaks' in my switch doesn't actually appreciably change the utility or power of switches, and so it doesn't really end up substantively impacting as much as other proposals would.

This proposal is not to change the power of switches. Implicit break is only for the case when we put braces. Existing syntax would not change in any way. The switch code snippet would remain same as it is now. The proposed syntax makes case blocks work more like all other blocks in the language.

@jnm2
Copy link
Contributor

jnm2 commented Mar 15, 2018

Only problem with current situation is scope sharing. No other code construct does that.

Goto does that, and that's the most literally similar construct to a switch statement that I can think of.

@nvmkpk
Copy link
Author

nvmkpk commented Mar 15, 2018

Goto does that, and that's the most literally similar construct to a switch statement that I can think of.

But everyone say goto is evil and I haven't seen anyone using it in my entire career. But switch/case is used much more.

@jnm2
Copy link
Contributor

jnm2 commented Mar 15, 2018

@nvmkpk Nevertheless, it's not true that no other code construct does that. You can't ignore the context and history of the switch statement.

@CyrusNajmabadi
Copy link
Member

But everyone say goto is evil

Clearly, C# does not say that :)

I haven't seen anyone using it in my entire career

It is used int the Roslyn codebase itself :)

@kameko
Copy link

kameko commented Mar 15, 2018

Goto does that, and that's the most literally similar construct to a switch statement that I can think of.

switch is used far more than goto, and often scope sharing is desired when using goto, whereas it's not as much when using switch

@jnm2
Copy link
Contributor

jnm2 commented Mar 15, 2018

I guess it is fair to say that if you don't use goto case in a certain instance, then scope sharing doesn't make sense. But it's weirder to have the scope magically adjust as soon as a goto case shows up.

@nvmkpk
Copy link
Author

nvmkpk commented Mar 17, 2018

Let's not debate about goto. The point here is about scope sharing in switch case.

@quinmars
Copy link

I'd like to have implicit breaks in C#, but without that brace restriction. I doubt, however, that the benefit is great enough to break through the 100 points line.

@BannZay
Copy link

BannZay commented Sep 5, 2018

For me must be significant reason to use switch instead of if/else. switch is a monster who eats space.
Both my hands is up for explicit break (preferable without additional brackets restriction)

@jnm2
Copy link
Contributor

jnm2 commented Sep 5, 2018

@BannZay The new expression form of switch will be much better for many things.

@YairHalberstadt
Copy link
Contributor

closing as duplicate of #3038 which is championed, and covers this and more

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants