Here is a description of all the new language features in C# 7.0, which came out last Tuesday as part of the Visual Studio 2017 release.
C# 7.0 adds a number of new features and brings a focus on data consumption, code simplification and performance. Perhaps the biggest features are tuples, which make it easy to have multiple results, and pattern matching which simplifies code that is conditional on the shape of data. But there are many other features big and small. We hope that they all combine to make your code more efficient and clear, and you more happy and productive.
If you are curious about the design process that led to this feature set, you can find design notes, proposals and lots of discussion at the C# language design GitHub site.
If this post feels familiar, it may be because a preliminary version went out last August. In the final version of C# 7.0 a few details have changed, some of them in response to great feedback on that post.
Have fun with C# 7.0, and happy hacking!
Mads Torgersen, C# Language PM
Out variables
In older versions of C#, using out parameters isn’t as fluid as we’d like. Before you can call a method with out parameters you first have to declare variables to pass to it. Since you typically aren’t initializing these variables (they are going to be overwritten by the method after all), you also cannot use var
to declare them, but need to specify the full type:
In C# 7.0 we have added out variables; the ability to declare a variable right at the point where it is passed as an out argument:
Note that the variables are in scope in the enclosing block, so that the subsequent line can use them. Many kinds of statements do not establish their own scope, so out variables declared in them are often introduced into the enclosing scope.
Since the out variables are declared directly as arguments to out parameters, the compiler can usually tell what their type should be (unless there are conflicting overloads), so it is fine to use var
instead of a type to declare them:
A common use of out parameters is the Try...
pattern, where a boolean return value indicates success, and out parameters carry the results obtained:
We allow "discards" as out parameters as well, in the form of a _
, to let you ignore out parameters you don’t care about:
Pattern matching
C# 7.0 introduces the notion of patterns, which, abstractly speaking, are syntactic elements that can test that a value has a certain "shape", and extract information from the value when it does.
Examples of patterns in C# 7.0 are:
- Constant patterns of the form
c
(wherec
is a constant expression in C#), which test that the input is equal toc
- Type patterns of the form
T x
(whereT
is a type andx
is an identifier), which test that the input has typeT
, and if so, extracts the value of the input into a fresh variablex
of typeT
- Var patterns of the form
var x
(wherex
is an identifier), which always match, and simply put the value of the input into a fresh variablex
with the same type as the input.
This is just the beginning – patterns are a new kind of language element in C#, and we expect to add more of them to C# in the future.
In C# 7.0 we are enhancing two existing language constructs with patterns:
is
expressions can now have a pattern on the right hand side, instead of just a typecase
clauses in switch statements can now match on patterns, not just constant values
In future versions of C# we are likely to add more places where patterns can be used.
Is-expressions with patterns
Here is an example of using is
expressions with constant patterns and type patterns:
As you can see, the pattern variables – the variables introduced by a pattern – are similar to the out variables described earlier, in that they can be declared in the middle of an expression, and can be used within the nearest surrounding scope. Also like out variables, pattern variables are mutable. We often refer to out variables and pattern variables jointly as "expression variables".
Patterns and Try-methods often go well together:
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:
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.
Tuples
It is common to want to return more than one value from a method. The options available in older versions of C# are less than optimal:
- Out parameters: Use is clunky (even with the improvements described above), and they don’t work with async methods.
System.Tuple<...>
return types: Verbose to use and require an allocation of a tuple object.- Custom-built transport type for every method: A lot of code overhead for a type whose purpose is just to temporarily group a few values.
- Anonymous types returned through a
dynamic
return type: High performance overhead and no static type checking.
To do better at this, C# 7.0 adds tuple types and tuple literals:
The method now effectively returns three strings, wrapped up as elements in a tuple value.
The caller of the method will receive a tuple, and can access the elements individually:
Item1
etc. are the default names for tuple elements, and can always be used. But they aren’t very descriptive, so you can optionally add better ones:
Now the recipient of that tuple have more descriptive names to work with:
You can also specify element names directly in tuple literals:
Generally you can assign tuple types to each other regardless of the names: as long as the individual elements are assignable, tuple types convert freely to other tuple types.
Tuples are value types, and their elements are simply public, mutable fields. They have value equality, meaning that two tuples are equal (and have the same hash code) if all their elements are pairwise equal (and have the same hash code).
This makes tuples useful for many other situations beyond multiple return values. For instance, if you need a dictionary with multiple keys, use a tuple as your key and everything works out right. If you need a list with multiple values at each position, use a tuple, and searching the list etc. will work correctly.
Tuples rely on a family of underlying generic struct types called ValueTuple<...>
. If you target a Framework that doesn’t yet include those types, you can instead pick them up from NuGet:
- Right-click the project in the Solution Explorer and select "Manage NuGet Packages…"
- Select the "Browse" tab and select "nuget.org" as the "Package source"
- Search for "System.ValueTuple" and install it.
Deconstruction
Another way to consume tuples is to deconstruct them. A deconstructing declaration is a syntax for splitting a tuple (or other value) into its parts and assigning those parts individually to fresh variables:
In a deconstructing declaration you can use var
for the individual variables declared:
Or even put a single var
outside of the parentheses as an abbreviation:
You can also deconstruct into existing variables with a deconstructing assignment:
Deconstruction is not just for tuples. Any type can be deconstructed, as long as it has an (instance or extension) deconstructor method of the form:
The out parameters constitute the values that result from the deconstruction.
(Why does it use out parameters instead of returning a tuple? That is so that you can have multiple overloads for different numbers of values).
It will be a common pattern to have constructors and deconstructors be "symmetric" in this way.
Just as for out variables, we allow "discards" in deconstruction, for things that you don’t care about:
Local functions
Sometimes a helper function only makes sense inside of a single method that uses it. You can now declare such functions inside other function bodies as a local function:
Parameters and local variables from the enclosing scope are available inside of a local function, just as they are in lambda expressions.
As an example, methods implemented as iterators commonly need a non-iterator wrapper method for eagerly checking the arguments at the time of the call. (The iterator itself doesn’t start running until MoveNext
is called). Local functions are perfect for this scenario:
If Iterator
had been a private method next to Filter
, it would have been available for other members to accidentally use directly (without argument checking). Also, it would have needed to take all the same arguments as Filter
instead of having them just be in scope.
Literal improvements
C# 7.0 allows _
to occur as a digit separator inside number literals:
You can put them wherever you want between digits, to improve readability. They have no effect on the value.
Also, C# 7.0 introduces binary literals, so that you can specify bit patterns directly instead of having to know hexadecimal notation by heart.
Ref returns and locals
Just like you can pass things by reference (with the ref
modifier) in C#, you can now return them by reference, and also store them by reference in local variables.
This is useful for passing around placeholders into big data structures. For instance, a game might hold its data in a big preallocated array of structs (to avoid garbage collection pauses). Methods can now return a reference directly to such a struct, through which the caller can read and modify it.
There are some restrictions to ensure that this is safe:
- You can only return refs that are "safe to return": Ones that were passed to you, and ones that point into fields in objects.
- Ref locals are initialized to a certain storage location, and cannot be mutated to point to another.
Generalized async return types
Up until now, async methods in C# must either return void
, Task
or Task<T>
. C# 7.0 allows other types to be defined in such a way that they can be returned from an async method.
For instance we now have a ValueTask<T>
struct type. It is built to prevent the allocation of a Task<T>
object in cases where the result of the async operation is already available at the time of awaiting. For many async scenarios where buffering is involved for example, this can drastically reduce the number of allocations and lead to significant performance gains.
There are many other ways that you can imagine custom "task-like" types being useful. It won’t be straightforward to create them correctly, so we don’t expect most people to roll their own, but it is likely that they will start to show up in frameworks and APIs, and callers can then just return and await
them the way they do Tasks today.
More expression bodied members
Expression bodied methods, properties etc. are a big hit in C# 6.0, but we didn’t allow them in all kinds of members. C# 7.0 adds accessors, constructors and finalizers to the list of things that can have expression bodies:
This is an example of a feature that was contributed by the community, not the Microsoft C# compiler team. Yay, open source!
Throw expressions
It is easy to throw an exception in the middle of an expression: just call a method that does it for you! But in C# 7.0 we are directly allowing throw
as an expression in certain places:
Is seems that match expression is not provided in C# 7.0.
AWESOME to see improvement/expansion to Expression Bodies! I am a huge fan of them.
However, it would also be nice to see some better tooling support in Visual Studio to help debug them, as getting/seeing the result is a bit burdensome. I constantly find myself having to assign to a local variable during debugging and then have to remember to undo it, etc.
Also, finally (FINALLY) getting blasted “out var x” support will be a dream. Definitely a hassle to endure and I was disappointed this didn’t make it in 6.0.
Is the custom `is` operator in? And if so could anyone tell me (or point to a discussion) why it hasn’t been unified with `Deconstructor`s? I understand that the use cases for these two things are slightly different but they serve almost the same purpose so some sort of unification seems to me as a good idea.
It’s all good, of course. But my question is – when are we going to see an updated official spec? VS2017 is still installing with the C# 5.0 spec.
Relevant: https://github.com/dotnet/csharplang/tree/master/spec
If only Jon Skeet were monitoring this conversation and could chime in with an answer…
Actually, Jon Skeet is one of the main people currently working on updating the C# spec. He’s “Convenor” of the Technical Committee responsible for the ECMA C# standard: http://www.ecma-international.org/memento/TC49-TG2.HTM
There is a discussion about this at https://github.com/dotnet/csharplang/issues/64. To sump up: work is being done to create C# 6.0 and 7.0 specs, but it’s going to take some time.
Well done! It’s useful and nice.
Well done! It’s useful and nice.
But what version of the framework will include valuetuple without the need for an external library?
I have exact the same question.
Please enhance the examples showing discards, as this is a new concept.
For C#<7 programmers, _ is just another variable. Please show multiple discards in your examples, such that it's immediately clear that the semantics of _ are different to the _ variable, which only may be defined once.
+1
I tried it in LINQPad 5.21.01 and I could not get it to work, so some help would be much appreciated!
In VS 2017 RTM, this works:
var (a, _) = (1, 2);
var (b, _) = (3, 4);
but not this:
var (a, _) = (1, 2);
var (a, _) = (3, 4);
However, in latest LINQPad beta (v5.21.02), none of those worked.
It should be considered a bug in LINQPad (I have already reported it as a bug).
The latter doesn’t work because of deconstruction. You are declaring 2 “a” variables in the same scope, which is not allowed.
I think that’s his point; only in the second example is a variable actually being declared twice, but LINQPad is complaining about both.
And it appears they fixed it in LINQPad v5.22!
var (foo, _, _) = (1, 2, 3); // returns 1
var (_, bar, _) = (4, 5, 6); // returns 5
var (_, _, baz) = (7, 8, 9); // returns 9
Console.Write($”{(foo, bar, baz)}”); // prints ‘(1,5,9)’
Now returns a ValueTuple containing (1,5).
I wonder why not use “void” instead.
I clearly remembered there was a discussion about this, and since use “void” here is exactly what it means, I supported this idea. Looks like it doesn’t matter after all : (
Personally I’m not keen on a lot of the stuff that’s gone into v6 and 7. I find some of the examples quite unreadable, and it’s not just because it’s an unfamiliar syntax. (It’s a bit like letting Resharper refactor a ‘for’ loop into LINQ – sometimes the result is pretty hideous). I realise developers can be an inherently lazy lot, but for the sake of readability I’d rather type a few extra keystrokes.
IMO it’s a matter of choice, “choose the style that suits your eyes”. For me, I’m pretty excited about some of them, like pattern matching, I believe it can make the code a lot clearer now (also faster to write). However, in the end of day, if you don’t like the new one, you can always use the old style, it’s not like the compiler refuse to compile it, or just blow up in your face, or something ^_^
Conversely, I find the shorthand syntax much more readable, especially in larger classes. Someone a few years ago told me to read => as “goes to” instead of “Lambda” and in my head that’s what I think whenever I read it. That has helped tremendously when it comes to reading the newer expression bodied syntax.
I also read => as “goes to” which is where the new expression bodies on constructors and setters feels wrong to me, as well as explicitly meaning there will be side effects, when I generally assume that with a lambda there won’t be any
With you there Andy. Getting developers to use existing features properly is sometimes hard enough. Some of this new stuff can sometimes feel like more rope for them to hang themselves with. An example I can recall, though somewhat old, is when developers I work with started using anonymous methods, then started nesting them. Great feature, that can easily create a nightmare in terms of maintainable code.
Can’t say I agree, but each unto their own. Tastefully removing boilerplate syntax cruft and making the language more expressive is worthwhile IMHO, even if sometimes it can take a little getting used to. E.g. with expression bodies, POCO objects often shrink to 1/3 of their size or less. That’s a readability win in my book.
I do agree there are limits, though I’d draw them at something like q/kdb+. Now there’s a language that takes it too far.
I, like many, am looking forward to these new language features. It’s important to note the argument “don’t use it if you don’t like it” is not so helpful, because oftentimes we are talking about community/team code.
The execution order of the new switch statement is confusing. Declaration order matters, but not for the “default” clause which is always executed last. This contradicts with existing behaviour of the try/catch block, where the catch-all statement (without exception type specification) must always be the last and no further catches are allowed by the compiler.
What they have done is introduced an ‘order’ to the switch statements, previously it was not possible to create multiple switch statements that the switch value could evaluate too, so in the past order was not an issue. Now that you can add conditions to the switch criteria the order is the only logical way to determine which path a value will be evaluated to.
This is inline with other languages, including SQL. Most developers probably thought that there always was an order and were probably coding with this in mind.
There is no confusion with try/catch because the catch statements are Type evaluations, not value comparisons. So in the catch statements the normal overload rules apply to find the type expression that is most prescriptive that applies to the exception type that has been thrown.
The ability for the default statement to be located anywhere within the switch logic can make reading switch statements a little easier. For instance I like to code the default statement first, allowing the team to append the switch logic with statements as the code evolves. People often least expect the default statement to evaluate, by putting it first, you are aware up front of the exceptional circumstance as you scan through code.
But now that order matters the C# team have allowed a logical solution so that existing code will still compile the. The default statement evaluates only when all other possible statement criteria has been exhausted. So it is not considered in the order of execution because it is always last. This is great because the logical meaning of the default statement has remained in changed.
In traditional switch statements the order did not mater and since the values where constant compilers could do something more than just iterate through the cases. I know this is true of at least C compilers. I have not studied the output of the c# compiler in this regard.
For example if you where switching on an int and had cases for integers 85 – 120 the compiler may take the input value if it is between 85 and 120 and subtract 85 and then put all of the cases as functions in a static array and then simply call the function at the index. This of course is much faster than iterating through all of the cases as I find is the assumption by most developers. I don’t know for sure if the c# compiler did these kinds of optimizations, but I know C compilers do.
The compiler still appears to carry out intelligent optimisations along this line when the switch parameter is an object.
It will build a jump table for groups of literals of the same type (e.g. case 85, case 86, etc.). If we intersperse cases for other types (or null or default cases) in the middle of these, it does not affect the jump table; it does the null value, type and condition checks first, in the order they appear. (From what I gathered when checking the IL generated by LinqPad).
Looks like they have already thought hard about this!
Virtually any pattern matching expression can be transformed to a tree of nested switches at compile-time- this change just lets us write what we intend and allows the compiler to optimize it appropriately- for instance, a possible optimization for pattern matching is dependency analysis to find the order of fastest resolution for the heaviest paths.
For a more intuitive understanding of how pattern matching can be optimized, consider the order of attribute selection in a dichotomous key- you check the attributes which narrow down the possibility set most evenly first, allowing you to somewhat mimic a binary search in an arbitrary tree. Some influences on choice of key ordering are ease of identification or measurement (and potentially, calculation) of an attribute, or balance of the key- if only one member of a large set has an attribute, you wouldn’t likely check that attribute first, because it is only a useful check to perform a (ratiotically) very small amount of the time. It’d be better to cut off nearer to half the potential set.
Awesome! Can’t wait to get my hands on all of this.
Not sure I understand the point of Local Functions. Whats the point of deconstructing a function into smaller parts and putting the smaller parts inside the function?
This would also break single responsibility principle as I can see it. If a piece of code can be broken down into a function then it should be its own function surely? If the enclosing function is also executing the enclosed function then surely the enclosing function is performing two actions?
The only reason I can see this being included in C# is to mimic popular JavaScript semantics
This can be useful when you need to perform some recursive calculation: the inner function does the actual work, and the outer provides default parameters and returns the result. Previously I had to use two functions – a public “CalculateStuff” and a private “CalculateStuffRecursive”, which polluted the class’ namespace – so the new approach is a bit cleaner.
There are definitely use cases where a local function can greatly simplify logic without compromising single responsibility. It gets tiresome having tons of functions that are only referenced once and always will be.
> Whats the point of deconstructing a function into smaller parts and putting the smaller parts inside the function?
Encapsulation. Moving part of your function (it’s private details) into external one violates encapsulation — you are not controlling it anymore. Your colleagues can start using this subfunction in their ones, and you cannot change it anymore without breaking someone’s code.
However, previously the C# team argued that wasn’t a sufficient reason to allow static local variables inside functions. That seems like a decision that deserves to be revisited in light of local functions.
Am I wrong or things have been removed from the previous previews?
I recall things like switch expression and more pattern matching scenarios.
Also, is there a difference between `bool a = foo == null` and `bool a = foo is null`?
If I recall, not all the pattern matching stuff made it in to the release version.
(per LINQPad 5.22.00)
string foo = null;
bool a = foo == null;
// becomes:
IL_0000: nop
IL_0001: ldnull
IL_0002: stloc.0 // foo
IL_0003: ldloc.0 // foo
IL_0004: ldnull
IL_0005: ceq
IL_0007: stloc.1 // a
IL_0008: ret
// end
bool a = foo is null;
// becomes:
IL_0000: nop
IL_0001: ldnull
IL_0002: stloc.0 // foo
IL_0003: ldnull
IL_0004: ldloc.0 // foo
IL_0005: call System.Object.Equals
IL_000A: stloc.1 // a
IL_000B: ret
// end
After both paths, a == true. The IL is more or less equivalent, although ‘==’ turns into ceq, and ‘is’ turns into a call to System.Object.Equals, which under the hood does the equality check:
public static bool Equals(Object objA, Object objB)
{
if (objA==objB) {
return true;
}
if (objA==null || objB==null) {
return false;
}
return objA.Equals(objB);
}
So the ‘is’ is slightly more expensive (you’re paying for a call).
Finally we can program directly in binary code thru the use of binary literals…
The abstraction level of using programming verbs always bothered me, especially in programs reaching a couple of thousand lines…
🙂
lol
From the example:
if (o is int i || (o is string s && int.TryParse(s, out i)) { /* use i */ }
Why is there no `var` keyword in the `int.TryParse` expression?
“o is int i” part already declares i. The scoping might take a little getting used too, but that’s how it is
Not to mention the fact that the scope of “i” leaks to the block that the “if” statement is contained it (i.e. is available after the if statement).
Not to mention that “i” is still in scope AFTER the “if” statement. “is” and “out” declarations scope leak to the block that the “if” statement is contained within.
Are we supposed to write this
if (o is null) return;
instead of this
if (o == null) return;
now?
depends on what you need. ‘==’ and ‘is’ are not the same.
int i = 0;
i == 0; //true
i == 2; //false
i is int //true
i is string; //false
Oh great, now this ‘var’ plague spreading even further.
More harder to read code for everyone!
‘var’ is not even close to a plague. It’s one of the most-useful features in C#, and does not negatively affect code readability in any way whatsoever.
It totally does. There are plenty of stack overflow snippets that demonstrate that it’s unknown to the reader what data types are returned from used methods.
There are cases where it’s obvious but there are also cases where it’s not and that’s the problem.
Yeah, if only there was a way to specify the type of the variables in your code…
If you hate var, someone should be able to write a refactor tool to swap var with the actual type. (Doesn’t help when reading other people’s code though.) Personally, I love var, especially for big ugly generic types like Dictionary<,List>
R# can do this already
Var makes code easier to read. There are a ridiculously small set of scenarios where this is not the case, but those are so odd that I would want them to look different anyway.
“Why doesn’t this code use var?”
“Well, you see, the typing is a little weird…”
Using var in all normal cases, which is fine because the type is usually obvious anyway, allows explicit types to become a flag that highlights that something strange is going on.
‘var’ makes the code look more pleasing to the eye, but it certainly makes it a lot harder to understand.
Notice how people keep mousing over their ‘var’ declared variables to show its true type on instructional videos.
For instance, which one is easier to understand of the following?
1.
var names = LookupName(id);
WriteLine($”found {names.first} {names.last}.”);
2.
(string first, string middle, string last) = LookupName(id);
WriteLine($”found {first} {last}.”);
I would never have guesses that the variable ‘names’ would have the properties first and last.
I would have guessed it was a string[].
Such misunderstandings happen all the time if the code is using ‘var’ everywhere. Unless everyone follow a strict naming convention for variables, it is hard to know if the variable is an identifier for an entity, its name, or a reference to the domain object itself.
I do agree that code using ‘var’ looks less complicated on first sight though.
It is definitely possible to make var var less readable readability becomes more murky than the second.
There are more examples we could contrive to use var and maintain readability:
3. (var first, var middle, var last) = LookupName(id);
4. var (first, middle, last) = LookupName(id);
5. var (first, _, last) = LookupName(id); // since we’re never using the middle name
Console.WriteLine($”found {first} {last}”);
These all seem to be very readable. I favor 4 & 5 myself.
To your point about naming conventions, ‘first’ and ‘last’ are still a little unclear — they, for example, mean first and last matching element in the set of names (perhaps the author is searching for duplicate keys in a collection that doesn’t enforce uniqueness?). We could improve clarity by making the variable names more verbose.
And then there’s the inherent cultural bias in the return type (a strict 3-Item Tuple). Perhaps a string[] or an IEnumerable would be superior for this function as some people have 1 name and some have 4 (or more). However, because C# can’t differentiate functions purely on return type (i get ‘why’ but I still wish the compiler and the runtime were smart enough to allow it… ;-), you’d have to come up with distinct names for each and every function if you wanted to get a ValueTuple back containing only the parts for the given record…
I agree to a very large extent, but a line like
(var first, var middle, var last) = LookupName(id);
is still muddy. If we do not know anything on the function.
I COULD be the first and last two single item and an array/list/… for the middle ones.
We have no way of knowing…
In general I suggest to ONLY use var where the type is obvious from the context.
If a type gets too hard to write full out, consider using use aliases https://msdn.microsoft.com/en-us/library/aa664765(VS.71).aspx
IMHO anyone should restrict themselves to using var to when the type is obvious.
1) With “new” and the type
2) The object name or what is assigned to it makes the type clear.
On the other hand AVOID var in cases like
3) A user defined function or object where it is hard to deduce the actual type
4) Expressions using overloaded functions, like + in myObject+myVar
‘var’ is wonderful when used intelligently. I only use it when a value’s type is directly presented, but even that helps tremendously with code readability.
var userList = new Dictionary(); // using explicit typing with generics is ugly as sin, var is better
var path = uri.ToString(); // pretty obvious
var path = Config.GetValue(“DataPath”); // also obvious
string descriptor = Device.GetDescriptor(); // not obvious, no var here, var bad
Those features are awesome! It really makes code so much easier to write. Just one thing that’s bugging me is that tuples require an external dependency, which is why I didn’t use them that much yet. Are there any plans to add ValueType to the desktop version of .NET Framework? So you don’t require an external DLL?
Awesome. Looking forward to more pattern matching.
Each time I read an article about new features in C#, I feel a little bit more depressed… I’m a Java developer…
I know this is not the place to say such thing, but, try Kotlin, just for once ^_^
Each time I read an article about new features in C#, I feel a little bit more depressed… I’m a C# developer…
C# is becoming new C++?
The “_” syntax for discarding out parameters and deconstruction variables looks confusing to me, because an underscore is a valid identifier, and the only thing that makes it special here is the absence of the type specifier. I think the “*” syntax could work much, much better.
The underscore is valid identifier of course, but there is almost no reason to use it as a whole variable name which is referenced in the code later. Who would know what that variable is for when read that code later? 🙂
The underscore as a variable/parameter name has already been used to name those parameters that were ignored in the function body, e.g., in lambdas and inline event handlers:
observableCollection.CollectionChanged += (_, args) => { /* code where we ignore the sender of the event */ };
or
If multiple parameters have to be ignored, additional underscores are added, e.g.:
ExecuteAndCallPassedCallback((_, __, importantArg, ___) => { /* code where we are interested only in the 3rd argument but have to specify all 4 arguments in the callback function */ });
From the C# 7.0 there are more use case scenarios (Try* methods pattern) because we do not have to specify the type.
The underscore for ignored parameters is handy, I first encountered the convention with its use in the Prolog language.
I like * over _ too. I have used _ for tiny lambda expressions because the variable name I wanted was already used in a containing scope, and _ would not make the one expression lambda unreadable.
Oh well, probably too late now! Guess I should have spoken up during RC’s.
I suppose that the sample:
~Person() => names.TryRemove(id, out *)
…should read TryRemove(id, out _)
Yes, I noticed this as well. The “*” was initially proposed, but it ended up being replaced with “_”.
i still have many concerns about how Deconstructors are implemented and expecially the lack of special character to define them (like finalizer’s ~)
i really hope this will not lead to a proliferation of reserved member name with magic behaviours, and that it will not return to hit the designer’s theet like a boomerang.
anyway, the idea is great and the rest of the new features are super awesome!
maybe i’m just overprotective because i really love c#
thanks
+1
Configuration (and everything) by convention is hot right now, but what if it goes out of style? I like it for frameworks, not so sure about languages yet (but I could maybe be convinced.)
Deconstruct is by far not the first of this kind. The foreach loop already “magically” calls a GetEnumerator() method (no, it does not require the IEnumerable or IEnumerable interfaces). The collection initialization syntax already “magically” calls an Add() method. The await keyword (NOT async) is similarly magic and doesn’t require the actual Task type (only async did, and now not even that). The fluent LINQ syntax magically calls any method called Where, Select, Join, etc.etc.
very good post enjoyed it a lot 🙂
Thanks a lot Mads and team, Great Work!!
I’m eager to make my coding easier with it and see what are you preparing for C# 8 or 7.1 😉
case Rectangle s when (s.Length == s.Height):
Is ‘when’ going to be a new Keyword?
It already is, has been used for exception filtering in catch clause, see here:
https://www.dotnetperls.com/catch
It already is, but was only used for filtering exceptions in the catch clause.
C# is sliding towards being a write-only language for a large sized solution code base.
Combine
a) The many language syntatic sugar to specify the same thing
b) The large number of language features
c) The programming by convention, e.g., ASP.NET MVC convention based routing, MVVM/XAML based convention based binding, etc
c1) Reflection, large chunks of a system being unreferenced at compile time or in the VS editor but hooked up at run-time or by an IL postprocessor
Write only language from Wikipedia
> Languages that are often derided as write-only include APL, DDT, Perl, Forth, TECO, Mathematica and regular expression syntax used in various languages. Attributes that these languages have in common include a large set of operators and a syntax which encourages, or at least permits, the writing of very dense code.
https://en.wikipedia.org/wiki/Write-only_language
For v6 and v7, only the following have promise:
– The ? operator for null reference checking (var x = a?.b?.c;)
– The => for 1 line property get or 1 line methods
– Nested methods. Though someone will figure out a way to return a nested method as an action to an outside caller and simulate a class with methods and properties inside of a single method. Declare everything as static and return reference to nested static methods and nested static variables.
– String interpolation with the $ operator
Other things give developers X more ways to make the language more difficult to read and understand.
Each individual operator may be easy to understand when isolated to 1 source code line, but will be a constant abrasive friction when used throughout a system.
For example, a using alias to let one not put ‘IsNullOrWhiteSpace()’ in the code instead of “string.IsNullOrWhiteSpace().’ That breaks any type of full text code searching a large multi-solution code base. Been there, done that with the yuck of the myriad of dumb ‘#define DATA_POINTER long’ , ‘#define MACHINE_OFFSET long’ in C++ or Windows.h.
Agree with the comment on the alias feature being abused like macros were in C/C++.
All other features in C# 7 seem worthwhile and beneficial though, including pattern matching and the tuple improvements. They are essentially borrowing the best elements that many functional languages already have and offering them to C# programmers. If you don’t think you’ll benefit from them or if you aren’t familiar with them then you can keep doing things the way you are already and ignore them, but I will definitely be taking advantage of them.
I tend to agree with the above poster. Although many readers here will share their personal preference for language design, I believe objectivity comes from an analysis of the language’s intent. With regard to C#, what kinds of problems was Anders Hejlsberg trying to solve when he created the language? How did his approach inform design and as a result, what became the distinguishing qualities of the language? … of course we can introduce an infinite variety of language features but what distinguishes C# from Perl? There is a developer culture aligned with each language and I think it is fair game to ask if the .NET team has lost their way.
> That breaks any type of full text code searching a large multi-solution code base.
Uhm, Visual Studio has had a “Find References” feature for years, and it works correctly for the case you describe. I would never go back to full-text code searching, since that also finds spurious references in literal strings, comments and commented-out code, etc.
It’s clear that the C# team want to incorporate as many functional language features as possible in this and future releases. This is understandable because by incorporating FP language features into C# it will elevate it to be a truly high level language.
Many of these and future FP language features would probably not have been under consideration had it not been for F#. In F# the C# designers have a fully tested .Net implementation of a FP language, without the need to spend years of R&D.
Without doubt FP language features will add a lot of complexity to the language. The question is whether or not the benefits warrant the extra complexity. Hopefully the C# designers have the restraint and good taste to avoid making it into a C++ish Frankenstein language.
I tried hard to find how to enable c# 7 in VS 2017 in a asp.net application (with the latest Roslyn installed). No way.
Enabling c#6 required adding this code to the web.config file:
What are we supposed to do for c# 7?
In short, update the reference to the “Microsoft.Net.Compilers” package to a 2.0.+ version. Then you can change the language version in your project settings to “C# 7.0”.
More details at http://stackoverflow.com/questions/42744689/enabling-c-sharp-7-in-a-asp-net-application
> …called ValueTuple. If you target a Framework that doesn’t yet include those types…
Why this type is not installed during VS2017 setup? Say, in .NET 4.6.3; WE MUST NOT jump on your dumpy nuget to get necessary types! Especially when they require access to Internet. Raise your a$$ and issue .NET 4.6.3 with all necessary types.
How do I get c# 7 features supported on build agents? Is there a Roslyn nugget package for it?
I suspect having latest MSBuild would do the trick. Check under visual studio downloads for “Build Tools for Visual Studio 2017” (https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=15).
Thanks, will test that
What is the status on non-core .net is 4.6.2 the final version of full framework? what is the status of WPF ?
In MSDN Magazine July 2009 “CLR Inside Out – Building Tuple” column, the CLRTeam mentioned they had made a decision to change Tuple from value type to reference type. Is that decision reversed?
https://msdn.microsoft.com/en-us/magazine/dd942829.aspx
There are 2 types of Tuple: System.Tuple is reference type and the new System.ValueTuple is value type.
Cool. Thanks for the explanation.
“Deconstruction” seems VERY similar to “Destructuring” syntax in one other popular language :)))
I love direction that C# language is evolving (aside from that one JavaScript like feature). Started with .NET/C# while was still in beta, 2001… And it was been awesome investment/choice. C# is living, growing and evolving language, with .net ecosystem.
This key message to C#: Don’t be obsessed with having “major” language features (or over do it, there is always next version), the convenient language features are used everyday… And make the language productive, efficient to express *clean code*, and overall pleasant to *read* and write alike… Don’t be deterred by negative comment, let C# be a language of envy to java and sql developers!
@Lee Dale @Mike.NET I was incredibly surprised, but the first new feature I used from C# 7 was actually Local Functions. I ended up writing a blog post about it: https://www.danielcrabtree.com/blog/73/c-sharp-7-dissecting-local-functions-to-understand-how-they-capture-local-variables
The second feature I ended up using was tuples and I loved them, but that wasn’t particularly surprising.
Out variables was the third feature I used and they made a nice addition. I always hated TryGetValue on dictionaries and mostly used a GetOrDefault helper, but TryGetValue is much more pleasant now.
Having this “hosted with (heart) by GitHub” underneath every code listing is REALLY distracting. Any way you can get rid of it?
It’s put there by GitHub’s gist script. I don’t think you can get rid of it.
A concise article demonstrating many useful new features. Nicely done all around!
How much of this is actually useable with UWP-compatible libraries and programs (given the various restrictions for UWP programs and libraries)?
still no final local variables.
I guess I’ll try using local functions instead? 😀
Pattern matching is quite new stuff for C# Developer. So i think it is better to introduce this feature step by step, Release by Release. The C# Team made the right decision.
A cool feature set. Thanks for sharing.
Please publish the C# 7.0 language specification in a document.
I don’t want to dig through all the blogs and GitHub design notes to read about a particular language feature.
When are these goodies coming to VB …. KEEP ‘Language Parity’ a first class PRIORITY!
Mads Torgersen discussed this in The .NET Language Strategy: https://blogs.msdn.microsoft.com/dotnet/2017/02/01/the-net-language-strategy/
They no longer on a shared course, which isn’t a surprise considering VB seems to be less and less used:
http://redmonk.com/sogrady/2017/03/17/language-rankings-1-17/
I just feel it’s becoming more harder to read things, everything lambda syntax! we are ending to these kinds of syntax
class Sample => public string A(int a, int b)=> return a+b; public string B(string input)=> return $”Hi {input}”;
That isn’t valid syntax. Or valid semantics.
For the ref local feature, and for the “ref int place = …” line, the only confusing part for me is the type of “place”. I was assuming it should be something like IntPtr, but it is just an int! How? so place.GetType().Name returns “Int32”.
My guess is that (as in C++) this is a `ref int`, so internally the compiler holds a pointer to an `int`.
And when you update the value, you update the value at that pointer location.
Just you never see/hold a pointer in your code, same as in C++ references.
Maybe it is better for understanding to consider `ref int` as the type and not just the `int` part.
Although I am not 100% how the C# compiler works, it should be the same as with `out` params.
They share some of the same `magic` as well.
Unfortunate that you can’t add XML documentation to a local function (e.g. summary tag).
C# 7.0 …
Good’ C# My love language /(*.*)\
Tuples are great, but what I really wanted was non-nullable reference types. About two thirds of all the bugs I fix are null reference exceptions.
Hmm. Maybe I’m a little thick, but the example for a custom Deconstructor doesn’t make any sense.
We have a class Point, with a method public void Deconstruct(out int x, out int y) { x = X; y = Y;}
That makes sense.
But then the article mentions to invoke it as (var myX, var myY) = GetPoint();
And that’s where you lose me. Is GetPoint an automatically generated instance method on Point (and the example is simply not clear on this)? So would it be more like:
var point = new Point(1, 2);
var (myX, myY) = point.GetPoint();
Because THAT makes more sense to me. Otherwise, if you’re calling GetPoint out of the blue, with no instance attached, there’s no context.
The other thing that would (sort of) make sense to me is to do something like:
var point = new Point(1, 2);
var (myX, myY) = point;
Which would also automatically call the deconstructor. But I admit that might be a bit far-fetched.
Or is it something completely different and I am totally missing the point? I’m not discounting that at all… 🙂
You got it with your last example:
var point = new Point(1, 2);
var (myX, myY) = point;
GetPoint() is just some method that returns a Point.
Using out and ref parameters usually tells about bad coding and now it’s even easier to do that which is not good. Also Tuples smells like bad code… well, maybe in the future C# will look like Javascript and it really sucks. Thank you for the improvements and keep up the good work 😀
Any reason we still cannot do this? :
dynamic d = new System.Dynamic.ExpandoObject();
d.A = “A”;
d[“test”] = “test”; // <=== Fails to compile!!! Why? Even simple dictionaries allow this! Even stupid JavaScript can do this!
(d as IDictionary).Add(“test”, “test”); // Do I have to do this?
—
Isn’t that one `ref` too many ? :
ref int place = ref Find(7, array); // aliases 7’s place in the array
Can’t we omit the 2nd `ref`? Coming from a C/C++ background and thinking in terms of pointers, it seems weird and confusing also…
—
The new features seem interesting.
I do have a fear that you might do something bad to the language accidentally at some point with all these new additions, but I hope you won’t.
If C# could also provide the same speed as C/C++ it would be the best language ever.
Great to see language evolving with new features and functionality, much changed since C# 2.0 – so good work! Yay for C# and yay for Open Source!
Very useful improvements indeed. The features which make C# the most convenient programming language. (Sadly enough, the implemetation is not as brilliant as the design, hopefully VS 2017 fixes some crucial C# bugs). I expected “throws” in function declaration and mandatory try–catch for some exceptions (simiar to Java) … maybe in c# 8 🙂
I would like to comment on ValueTask feature. There were troubles with virtual and abstract methods, when some subclass implementations were async, others weren’t, in which case you either had to use ‘async void’, or (rather brutally) disable warinings with pragma. Now is is possible to declare base mathed as ValueTask, and (I hope) override it with either Task or ValueTask whatever applicable.
Is it only me or does someone see C# becoming quite similar to python in syntax? Tuples, underscore, pattern matching (is) etc.
Wow, that got mangled. o.O
First sentence should read, “It is definitely possible to make var’s readability more murky than the second example you gave.”
Later, when I said “‘first’ and ‘last’ are still a little unclear —” the rest should read: “they [could], for example, mean first and last…”
Is it possible to use new C# features in VS2015?
Thanks for the much needed attention to the ‘thorny’ bits of the language. The subtleties of a language make it truly great to work with or put on the list of ‘pain in the arse’ to work. The improvements are greatly appreciated. Thanks *~Felix
What will happen if I ref return a field of temporary object?
Could that be safe after the temporary object is collected by GC?
ex)
class Foo
{
public int value;
static ref int GetFieldOfTempObj()
{
var temp = new Foo();
return ref temp.value;
}
static void Curious()
{
ref int tempField = ref GetFieldOfTempObj();
// Good bye temp obj~
GC.Collect();
// Is this safe?
WriteLine(tempField);
}
}
Just checked myself, that GC will not collect the temporary while ref local still refers any field of the object.
code)
// I don’t know how to keep indentation on posting comment. 🙁
using System;
class Program
{
class Foo
{
public int[] values = new int[5000];
public static ref int GetFieldOfTempObj(out WeakReference weakFoo)
{
var temp = new Foo();
temp.values[3000] = 15;
weakFoo = new WeakReference(temp);
return ref temp.values[3000];
}
}
static void Main(string[] args)
{
WeakReference weakFoo;
void FooTest()
{
ref int tempField = ref Foo.GetFieldOfTempObj(out weakFoo);
tempField += 20;
GC.Collect();
Console.WriteLine($”temp alive after gc: {weakFoo.TryGetTarget(out var _)}”);
Console.WriteLine($”temp field: {tempField}”);
}
FooTest();
GC.Collect();
Console.WriteLine($”temp still alive: {weakFoo.TryGetTarget(out var _)}”);
}
}
———–
result)
temp alive after gc: False
temp field: 35
temp still alive: False
p.s. Happy to see how convinient out vars and local functions are!
One more note: In above code, Foo was collected by GC but int[] of it was not collected.
code)
result)
temp alive after gc: False
array alive after gc: True
temp field: 35
temp still alive: False
array alive after gc: False
I’m afraid that I couldn’t find any editing / removing feature on comment.
code is at below link:
https://gist.github.com/ellongrey/6f965c7f4c3976fa16e0751cfbc11e6f#file-reflocaltest-cs
Awesome work! The things I want to see from C# in the next release are true inner classes and multiple inheritance, but that’s just me 🙂
Excited for C# 7, but nothing beats the string interpolation from C# 6! 🙂
Let’s hope C#8 brings enum generic constraints
.
dynamic u = 42;
if (u is int i)
// Error CS8121 An expression of type dynamic cannot be handled by a pattern of type int.
WHY?
Good Job
Awesome update!