If you could make breaking changes to C#, what would you do?
-
@lucas1 By definition, the block ends where the next one begins.
-
@masonwheeler except you can fall through a case statement.
-
@lucas1 said in If you could make breaking changes to C#, what would you do?:
@raceprouk when? I didn't say anything to do with ending a case block. I said about it falling through.
Since you have to end a
case
block withbreak
,throw
, orgoto case
, a case will not fall through. You can't leavegoto default
out.
-
@lucas1 For fuck's sake, it's really fucking simple: you must end a
case
with eitherbreak
,throw
, orgoto case
because YOU CANNOT FALL THROUGH CASES IN C#.
-
@lucas1 said in If you could make breaking changes to C#, what would you do?:
@masonwheeler except you can fall through a case statement.
That's what everyone is telling you. You can not fall through, not in C#. It's specifically forbidden by the language definition.
-
Except you can because you can stack case statements and then end them with that stuff.
FFS that is falling through.
using System; public class Example { public static void Main() { Random rnd = new Random(); int caseSwitch = rnd.Next(1,4); switch (caseSwitch) { case 1: Console.WriteLine("Case 1"); break; case 2: case 3: Console.WriteLine($"Case {caseSwitch}"); break; default: Console.WriteLine($"An unexpected value ({caseSwitch})"); break; } } } // The example displays output like the following: // Case 1
It is there in the MSDN docs @abarker linked FFS.
-
@lucas1 said in If you could make breaking changes to C#, what would you do?:
Except you can because you can stack case statements and then end them with that stuff.
FFS that is falling through.
Okay. Good luck with your C# endeavors.
-
@lucas1 That's not falling through, that's one block with two labels.
-
@raceprouk If you say so, to everyone else that is falling through.
Like most devs in the UK.
-
@heterodox Cheers.
-
@lucas1 said in If you could make breaking changes to C#, what would you do?:
@raceprouk If you say so, to everyone else that is falling through.
Like most devs in the UK.
Of course. Yep. You're right and everyone else is wrong. Keep up the good fight.
-
@raceprouk said in If you could make breaking changes to C#, what would you do?:
@lucas1 For fuck's sake, it's really fucking simple: you must end a
case
with eitherbreak
,throw
, orgoto case
because YOU CANNOT FALL THROUGH CASES IN C#.Well, I believe that there are two other possible ways to end a case block:
return
, or a loop that is always endless (while (true) Console.WriteLine("Endless looping. . . .");
).
-
-
@heterodox Cheers dude. It is nice for the support.
-
@abarker well since the compiler converts case statements into if else statements then a return will always break out of the method that it is in.
-
@raceprouk What is the difference? The default case state will always be executed if the value is outside of what is specified with the case keyword.
-
@lucas1 said in If you could make breaking changes to C#, what would you do?:
@raceprouk If you say so, to everyone else that is falling through.
Like most devs in the UK.
Except it's not falling through. Applying an 'or' to the possible cases does not count as falling through.
This is a multi-label case:
case 1: case 2: //executes for both 1 and 2 Foo(); Bar();
This is falling through:
case 1: Foo(); case 2: //executes for both 1 and 2 Bar();
The former is allowed. The latter isn't, and furthermore is what we're talking about here.
I can't tell if you're trolling or not. I really can't.
-
@lucas1 said in If you could make breaking changes to C#, what would you do?:
Except you can because you can stack case statements and then end them with that stuff.
FFS that is falling through.
using System; public class Example { public static void Main() { Random rnd = new Random(); int caseSwitch = rnd.Next(1,4); switch (caseSwitch) { case 1: Console.WriteLine("Case 1"); break; case 2: case 3: Console.WriteLine($"Case {caseSwitch}"); break; default: Console.WriteLine($"An unexpected value ({caseSwitch})"); break; } } } // The example displays output like the following: // Case 1
It is there in the MSDN docs @abarker linked FFS.
The spec makes a differentiation, though. Each block of code is considered a "switch section", and each case (or default) is considered a "case label". As the spec says:
… each section can have one or more case labels …
…
C# does not allow execution to continue from one switch section to the next."Fallthrough" is when control goes from one section to the next.
Given this explanation, the example you keep giving shows a section with multiple labels. It does not demonstrate fallthrough.
ETA: Pretty much what @pie_flavor just said.
-
Well it the opposite of what I had thought. Okay I was wrong.
It never really changed how I programmed.
-
@pie_flavor said in If you could make breaking changes to C#, what would you do?:
Except it's not falling through. Applying an 'or' to the possible cases does not count as falling through.
This is a multi-label case:
case 1: case 2: //executes for both 1 and 2 Foo(); Bar();
This is falling through:
case 1: Foo(); case 2: //executes for both 1 and 2 Bar();
I can't tell if you're trolling or not. I really can't.
He's not trolling and he's not an illiterate cunt; obviously, your first example there is falling through in the UK. @RaceProUK wouldn't know that.
-
@abarker said in If you could make breaking changes to C#, what would you do?:
@raceprouk said in If you could make breaking changes to C#, what would you do?:
@lucas1 For fuck's sake, it's really fucking simple: you must end a
case
with eitherbreak
,throw
, orgoto case
because YOU CANNOT FALL THROUGH CASES IN C#.Well, I believe that there are two other possible ways to end a case block:
return
, or a loop that is always endless (while (true) Console.WriteLine("Endless looping. . . .");
).return
is valid, but I'm not sure if the compiler will allow an infinite loop, mainly because I'm not sure if it enforces it during the lexical analysis or flow analysis stages.
-
@raceprouk The compiler will because it will allow infinite recursion.
-
@raceprouk The spec gave an example of it being acceptable. Why you would want to, I don't understand. But it is supposed to get past the compiler, I guess.
-
@heterodox I said I was wrong. I am not a "proper" programmer.
-
@lucas1 said in If you could make breaking changes to C#, what would you do?:
@raceprouk The compiler will because it will allow infinite recursion.
Recursion has fuck all to do with an infinite loop. Not to mention that infinite recursion's gonna blow the call stack a new arsehole.
@abarker said in If you could make breaking changes to C#, what would you do?:
@raceprouk The spec gave an example of it being acceptable. Why you would want to, I don't understand. But it is supposed to get past the compiler, I guess.
Must enforce it at the flow analysis stage then. I'd have enforced it at the lexical analysis stage myself, but
-
@raceprouk said in If you could make breaking changes to C#, what would you do?:
Recursion has fuck all to do with an infinite loop. Not to mention that infinite recursion's gonna blow the call stack a new arsehole.
well that depends how you put that loop together. You can do a recursive infinite loop without blowing the stack.
-
@raceprouk I mean, all you really need to do is ensure it never leaves the case statement. Enforcing specific keywords muddles matters, especially when you consider that there could be complicated flow determining which exit action is taken.
-
@lucas1 said in If you could make breaking changes to C#, what would you do?:
@raceprouk said in If you could make breaking changes to C#, what would you do?:
Recursion has fuck all to do with an infinite loop. Not to mention that infinite recursion's gonna blow the call stack a new arsehole.
well that depends how you put that loop together. You can do a recursive infinite loop without blowing the stack.
Only with tail call optimisation, which C# doesn't do. And yes, it's a major failure of the language, especially as .NET itself does it.
-
@raceprouk As I said I am not a "real" programmer. I have no idea what tail optimisation means. Nor do I care.
I am just a web developer who knows a lot of C#.
-
@raceprouk said in If you could make breaking changes to C#, what would you do?:
And yes, it's a major failure of the language, especially as .NET itself does support it.
There are IL commands available for tail-call functionality, but I'm not aware of any major language that uses them.
-
@masonwheeler But why would I care?
99% of my C# programming is boring boiler plate shite.
The odd time I might get to abuse reflection to make a library do what I want.
-
@masonwheeler said in If you could make breaking changes to C#, what would you do?:
@raceprouk said in If you could make breaking changes to C#, what would you do?:
And yes, it's a major failure of the language, especially as .NET itself does support it.
There are IL commands available for tail-call functionality, but I'm not aware of any major language that uses them.
The only .NET language I know definitely does support it is F#, which isn't exactly mainstream.
-
@lucas1 said in If you could make breaking changes to C#, what would you do?:
@raceprouk As I said I am not a "real" programmer. I have no idea what tail optimisation means. Nor do I care.
I am just a web developer who knows a lot of C#.
If you don't understand the topic, then why are you arguing it?
-
@lucas1 said in If you could make breaking changes to C#, what would you do?:
As I said I am not a "real" programmer. I have no idea what tail optimisation means. Nor do I care.
It's literally the thing that makes it possible to do recursion at an arbitrary depth--including infinite--without blowing the stack. If your compiler doesn't implement it, then that's not possible.
-
@masonwheeler WAT? I am a not a real programmer. I have no idea what this means.
-
@raceprouk said in If you could make breaking changes to C#, what would you do?:
The only .NET language I know definitely does support it is F#, which isn't exactly mainstream.
Does it? I was under the impression that F# had poor support for recursion in general, due to its ML heritage.
-
@masonwheeler said in If you could make breaking changes to C#, what would you do?:
@raceprouk said in If you could make breaking changes to C#, what would you do?:
The only .NET language I know definitely does support it is F#, which isn't exactly mainstream.
Does it? I was under the impression that F# had poor support for recursion in general, due to its ML heritage.
You need to explicitly mark a function as recursive, but as far as I'm aware, recursion support is no worse than most languages. Then again, I've never used F#.
-
@sloosecannon said in If you could make breaking changes to C#, what would you do?:
@cheong said in If you could make breaking changes to C#, what would you do?:
functionally identical to the previous version.
That shouldn't matter. What should matter is if it's functionally identical to the specs.
That's if the said "spec" still exists.
In my experience, since the customers/users change the spec. lots of time, the spec. most function will split into fragments in multiple emails / conversations of email.
What's more, especially when I worked for some government department's renewal project, for some function no one in the department know what logic it actually supposed to do, as those who know about it had retired like 30 years ago.
When no one can make sure what is the complete spec, the next best you could aim for is the code that customer had supposed verified in UAT.
So when refactoring, usually the target is "function identical to original code" instead of "function confirming to certain spec."
-
@lucas1 Did you choose the gorilla avatar because you wanted to give people the impression you were smarter than you actually are?
-
@pie_flavor said in If you could make breaking changes to C#, what would you do?:
@dreikin said in If you could make breaking changes to C#, what would you do?:
@zecc said in If you could make breaking changes to C#, what would you do?:
@cheong said in If you could make breaking changes to C#, what would you do?:
"Efficiency to type" is rarely a bottleneck to development speed because after all, we need to think before we type. On the other hand, lacking "efficiency to read" will cause all kinds of maintainability problem, make beginners difficult to pick up the language, and make the code more error prone.
Why I'm for mandatory braces and semicolons.
Because you like to make things harder on newbies, thus holding off your competition?
Uh, what? Is the goal here to make a language that's easy for newbies to pick up, or to make a language that does its job cleanly? The stated point was that mandatory braces and semicolons make code that's mandatorily easier to read.
I'd argue the other way (thus the popularity of python in academic and other non-professional-programmer contexts). Braces and line-ending sigils are more work to keep track of and get right than simple visual arrangement (indentation and automatic line endings). The advantages C-style blocking supposedly has come with a cost: making code more cluttered and subject to difficult-to-find errors (find the lost semi-colon, make sure the braces match what the indentation leads you to believe they should be, scoping errors (Apple's goto fail bug), etc).
-
@pie_flavor said in If you could make breaking changes to C#, what would you do?:
@masonwheeler said in If you could make breaking changes to C#, what would you do?:
@pie_flavor said in If you could make breaking changes to C#, what would you do?:
The stated point was that mandatory braces and semicolons make code that's mandatorily easier to read.
I don't agree.
Console.WriteLine("Hello, World!");
Console.WriteLine("Hello, World!")
Is one of those any harder to read than the other? And on a related note, if you had the latter embedded in the middle of a 20-line method, is there any obvious reason to believe something's wrong with it before the compiler screams at you?
How about this Kotlin code?
val value = Foo() .doSomething(bar)
Linebreak indicates the separation of ideas. You could easily interpret
value
to be simply a newFoo
object, since semicolons aren't required. But that's not the case - it's the result ofdoSomething
. A noob could easily misread that. It's also harder on the parser, for the same reason.A noob can easily mess something up with braces+semicolons too:
if ((err = SSLFreeBuffer(&hashCtx)) != 0) goto fail; if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail; goto fail; if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) goto fail;
-
@lucas1 said in If you could make breaking changes to C#, what would you do?:
@abarker No you just leave the goto out. I am sure I said that you can fall through swtich statements.
You could put in the goto default but it is defunct, unless you have a more case statements.
Sorry this isn't the gotcha that you think it is.
-
@abarker said in If you could make breaking changes to C#, what would you do?:
@raceprouk The spec gave an example of it being acceptable. Why you would want to, I don't understand. But it is supposed to get past the compiler, I guess.
Event loops that exit in an inobvious way?
@raceprouk said in If you could make breaking changes to C#, what would you do?:
Recursion has fuck all to do with an infinite loop. Not to mention that infinite recursion's gonna blow the call stack a new arsehole.
What about tail c—
@masonwheeler said in If you could make breaking changes to C#, what would you do?:
@raceprouk said in If you could make breaking changes to C#, what would you do?:
And yes, it's a major failure of the language, especially as .NET itself does support it.
There are IL commands available for tail-call functionality, but I'm not aware of any major language that uses them.
The linked proposal above suggest both that F# uses it and that F# instead rewrites them into a loop. It also suggests the JITer will do it if it thinks it profitable.
@lucas1 said in If you could make breaking changes to C#, what would you do?:
@masonwheeler WAT? I am a not a real programmer. I have no idea what this means.
From here:
Inside your computer, as Sean Hargreaves has informed us, are lots of little elves who scribble away at fantastic speeds, doing all the calculations that we programmers throw at them. Each elf has his own little pile of paper on which he jots the results of his sums. As you would expect, the elves need to be very methodical, and they follow a particular system.
Imagine that Charles, Chief Processing elf, is working his way through a function. He scribbles busily on his piece of paper, humming to himself as he notes down the result of each calculation (that's him you can hear if you stick your head next to the case). Then his instructions tell him that he's got to call another function. So he reaches out, grabs a fresh piece of paper, writes the name of the function at the top (and underlines it) together with the values of the parameters, and then plugs away at it. When he gets to the end, and has found his answer, he screws the paper up, and throws it over his shoulder (ever wondered why your case gets clogged up with so much dust?). He writes the answer on the piece of paper now at the top of the pile, right where he left off before the function call.
So you see, for each nested function call, his pile of paper gets one sheet taller. If we give poor Charles a recursive function to work on, the pile will grow and grow and grow, and he'll never be able to chuck any pieces away. As the pile grows, he has to stand on his chair to reach the top. Then he has to fetch a stepladder. The pile keeps on growing. Now he's standing on tip-toes, and then, as he reaches out to get a fresh sheet for his next function call, Catastrophe! He wobbles, the ladder falls, the pile topples. Stack Overflow!
(You can make all this tie up with what Wikipedia says if you know that Charles calls his pile of paper a "Call Stack", and each piece on it a "Stack Frame").
Some Compilers (like the F# compiler for instance) are kind to poor Charles, and change his instructions slightly to help him avoid accidents. It can do this when the final instruction in a function is to call another function and immediately return its result. This is called a Tail Call. If the last instruction of a recursive function is the recursive call, then we call that Tail Recursion. You'll notice that the function we created last time for factoring primes is tail recursive.
So what can the compiler do? Well, because the last instruction Charles has to carry out is to call the next function and then return its result, he knows that he doesn't need to keep his workings-out for the current function - he isn't going to need them again. So the compiler can tell Charles that, rather than starting a fresh sheet of paper, he can scrub his current one with his eraser and reuse it for the next function. To put it more boringly, the function is changed so that rather than making a call, it does a goto back to the top of the function, and thus avoids using a new Stack Frame.
Unfortunately, the C# compiler has no compassion for poor elves, and does nothing to help them avoid Stack Overflow (though in certain circumstances the .Net Just-In-Time compiler does help out a bit ).
-
The JIT can help by using tail call optimizations... except for when it hurts instead.
-
@unperverted-vixen said in If you could make breaking changes to C#, what would you do?:
The JIT can help by using tail call optimizations... except for when it hurts instead.
This issue is narrow in nature. Your code has to use specific data types, pass them in specific ways and execute specific operations. Very few programs will satisfy all of these characteristics, which is required to trigger this codgen bug. We have reviewed this issue to determine if it is exploitable. We have not identified an exploit, but are pushing the change through our process at the same pace as we would an exploit.
"It's unlikely to happen, and we don't think it's exploitable, but we're going to be careful and treat it like it is anyway"
-
@dreikin said in If you could make breaking changes to C#, what would you do?:
@pie_flavor said in If you could make breaking changes to C#, what would you do?:
@masonwheeler said in If you could make breaking changes to C#, what would you do?:
@pie_flavor said in If you could make breaking changes to C#, what would you do?:
The stated point was that mandatory braces and semicolons make code that's mandatorily easier to read.
I don't agree.
Console.WriteLine("Hello, World!");
Console.WriteLine("Hello, World!")
Is one of those any harder to read than the other? And on a related note, if you had the latter embedded in the middle of a 20-line method, is there any obvious reason to believe something's wrong with it before the compiler screams at you?
How about this Kotlin code?
val value = Foo() .doSomething(bar)
Linebreak indicates the separation of ideas. You could easily interpret
value
to be simply a newFoo
object, since semicolons aren't required. But that's not the case - it's the result ofdoSomething
. A noob could easily misread that. It's also harder on the parser, for the same reason.A noob can easily mess something up with braces+semicolons too:
if ((err = SSLFreeBuffer(&hashCtx)) != 0) goto fail; if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail; goto fail; if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) goto fail;
That only showcases why braces should be required.
-
@pie_flavor said in If you could make breaking changes to C#, what would you do?:
@dreikin said in If you could make breaking changes to C#, what would you do?:
@pie_flavor said in If you could make breaking changes to C#, what would you do?:
@masonwheeler said in If you could make breaking changes to C#, what would you do?:
@pie_flavor said in If you could make breaking changes to C#, what would you do?:
The stated point was that mandatory braces and semicolons make code that's mandatorily easier to read.
I don't agree.
Console.WriteLine("Hello, World!");
Console.WriteLine("Hello, World!")
Is one of those any harder to read than the other? And on a related note, if you had the latter embedded in the middle of a 20-line method, is there any obvious reason to believe something's wrong with it before the compiler screams at you?
How about this Kotlin code?
val value = Foo() .doSomething(bar)
Linebreak indicates the separation of ideas. You could easily interpret
value
to be simply a newFoo
object, since semicolons aren't required. But that's not the case - it's the result ofdoSomething
. A noob could easily misread that. It's also harder on the parser, for the same reason.A noob can easily mess something up with braces+semicolons too:
if ((err = SSLFreeBuffer(&hashCtx)) != 0) goto fail; if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail; goto fail; if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) goto fail;
That only showcases why braces should be required.
Alternatively, if indentation were significant it would already work exactly as intended. (Although with a competent compiler it should error/warn about unreachable code in either case.)
-
The #1 feature I'd like to see in C# is LINQ to XML.
"But wait TwelveBaud, it already has it!" I hear someone say. Well... yes. Technically. But also no.
Dim customer = _ <customer> <name> <firstName>John</firstName> <lastName>Smith</lastName> </name> </customer>
// Usings omitted var customer = new XElement("customer") { new XElement("name") { new XElement("firstName") { Value = "John" }, new XElement("lastName") { Value = "Smith"} } };
Dim customerName = String.Format("{0}, {1}", customer..<name>.<lastName>, customer..<name>.<firstName>)
var customerName = string.Format("{0}, {1}", customer.Descendant("name")?.Element("lastName")?.Value, customer.Descendant("name")?.Element("firstName")?.Value);
True, there's not much different in this toy example, but when writing something to transform a whole bunch of XML call data records with all kinds of crazy queries going on, it's really helpful to have those shortcuts rather than type the XElement boilerplate out by hand. Plus, if you use XML literals, you even get Intellisense while typing queries against it.
-
@twelvebaud I agree with whoever said that Scala had too much magic (I think it was this thread) but XML integration is one of my favorite parts of it.
-
@twelvebaud said in If you could make breaking changes to C#, what would you do?:
Dim customer
Tell us what you really think! ;)