19 ms·
What’s New in C# 7.0
- ComputerGuru 10y agoMy instant concern: the variable names used by function declarations have become part of the API. If you use var to match the library producer's naming for tuple members, a rename of the variable in the definition will break your code, as the name you previously used will no longer exist! Old example: bool Hello(string name) {...} var myName = "world"; Hello(myName); The developer can change the name of variables in the prototype to be more (or less!) descriptive without a problem - they're decoupled. New example: (string interjection, string name) GenerateGreeting() {...} var greeting = Greeting(); Console.Write("{0} {1}", interjection, name); Now should the author change "interjection" to "greeting", _ your code won't compile _ and in a way that you likely didn't expect.
- bhrgunatha 10y agoI assumed they are still decoupled and just shorthand for: string interjection; string name; (interjection, name) = GenerateGreeting() {...} I can't believe the C# team would introduce something so brittle into the language. If you're right, that a serious concern.
- halestock 10y agoAgreed, I would much prefer something like: (string first, string last) name = GetName();
- ajanuary 10y agoThe names of the tuple field are a part of the method signature. Would you expect to be able to change other parts of the method signature, like the method name or argument types, and not have stuff break? [edit] unless you're talking about how your example magically introduces "interjection" into the scope. That's not how it works. You would have to say "greeting.interjection". Or use the destruction syntax and say "var (ichosethis, andthis) = generateGreeting();", in which case its the order of the fields, not the name of them, that is important.
- hokkos 10y agoI think named tuple parameters only matters when not deconstructed, when deconstructed the position matter and you can choose your name. If you don't want to take that risk don't name your output parameters. But that's the same as named parameter, and you didn't complained, if the client used named parameters and you change them it will break their code. The full signature of the method is the public API, as you can see when navigating a compiled assembly.
- sergiotapia 10y agoI thought pattern matching in C# would look like pattern matching in Elixir. For example, two functions with different signatures run based on the parameters you give it. def hello("sergio") do IO.puts "Hello Sergio" end def hello(name) do IO.puts "Hello #{name}" end --- hello("sergio") => "Hello Sergio" hello("mia") => "Hello mia"
- daxfohl 10y agoIsn't that more an example of `multiple dispatch` rather than `pattern matching`?
- sergiotapia 10y agoIn Elixir land it's been taught to me as pattern matching. I have never heard of `multiple dispatch`.
- muhmi 10y agoBoth :) You can pattern match in function head (definition) http://elixir-lang.org/getting-started/pattern-matching.html http://elixir-lang.org/getting-started/pattern-matching.html
- MichaelGG 10y agoWill C# ever start to increase type inference to make it less verbose? Local functions are ok. But why not lambda syntax+inference? Probably still because of making quoted code have ambiguous syntax. But this ends up adding noise and increases the barrier on deciding when to put code into a tiny function. When using C# I'm constantly noticing how much extra code there is. It's just frustrating, and I don't feel like I'm getting a unique benefit in return (unlike, say, in Rust). I know F# would be more concise and work just as well. But I know it's not easy extending the existing design decisions. (The tuple story is sad, eh? This was F#'s original design, using structs. Then they made peace with the strange heap allocated framework tuple. And now...? No tuple interop?) Anyways, congrats, C# definitely is the best general dev language commonly accepted at a large amount of companies, especially when factoring in tooling.
- snaky 10y ago> how much extra code there is. It's just frustrating, and I don't feel like I'm getting a unique benefit in return (unlike, say, in Rust) Actually you are getting a benefit in return (unlike, say, in Rust) - the libraries. Verbose syntax is less complex in regard to writing the code, so more developers write the code. I have no scientific evidence to provide about the fact, but observations speak for themselves. Compare the quantity of libraries available for Rust and yet another 'overly verbose' language, Go. We can find Go wrapper for almost anything, and often a few to chose from.
- mcsofake 10y ago> Compare the quantity of libraries available for Rust and yet another 'overly verbose' language, Go. We can find Go wrapper for almost anything, and often a few to chose from. Rust was stabilized last year, while Go was released six years ago. It is simply wrong to say that Go has a larger quantity of libraries because it is more verbose. IMHO the Rust ecosystem is surprisingly comprehensive for a language its age.
- MichaelGG 10y agoNo benefit over F# is what I mean - nothing about .NET requires C# to be verbose. With Rust, there's zero alternative that'll have the same guarantees and performance. So I can put up with the verbosity.
- flukus 10y agoOut variables seem like a mis-feature, especially when they are adding a better alternative (Tuples) in the same release. It's great to finally have tuples, but the c/java style syntax is showing it's age compared to something like scala which has return type declarations at the end, which I find much more readable. Literal improvements will be a godsend for writing database migrations. Ref returns and locals look like a source of constant headaches. It's much harder to reason with code when the data can be modified by random others bits of code. Currently I can look for all references to an array to find everywhere that modifies it now I can't.
- clusmore 10y ago>Out variables seem like a mis-feature, especially when they are adding a better alternative (Tuples) in the same release. You can't retro-fit multiple-returns (via Tuples) onto existing library functions, so for places where you're forced into using out parameters, this is a slight improvement.
- jameshart 10y agoSure you can - you can introduce a new overload resolution rule that lets you treat trailing out params on a method as tuple members, so a method TReturn Foo(T1 param1, out T2 param2) can be called as if it were (TReturn, T2) Foo(T1 param1) You'd need a keyword to trigger this kind of overload resolution at the call site to ensure back compatibility - maybe you'd have to call (var x, var y) = out Foo(param); or something. That way all that legacy library code gets a free upgrade to your new language feature. Since the C# team decided not to do that, you can actually implement a version of this at a library level, by static importing a family of generic methods like this: Func<TParam, (T1, T2)> Tuplify<TParam,T1,T2>(Func<TParam, out T1, T2> outFunc) {...} for every pattern of out params you want to convert, then you can just call (var x, var y) = Tuplify(Foo)(param);
- deleted 10y ago[deleted]
- merb 10y agoI've seen some p/invoke examples where out variables are used as a c pointer.
- deleted 10y ago[deleted]
- dleslie 10y agoIt looks like they've added a lot of rope to hang ourselves with typos. int myvar, I; foo(out int mvar); // oops, not myvar; maybe caused by a refactor? bar(out *); // oops, not I; was up too late coding And so on. Things like this would be easily missed when reading code at-a-glance, and it's this sort of bug that arises often in languages that allow implicit declaration of variants.
- addicted 10y agoThe first one requires 2 errors. Reinitializing a variable (if you intended to use myvar then you wouldn't need to put int after your out) and compounding it with a misspelling. This is no different from how you'd make the same mistake today. I'm not happy about wild cards. It seems like taking what is a very powerful character in software development and using it for a pretty minor usability improvement. Besides it seems misleading. When I see an asterisk I don't think throwaway. I can see how that aligns with "anything can go here" meaning from regex, but I feel there is a difference in "value". Using a * in a regex seems to increase the power and heft of the regex, where as using it here, seems to decrease the value, which is almost the opposite effect. Another way of putting it is that the point should be to let me ignore this while reading code, but the asterisk draws my attention to it instead. Compare this to the Haskell convention of using an _ for throwaway items, which disappears just enough, instead of attracting attention. And by simply being a convention, it isn't giving the character too much power. Not sure if lack of Haskell style type inference prevents C# from using convention for throwaways instead of wildcard chars, but I think it would be much less overhead on the Dev.
- douche 10y agoIt does seem silly, considering that F# already uses _ as a "don't care" wildcard, and it's a pretty common pattern already in C# lambda-heavy code to use the underscore for the same idea.
- taspeotis 10y agoR# should warn "unused variable myvar" on the first one. You'll get a compiler error if you try and use `I` uninitialized. Not saying you're wrong, just having trouble getting worried about this. You can make typos now: int x, y; foo(out x, out x); // oops, not y; was up too late coding
- statictype 10y agoLike everything except "Ref returns and locals". I don't think I've ever seen a case where I wished for that feature. All the other things - tuples, anonymous out vars, pattern matching - I've found myself wanting quite often.
- taspeotis 10y agoI believe ref returns are a performance feature. They seem a bit like move constructors in C++ in that they can save you a copy? But I am not confident I understand the nuances of move constructors to compare them properly.
- johncolanduoni 10y agoThey don't move anything, they are either pointers to a value on the stack or to a field in an object on the heap. The first is more like how standard C++ references are usually used, and the second are interior pointers like Go has. No code gets executed to make them happen, and no data is copied.
- deleted 10y ago[deleted]
- statictype 10y agoLike everything except "Ref returns and locals". I don't think I've ever seen a case where I wished for that feature. All the other things - tuples, anonymous out vars, pattern matching - I've found myself wanting quite often.
- diego_moita 10y agoSometimes it feels like we're entering a new age of coding. C# is so full of "features" that code refactoring tools like ReSharper, CodeRush and JustCode became simply indispensable. It is quite hard to be sure, every time, what is the most elegant/compact way of doing things. In the .Net/VisualStudio world, the language tooling (Intelisense, visual drawing XAML & WinForms, etc) became as important as the language semantics or the availability of frameworks and documentation. A long ago there was a fad, known as CASE (Computer Aided Software Engineering) that advocated doing on programming what CAD did to other engineering. It seems that were finally getting there.
- pjmlp 10y agoThat type of programming never went away. That is what I was doing on Windows 3.x and have done while coding in Mac OS X and Windows. Also the reason I never quite adapted to UNIX mentally of VI/Emacs. Even though I have spent enough years coding for UNIX that me and Emacs are quite old acquainted with each other.
- caseymarquis 10y agoThere's a Vi plugin for almost everything. Highly recommend VsVim for visual studio.
- pjmlp 10y agoExcept I don't like VI at all. I know the essential for when Emacs isn't available which is quite common on commercial UNIX installations, learned back when Xenix was still being sold and don't intend to learn more than that. Thanks anyway, I know you had good intentions.
- int_19h 10y agoI don't know about that. I'm working on a codebase that heavily uses C# 6.0 features, and for the most part, the "most elegant/compact way of doing things" is disseminated via code reviews, and quite fast at that. Convenient things stick around and become idiomatic precisely because they're convenient. Then again, you don't have to always go for the most elegant/compact thing, either.
- joeax 10y agoSince C# is starting to look more like JavaScript (i.e. local functions) and vice versa (i.e. arrow aka lambda expressions). I'm going to throw my pocket change into a couple features I've been growing old hoping to see: 1. Regex expressions just like Regexp in JS: /^\s+$/.IsMatch(" "); // or Regex r = /^\s+$/; 2. DateTime expressions, similar to regex, something like: DateTime clockTowerLightning = #1955/11/12 10:04PM#;
- pjmlp 10y agoAlgol and Lisp already had local functions....
- MichaelGG 10y agoThe first is almost certainly better off as it is in F#: active patterns. That'll let you define patterns that'll execute arbitrary code to match, making regex a simple library feature, vs a special one-off. C# should have focused on having proper extensible syntax vs hard coding random features (like duck typed foreach or collection initializers). But given the constraints of mscorp and the target users perhaps they made the right decisions.
- Jtsummers 10y agoTo be clear, local functions long predate Javascript. Though a handy regex notation would be nice, I could've used that on a couple projects that I had (corporate environment) to do in C# when it wasn't really best suited to the task (at least in terms of brevity/clarity compared to other languages like python or perl for generating reports and similar behaviors.
- Pharylon 10y agoDateTime literals... something I wish C# would borrow from VB.NET
- mintplant 10y ago> 1. Regex expressions just like Regexp in JS: I don't know about the current state of C#'s grammar, but ambiguities between this regex construct and eg. division contributes to the complexity of correctly parsing JavaScript code. https://tc39.github.io/ecma262/#sec-ecmascript-language-lexical-grammar https://tc39.github.io/ecma262/#sec-ecmascript-language-lexi...
- platz 10y agoI wish they did not call it pattern matching. Instead this is more like Destructuring combined with Switch. the guarantees are different
- int_19h 10y agoIf you look at the original specs on Roslyn GitHub, it started as a more generalized extensible pattern matching system (tying into destructuring). I would imagine that this is still in the plans, but it just didn't fit into this version.
- platz 10y agoyes I'm aware and participated in some of the discussions.
- edgyswingset 10y ago"Full" pattern matching, as one would expect from F# for example, wouldn't be something I could expect from C#. For example: type Tree<'a> = Empty | Node of 'a * Tree<'a> * Tree<'a> There is no way to express this directly in C#. Thus, I am "locked out" of a whole class of Pattern Matching that I would get with F#. But that doesn't mean that C#-style pattern matching (really, Is-patterns and a Type Switch) don't fall under the umbrella of Pattern Matching. You can define tuple patterns that you can match on with the switch statement in C#, which is every bit a form of pattern matching as matching on a particular case of a union type.
- platz 10y ago> C#, is every bit a form of pattern matching as matching on a particular case of a union type. I'm afraid that is not the case, because in the current C# version, the compiler does nothing help you determine if you've matched all the possibilities. (it is not exhaustive) Exhaustiveness is important because it gives warning or an error to help you refactor and modify code without fear of breaking other code. Why engage in all the static typing business if the compiler is not going to help you refactor things? This is important in the same way that adding a subclass requires exhaustively supplying all the abstract methods (true pattern matching is "dual" to adding a subclass; you use the compiler feedback to direct what actions to take next. you can't do this with the Switch based formulation because you don't get any feedback from the compiler if you missed cases or have refactored other code to add cases (for example, adding/refactoring abstract methods in a base class provides feedback on where to add/update methods in the subclasses)
- Sir_Cmpwn 10y agoIn the binary literal proposal there is also some unresolved discussion about octal support, chip in if you like: https://github.com/dotnet/roslyn/issues/215 https://github.com/dotnet/roslyn/issues/215
- Jtsummers 10y agoI wish more languages would take a radix-agnostic approach (at least to a reasonable limit). What's wrong with: 2#1010101 8#75342 1341235 10#13451 16#feb1300 radix#value, from erlang. Or: #b10101 #xfefe #o7777 #36rSSSS From common lisp. Customize in some fashion for C# and its current notations for hex and (now) binary literals. 036rSSSS 02r10101 0b10101 // this and above are equal
- Retra 10y agoThe reason people don't do this is: 1. Our current base notation is already familiar and widely used. Nobody is confused about 0xA vs 0b10. 2. Nobody will really use those other bases, so you're adding obscure features that muddle your syntax.
- mintplant 10y agoPattern matching! Tuples! Awesome, C# 7.0 is scratching two itches I've felt every time I've worked with it. If only .NET had a suitable cross-platform UI toolkit, then I'd be using it everywhere. Eto.Forms is a good attempt but I found rather buggy and limited at this point in development. Avalonia, while further along in terms of stability and features, doesn't even try to fit in with any platform's look and feel.
- jimmaswell 10y agoWhy not winforms? Very convenient, and mostly works in mono
- Aeolos 10y agoWinForms is a dead end. It doesn't support Windows modern or Mac OS X, and it looks completely out of place on Linux.
- snaky 10y ago> It doesn't support Windows modern That's a good thing. > or Mac OS X "Does Winforms run on OSX? Yes, as of Mono 1.9, Winforms has a native OSX driver that it uses by default" http://www.mono-project.com/docs/faq/winforms/ http://www.mono-project.com/docs/faq/winforms/ > it looks completely out of place on Linux On KDE3? KDE4? KDE Plasma? Gnome2? Gnome3? MATE? Cinnamon? LXDE? LXQt? Xfce? CDE? GnuStep? Unity? Enlightenment? Non-DE X Window System environment - with which Window Manager, with which theme?
- jsight 10y agoI'm pretty sure that it looks out of place in all of the Deskktop environments that you have mentioned.
- creshal 10y agoGoing by the documentation you linked yourself: > In terms of integrating visually with the desktop, we currently ship with a classic Win32 theme. That sticks out like a sore thumb everywhere, including every Win32 release since Windows 2000.
- daxfohl 10y agoAll I want is easy syntax for immutable records, and C#-like a fluent syntax for .WithPhoneNumber(phoneNumber) etc. Seems like it'd be a cinch to implement, and for me the single handiest feature from F#. In F# these are "guaranteed" to be non-null, even though null instances come up during deserialization all the time. In C# use cases, I don't think the non-null "guarantee" should be made or implied, just a POCO.
- CyrusNajmabadi 10y agoHi there! C# language designer here. You can see (and participate in) the discussion on records here if you'd like: https://github.com/dotnet/roslyn/issues/10154 https://github.com/dotnet/roslyn/issues/10154 > Seems like it'd be a cinch to implement Ah... how i wish that were so :)
- daxfohl 10y agoIndeed. While records are my favorite feature from F#, they could be improved. I'd love it if record definitions were extensible (even abstractly--sometimes you want a record with just the data, and sometimes including db-centric "id, createdTime, etc"), and there should be a way of defining / converting between them without a ton of boilerplate. That would allow something like: record DbStuff = { id: int; created: DateTime } record UserRecord: DbStuff { name: string; ... } var userRecord = new UserRecord(...) var userData = userRecord.WithoutDbStuff() // but what would be the reflected name of this type? var newRecord = userData.WithDbStuff(3, DateTime.Now) ---- Sometimes you want to be able to define records PhotoData{source, metadata, yada, etc, url} and PhotoDisp{source, metadata, yada, etc, bytes} without the repetition, and again with an easy way to convert between the two. (And yes you could simplify the above by using containership but oftentimes there are cross-cutting things that containership doesn't solve. You really want a flattening solution.) Easy integration with C# anonymous classes should be considered too. C# has always been the more real-world-centric language so I'd hope these common use cases would be considered.
- JamesBarney 10y ago
- mhomde 10y agoWow, lot's of great stuff! I especially like local functions, I'm all for breaking up complicated methods into several methods to simplify and clarify syntax... but it always felt weird that all those methods where on an class scope even though they only were relevant for that method. This resulted in many cases that those methods needed to be broken out into their own class... which is the way to go some times but felt like a bit of overkill in others
- zubspace 10y agoI mostly agree, but until now I just created private helper methods and went on with my life. If there are many of them, I put them into a #region. There are alot of cases where such helpers can be used from two separate locations and they also increase discoverability for other devs. If you really wanted to, wasn't it already possible to create anonymous delegates/lambdas locally? The only improvement I see with local named methods are readable stacktraces.I have to admit, the mangled names are a major headache for me (and the stacktraces starting at lamda invocations, missing the 'original' stacktrace. I'm looking at you Parallel.Foreach!)
- 72deluxe 10y agoI would have thought use of a Func<> or a lambda would have been appropriate instead of a local function?
- davidgrenier 10y agoUnfortunately, C# can flail about adopting F# features yet the best feature of F# is something C# can never get: Dependency Order Compilation
- daxfohl 10y agoExcept it does. And F# doesn't. F# just has in-order compilation. C# has an extra step to determine dependencies and compile them in dependency order. The only thing for F# is that F# allows the user to determine the compilation order and show it in Visual Studio.
- davidgrenier 10y agoSorry I wasn't clear, I meant in the following sense: "One of the most common complaints about F# is that it requires code to be in dependency order." In light of your statement I understand the way I put it made little sense.
- CyrusNajmabadi 10y agoHi David, language designer here. Can you give an example of where you'd want to take advantage of this in C#? Thanks!
- davidgrenier 10y agoI don't understand the question, rather what's the point of it?
- adrianratnapala 10y agoDoes the pattern matching also statically check that you don't try to use a failed match. What if instead of if (o is null) return; // constant pattern "null" if (!(o is int i)) return; // type pattern "int i" WriteLine(new string('*', i)); somone forgot to return, as in if (!(o is int i)) { // do something } // incorrectly try to use `o` as an int WriteLine(new string('*', i)); Rust uses the special `match` syntax to avoid this. But I suppose C# 7.0 also analyse the structure of the `if`s and `return`s to acheive the same effect more flexibily. And if it can do that, could that they also start phasing in statically-checked null avoidance?
- qu4z-2 10y agoMy guess is this would be covered by the "have you initialised the variable" check, similarly to: int i; if (x == 3) { i = 2; } WriteLine(i); I'd be interested to hear the answer, though.
- Eyas 10y agoThis was a concern of mine as well, as you can see in the discussion of scope changes for pattern variables [1], the C# checks for definite assignments handle this. So: if (o is int i) { f(i); } use_int(i); // <-- error: variable `i` is not definitely assigned But then if you have: if (o is int i || (o is string s and int.TryParse(out i)) use_int(i); We know that `i` is definitely assigned at that location. [1]: https://github.com/dotnet/roslyn/issues/12597 https://github.com/dotnet/roslyn/issues/12597
- iliketrains 10y agoNice! I was also hoping for some sort of guaranteed not-nullable type and immutable classes. Maybe in C# 8.
- daxfohl 10y agoF# has guaranteed not-nullables, except when you do default<NotNullableThing> it returns null. That said, it generally works well in well-defined situations but any time there's deserialization it's often a bigger mess than just never assuming not-null. I think it's a problem that needs to be solved in the CLR, not C#, and my guess is it probably never will be.
- myf01d 10y ago>C# >2016
- rmsaksida 10y agoSince we're all chipping in with features we'd like to see in C#, here are mine: anonymous classes - with actual class bodies, that can implement interfaces - and traits.
- rjbwork 10y agoYou could, if you were so inclined, just generate proxies on the fly.
- voltagex_ 10y agoCan you give an example of how C# would be different with anonymous classes? Googling that term just gives a whole lot of references to inner classes in Java.
- flukus 10y agoOne I've come across is binding a command to a button. With anonymous inner classes you can have something like: myButton.AddListener(new Command { bool enabled() { return false; //more logic goes here } void onClick() { //do something } });
- voltagex_ 10y agoI'm not convinced that gives you that much more over using a delegate.
- flukus 10y agoIt doesn't. It's a nice to have feature, not a world changing one.
- ygra 10y agoBut that's something that's very rare in C#. Usually for that sort of thing you have events and delegates. Although I have to admit that the library I work on had a few patterns that would benefit from anonymous interface implementations, but not that much to really miss the feature.
- rat87 10y agoIs 6.0 widely used in industry/open source?
- __s 10y agoAt my work I do a lot with 3.5 still. We need to upgrade our version of devexpress. More recent projects use MVC with .Net 4.0 or 4.5 (but our IT guy is nervous about installing such new runtimes on the servers that don't have 4.5 already..) We use VS2012
- andrewgretton 10y ago25-strong dev team using C# 6 right now. Painless upgrade apart from a few pieces of legacy tooling. Some patterns haven't really been adopted much (e.g. exception filters). C# 7 looks like more of a leap but there's always an appetite to stay current in our team and I'm sure we'll take the plunge.
- bifel 10y agoHaving done a lot of python recently, this looks great (and familiar). But some things feel a little bit rushed: - In the example "(o is int i || (o is string s && int.TryParse(s, out i))": When reading this statement as a human, o is obviously not an int when it comes down to the TryParse function. But if the 1st part was removed, the 2nd part wouldn't be valid either. I know this is technically how declarations work and I don't have an idea, if there is a better solution for this, but it feels weird. - The new features of the case statement are nice but the old syntax with the mandatory break is probably worth getting rid of. Especially since all cases share a scope, adding/removing cases is prone to errors. I'd love to see a solution similar to "catch". - The Deconstruct method is introduced as a "magic name". No interface, no override, nothing... Even the return type is "void". Why not use something like "public out Point(...)" to keep it similar in fashion to the constructor. Other options may be something with "this" (like indexing) or "operator".
- Arnavion 10y ago>The Deconstruct method is introduced as a "magic name". No interface, no override, nothing... There is precedence for this in the form of GetEnumerator and GetAwaiter.
- bruceboughton 10y agoDeconstruct will be an operator and this is how C# handles other operator overrides, e.g. equality, implicit/explicit type conversions, so this is in line with what developers would expect.
- fuzzy2 10y ago> The Deconstruct method is introduced as a "magic name". Collection initializers already rely on “magic names” (the `Add` method + `IEnumerable`), so I’d say that’s okay. It’s simply a compiler feature, after all.
- mcintyre1994 10y agoI was thrown by the first one you pointed out too, I'm still not sure I understand it. The page said for type patterns it will "test that the input has type T, and if so, extracts the value of the input into a fresh variable x of type T", so if o is an int it'll be extracted to a fresh int i with that value But the out syntax in TryParse isn't the new one they mentioned, it's the current one that requires predeclared variables - to be new it'd be out int i or out var i. So i is already declared as an int before this code example? In that case how can the first bit work? Does it not create a "fresh variable" if there's already one in scope with the desired name and type? That could be quite confusing, usual behavior is to compile error if an inner scoped variable conflicts with an outer one, I'm not sure I understand why this should be different.
- hvidgaard 10y agoI don't like the idea of accessing tuple values by their local name var names = LookupName(id); WriteLine($"found {names.first} {names.last}."); It's leaky and should simply use the deconstructing syntax instead. I'm on the fence about the ref returns. It can lead to some fantastic performance improvements and enable otherwise unusable datastructures. But is C# really a language you want if that is important to you. Why not go all in a use a lib in C or C++ for the critical parts of the code? I still miss better immutability support, and probably most of all, ability to declare something at non-nullable. But that said, the update is a fantastic update to an already good language.
- zamalek 10y ago> But is C# really a language you want if that is important to you. C# is used by hundreds if not thousands of games by ways of Unity and is therefore demonstrably good enough in this scenario. Furthermore, just because a language is not C++ does not mean you shouldn't take every opportunity to give programmers tools to write fast code - at the end of the day I doubt anyone would be interested in a language that is purposefully slow. Performance was a core feature of the language (yes, yes, it's managed) from day 1 with unsafe - it's nice to see further improvements in that department. Use C++ when you need to, definitely, but when you're copying about 256 bytes around for a trivial world-view-projection matrix multiplication[1] you have a problem. [1]: https://github.com/dotnet/roslyn/issues/10378#issuecomment-223318382 https://github.com/dotnet/roslyn/issues/10378#issuecomment-2...
- hvidgaard 10y agoWhile it's used for game development, I'm not convinced that it automatically means features should cater specifically to that audience. Compared to everything non-performance critical the language is used for, the performance crowd is dwarfed. I'm not against it, I personally have been in situations where it would have been useful, I'm just not convinced it's beneficial for the language to implement it.
- zamalek 10y ago
- DropbearRob 10y agoIm so excited by this in particular "Switch statements with patterns We’re generalizing the switch statement so that: •You can switch on any type (not just primitive types) •Patterns can be used in case clauses •Case clauses can have additional conditions on them Here’s a simple example: switch(shape) { case Circle c: WriteLine($"circle with radius {c.Radius}"); break; case Rectangle s when (s.Length == s.Height): WriteLine($"{s.Length} x {s.Height} square"); break; case Rectangle r: WriteLine($"{r.Length} x {r.Height} rectangle"); break; default: WriteLine("<unknown shape>"); break; case null: throw new ArgumentNullException(nameof(shape)); } There are several things to note about this newly extended switch statement: •The order of case clauses now matters: Just like catch clauses, the case clauses are no longer necessarily disjoint, and the first one that matches gets picked. It’s therefore important that the square case comes before the rectangle case above. Also, just like with catch clauses, the compiler will help you by flagging obvious cases that can never be reached. Before this you couldn’t ever tell the order of evaluation, so this is not a breaking change of behavior. •The default clause is always evaluated last: Even though the null case above comes last, it will be checked before the default clause is picked. This is for compatibility with existing switch semantics. However, good practice would usually have you put the default clause at the end. •The null clause at the end is not unreachable: This is because type patterns follow the example of the current is expression and do not match null. This ensures that null values aren’t accidentally snapped up by whichever type pattern happens to come first; you have to be more explicit about how to handle them (or leave them for the default clause). Pattern variables introduced by a case ...: label are in scope only in the corresponding switch section."
- insulanian 10y agoI just realized that I don't remember I ever saw a C# rant on HN and very very rarely in general. It must have the highest usage/complaints ratio in the industry. Now that I said that I'd love to see the languages ordered by that ratio!
- nenreme 10y agoMaybe not exactly what you want but it is a "% of developers who are developing with the language or tech and have expressed interest in continuing to develop with it". http://stackoverflow.com/research/developer-survey-2016#technology-most-loved-dreaded-and-wanted http://stackoverflow.com/research/developer-survey-2016#tech...
- headmelted 10y agoI've been really excited about this release, but also a little disappointed that we still don't have proper object composition. I'd be happy with either extension methods with state or adding traits to the language as a separate feature. I understand the reasons it was decided against in C# 4, but its hard to preach composition over inheritance when the framework is philosophically against it, and it runs contrary to how the whole framework is structured (single inheritance from Object). But it still irks my fussiest self. You can get something that sort of gets mostly there with ConditionalWeakTable, but its not endorsed by the vendor, and in the experience I had with it while trying to create a mixins module for C# a few years back, makes the GC leak like a sieve at scale.
- markatkinson 10y agoWow! These are some really impressive features. I started learning F# a few months back and I can see some interesting parallels. Very excited to see Tuples and Pattern Matching.
- billpg 10y agoI tend to avoid using switch/case for quite irrational reasons. The break statement just looks wrong and I can't layout the code in a way I find at all pleasing. I'll almost always use a sequence of else if conditions instead. In my ideal world, it'd look like... switch (x) { case 1: { /* ... */ } case 2: case 3: { /* ... */ } } And before anyone points it out, switch is the same as else if when the thing being compared is a simple local variable.
- ivanca 10y agoSame here, plus I think the parent brakes are noise, can the compiler just know that the switch statement ends on last case?
- 72deluxe 10y agoNo, as in some instances you may wish to do the same thing for two case statements, so you need it to fall through case1 into case2. In other situations, you really don't want it to do that, so a break is required. How would the compiler know the difference? Note that you can't "fall through" cases in Swift, and it is irritating. It stops you using the same code for two case statements - you have to duplicate it or put it into a function.
- breakingcups 10y agoNot with nested switch statements.
- ivanca 10y ago...I don't want to ever have to work with your code.
- iaskwhy 10y agoBut you can already do almost that, right? switch (x) { case 1: { /* ... */ } break; case 2: case 3: { /* ... */ } break; }
- ricardobeat 10y agoWhat's the point of GetCoordinates(out var x, out var y) over destructuring assignment like var x, var y = GetCoordinates(); the former looks completely backwards.
- masklinn 10y agoThe former works with pre-tuple out-parameter-based API e.g. Int32.TryParse.
- frogfuzion 10y agoMaybe the former method would make more sense to use if it were HasCoordinates and returned a Boolean? This way you would get a Boolean if the coordinates exist and would not have to perform validation on the out variables.
- reitanqild 10y agoWondered about this myself, is this something that is needed for backwards compatibility or something? IMO fishing parameters back from functions is one of the things I do not miss from old C. Anyone has anything to add to masklinn's explanation? Edit: found CyrusNajmabadi's comment here: https://news.ycombinator.com/user?id=CyrusNajmabadi https://news.ycombinator.com/user?id=CyrusNajmabadi
- 72deluxe 10y agoI much prefer your second example. In fact, surely tuples would help in this situation? eg. in C++: tuple<int,int> x = GetCoordinates(); or auto x = GetCoordinates() Much easier to see the output. I maintain enough old old C++ code and don't like seeing GetCoordinates(int x, int y) or x in COM-land any more.
- hacker_9 10y agoCSharp once again showing it is the best language in terms of features and improvements. Great job all round by the designers.
- wsc981 10y agoI'd say Swift is more or less in line with C# with regards to functionality. Many new features added to C# seem to already exist in Swift. Swift could use some async/await mechanism en sometimes it's a bit annoying to typecast simple types for calculations, but otherwise Swift is a really sweet language to work with. Nonetheless C# is a nice language. I enjoy writing C# code, just as I enjoy writing Swift code.
- hacker_9 10y agoI'd disagree with you to be honest. Swift is still in it's infancy, and while it copied many of it's features from CSharp, it did so poorly and even now they continue to make breaking changes to their standard with each update.
- 72deluxe 10y agoYes I have noticed this. It is interesting observing the changes to Obj-C just to keep up with the developments in Swift-land, when Swift itself is changing so frequently.
- apetrovic 10y agoSwift is my daily driver for a year and some, I love the language and I'm having much fun working in it, it have some great ideas (nullability, emphasis on value types, protocol extensions), but calling it "more or less in line with C#" is still a bit of stretch. (For starters, Swift desperately needs to include most of the points from "Generic Manifesto" to be comparable with more mature languages like C#. Not being able to return a generic interface from a function is just silly)
- jinst8gmi 10y ago> CSharp once again showing it is the best language in terms of features and improvements. That's a pretty sweeping generalization. Most of the headline features in the article are already in other languages e.g. Scala.
- alkonaut 10y agoI still lack some kind of sum type that is always checked for exhaustiveness. When I'm creating a class hierarchy for a domain, 9 times out of 10 I'd rather have a simple sum type. When I have to make a class hierarchy in C# anyway (because there are no simple sum types). I'd like to be able to write something like this, and have this match/switch fail to compile if I add a new type of shape. match(shape) { case Rectangle r return r.With*r.Height; case Circle c return pi*c.Radius*c.Radius; }
- macca321 10y agoI'm just going to pimp my library (github.com/mcintyre321/OneOf) which lets you pull this off in c#. I'm quite sad it's needed though, it would be great to have it in the language.
- alkonaut 10y agoThat's very neat, it should be pretty easy to sugar something like that into the compiler with no CLR changes.
- Achshar 10y agoNoob question, why tuples? I mean why 3?
- bsaul 10y agot doesn't mean three, it works with 2 or more.
- pingec 10y agoPattern matching, tuples, local functions... feels like someone was inspired by how Typescript turned out :)
- hvidgaard 10y agoOr just looking at F#.
- Nano2rad 10y agoMicrosoft is mixing object oriented and functional in c#. This is not right, not only in case of Microsoft but also Python etc. They are fundamentally different and self-contained and need to be kept separate.