5. Changing our tune…
Run on Windows
.NET as system component
Run on VM (CLR)
Black box compilers
Edit in Visual Studio
Proprietary
Run everywhere
Deploy with app
Compile to native
Open compiler APIs
Use your favorite editor
Open source
8. The Roslyn Compiler API
There should only need to be
one code base in the world
for understanding C#
9. Other IDEs On other platforms
Custom diagnostics Style, API usage, patterns…
Source transformation Refactorings, fixers, migraters, updaters…
Scripting Batch scripts, hosted code…
Coding in execution REPL, edit-and-continue…
Documentation Hyperlinked API docs, web playgrounds…
Static analysis Code metrics, graphs, telemetry, code querying…
Metaprogramming Source generators, injectors, weavers…
Other language understanding scenarios
10. Custom analyzers and fixes
Plug in to diagnostic reporting and code fixing
infrastructure
Batch and interactive
“Code-aware libraries”
APIs can ship with analyzers and fixes to guide their users
Toolboxes
Style enforcement, discovery of opportunities
15. Pattern matching
if (o is Point p) { WriteLine($"({p.X}, {p.Y})"); }
if (o is Point p && p.X == 5) { WriteLine($"Y: {p.Y}"); }
if (o is Point(5, var y)) { WriteLine($"Y: {y}"); }
16. Patterns in switch statements
switch (o)
{
case int i:
WriteLine($"Number {i}");
break;
case Point(int x, int y):
WriteLine($"({x},{y})");
break;
case string s when s.Length > 0:
WriteLine(s);
break;
case null:
WriteLine("<null>");
break;
default:
WriteLine("<other>");
break;
}
17. Tuples
public (int sum, int count) Tally(IEnumerable<int> values)
{
var s = 0; var c = 0;
foreach (var value in values) { s += value; c++; }
return (s, c);
}
var t = Tally(myValues);
Console.WriteLine($"Sum: {t.sum}, count: {t.count}");
(var s, var c) = Tally(myValues);
Console.WriteLine($"Sum: {s}, count: {c}");
18. Records
class Person : IEquatable<Person>
{
public string First { get; }
public string Last { get; }
public Person(string First, string Last) { this.First = First; this.Last = Last; }
public (string First, string Last) Deconstruct() => (First, Last);
public bool Equals(Person other) => First == other.First && Last == other.Last;
public override bool Equals(object obj) => obj is Person other ? Equals(other) : false;
public override int GetHashCode() => GreatHashFunction(First, Last);
…
}
class Person(string First, string Last);
20. Nullable and non-nullable reference types
string? n; // Nullable reference type
string s; // Non-nullable reference type
n = null; // Sure; it's nullable
s = null; // Warning! Shouldn’t be null!
s = n; // Warning! Really!
WriteLine(s.Length); // Sure; it’s not null
WriteLine(n.Length); // Warning! Could be null!
if (n != null) { WriteLine(n.Length); } // Sure; you checked
WriteLine(n!.Length); // Ok, if you insist!
Evolve: it’s now easier to evolve the languages
Enable: it enables a whole ecosystem of code analysis, refactoring tools, and tools that act on code
Dogfood: we can roll out new language features and tooling to early adopters for feedback without having to ship VS or compilers
Pace of innovation is not necessarily whenever you get an idea. There’s such a thing as an innovation that comes too soon.
The evolution comparison is also interesting because it’s the environment that drives innovation, not random mutations.
Horseshoe crab picture by Didier Descouens (Own work) [CC BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons
Saddleback caterpillar picture by Mary Keim https://www.flickr.com/photos/38514062@N03/9410316517/in/photolist-fkykfv-fkyk58-fpYfpv https://creativecommons.org/licenses/by-nc-sa/2.0/
Launch VS, open REPL (view/other windows/c# interactive)
2+2, Console.WriteLine(“Hello SpaceX”) – Remember, Alt+up arrow to copy a previous statement. CTRL+Enter to execute no matter where the cursor is.
using static System.Console;
Console.WriteLine(“Hello SpaceX”) <- Roslyn tells you what became unnecessary. Hover to see recommendation. Remove “Console”
Interpolating strings should be easy: Add the $ in front of the string, and start introducing expressions: {2016} at the end of the string.
Replace expression with {2015+1}
Make it reusable next year by writing{DateTime.Now.Year}
You can also declare variables in the REPL:var awesomeCompany = “SpaceX”; and then replace the static string.
Let’s define a method now: take the previsous code and change it to:string Greeting() {return $”Hello {awesomeCompany} {DateTime.Now.Year}”;}then call Greeting()
Change it to a expression-bodied function:string Greeting() => $"Hello { awesomeCompany} { DateTime.Now.Year}";
Let’s look at other C#6 features. First, auto-property initializers:public class Person{ public string FirstName { get; } = "Brett";}new Person().FirstNameYou can also set such properties from a constructor, which is nice as it removes the need for a private setter that you never don’t need.
You can replace the property definition withpublic string FirstName => "Brett";
Add the following members to the class to introduce the null-coalesce operator:public string LastName { get; set; }public string Initials => FirstName?[0].ToString() + LastName?[0].ToString();then do new Person().Initialsthen new Person { LastName = "Morrison" }.Initials
We have a new operator that can make a lot of refactoring scenarios more robust: nameofnameof(Person)string Greeting(string awesomeCompany) => $"Hello {nameof(awesomeCompany)} { awesomeCompany } { DateTime.Now.Year }";Refactoring is going to work inside string interpolation.
Index initializers:var numbers = new Dictionary<int, string>{ [1] = "One", [42] = "Forty-two“};numbers[42]
Other C#6 features include await in catch blocks, and “when” conditions on catch.
Closest current equivalent code is var p = o as Point; if (p != null) {… but that gives p too large a scope.
Alternative today is to declare a small class, or have out parameters.
The syntax is designed to mirror that of function arguments.
String! Could have been another solution, but would have implied that non-nullable is the exception.
Having string? makes nullable strings the exception, as it should have been from the start, but enforcing string without qualifiers to be non-nullable would have been far too breaking.
In the end, emitting warnings for failures to check for null is a good compromise as it encourages the right behavior without breaking existing code.