SlideShare a Scribd company logo
@davidwengier
Lowering in C#
What’s really going on in your code?
David Wengier
Microsoft
NDC { Oslo }
2019
@davidwengier
foreach (int item in listOfInts)
{
// do something with item
}
for (int i = 0; i < listOfInts.Count; i++)
{
int item = listOfInts[i];
// do something with item
}
int i = 0;
while (i < listOfInts.Count)
{
int item = listOfInts[i];
// do something with item
i++;
}
int i = 0;
again:
int item = listOfInts[i];
// do something with item
i++;
if (i < listOfInts.Count)
{
goto again;
}
IL_0024: ldloc.0
IL_0025: ldloc.1
IL_0026: callvirt instance !0 class
[mscorlib]List`1<int32>::get_Item(int32)
IL_002b: pop
IL_002c: ldloc.1
IL_002d: ldc.i4.1
IL_002e: add
IL_002f: stloc.1
IL_0030: ldloc.1
IL_0031: ldloc.0
IL_0032: callvirt instance int32 class
[mscorlib]List`1<int32>::get_Count()
IL_0037: blt.s IL_0024
What is lowering?
IL
foreach
for
while
gotogoto
while
for
foreach
@davidwengier
What is lowering?
“A common technique … is to have the compiler
“lower” from high-level language features to low-level
language features in the same language.”
Eric Lippert
https://ericlippert.com/2014/04/28/lowering-in-language-design-part-one/
@davidwengier
LINQ
from c in customers
where c.Country == “AU”
select c;
@davidwengier
LINQ
customers.Where(c => c.Country == “AU”)
.Select(c => c);
@davidwengier
LINQ
Enumerable.Select(
Enumerable.Where(customers,
c => c.Country == “AU”),
c => c);
@davidwengier
LINQ
Enumerable.Select(
Enumerable.Where(customers, FilterCustomers),
SelectCustomer);
bool FilterCustomers(Customer c)
{
return c.Country == “AU”;
}
Customer SelectCustomer(Customer c)
{
return c;
}
@davidwengier
var message = "NDC Oslo";
decimal message = 5M;
string message = "NDC " + "Oslo";
string message = part1 + part2;
@davidwengier
Why do I want to know?
string message = "You have " + count + " items";
string message = $"You have {count} items";
string message = string.Format("You have {0} items",
count);
@davidwengier
foreach
foreach (int m in values)
{
Console.WriteLine(m);
}
@davidwengier
IEnumerable
interface IEnumerable
{
IEnumerator GetEnumerator();
}
interface IEnumerator
{
object Current { get; }
bool MoveNext();
void Reset();
}
interface IEnumerable<T> : IEnumerable
{
new IEnumerator<T> GetEnumerator();
}
interface IEnumerator<T> : IEnumerator, IDisposable
{
new T Current { get; }
}
@davidwengier
foreach
{
var e = values.GetEnumerator();
try
{
int m;
while (e.MoveNext())
{
m = (int)(int)e.Current;
Console.WriteLine(m);
}
}
finally
{
if (e != null && e is IDisposable)
{
((IDisposable)e).Dispose();
}
}
}
object[] v = new [] { 1, 2 };
Write(v);
void Write(object[] arr)
{
foreach (int s in arr)
{
Console.WriteLine(s);
}
}
Person[] v = new [] { Empl(),..};
Write(v);
void Write(Person[] arr)
{
foreach (Customer c in arr)
{
Handle(c);
}
}
@davidwengier
foreach (C# 5+)
{
var e = values.GetEnumerator();
try
{
while (e.MoveNext())
{
int m;
m = (int)(int)e.Current;
Console.WriteLine(m);
}
}
finally
{
if (e != null && e is IDisposable)
{
((IDisposable)e).Dispose();
}
}
}
@davidwengier
Lambdas
public class C
{
public void M()
{
Action<string> act = x => Console.WriteLine(x);
act(“hello”);
}
}
@davidwengier
Lambdas
public class C
{
public void M()
{
Action<string> act = _act;
act(“hello”);
}
private void _act(string x)
{
Console.WriteLine(x);
}
}
@davidwengier
Lambdas
public class C
{
public void M()
{
ActHelper c = new ActHelper();
Action<string> act = c.act;
act(“hello”);
}
private class ActHelper
{
internal void act(string x)
{
Console.WriteLine(x);
}
}
}
@davidwengier
Lambdas
public class C
{
public void M()
{
if (ActHelper.Instance._act == null)
{
ActHelper.Instance._act = new Action<string>(ActHelper.Instance.act);
}
Action<string> act = ActHelper.Instance._act;
act(“hello”);
}
private sealed class ActHelper
{
public static readonly ActHelper Instance = new ActHelper();
public static Action<string> _act;
internal void act(string x)
{
Console.WriteLine(x);
}
}
}
@davidwengier
public class C
{
public void M()
{
Action<string> act = x => Console.WriteLine(x);
act(“Hello”);
}
}
public class C
{
public void M()
{
ActHelper c = new ActHelper();
Action<string> act = c.act;
act(“Hello”);
}
private sealed class ActHelper
{
internal void act(string x)
{
Console.WriteLine(x);
}
}
}
@davidwengier
public class C
{
public void M()
{
string y = “ World”;
Action<string> act = x => Console.WriteLine(x + y);
act(“Hello”);
}
}
public class C
{
public void M()
{
ActHelper c = new ActHelper();
Action<string> act = c.act;
act(“Hello”);
}
private sealed class ActHelper
{
internal void act(string x)
{
Console.WriteLine(x + y);
}
}
}
public class C
{
public void M()
{
ActHelper c = new ActHelper();
Action<string> act = c.act;
act(“Hello”);
}
private sealed class ActHelper
{
public string y;
internal void act(string x)
{
Console.WriteLine(x + y);
}
}
}
public class C
{
public void M()
{
ActHelper c = new ActHelper();
c.y = “ World”;
Action<string> act = c.act;
act(“Hello”);
}
private sealed class ActHelper
{
public string y;
internal void act(string x)
{
Console.WriteLine(x + y);
}
}
}
@davidwengier
public class C
{
public void M()
{
string y = “ World”;
Action<string> act = x => Console.WriteLine(x + y);
y = “ Fish”;
act(“Hello”);
}
}
public class C
{
public void M()
{
ActHelper c = new ActHelper();
c.y = “ World”;
Action<string> act = c.act;
act(“Hello”);
}
private sealed class ActHelper
{
public string y;
internal void act(string x)
{
Console.WriteLine(x + y);
}
}
}
@davidwengier
public class C
{
public void M()
{
string y = “ World”;
Action<string> act = x => Console.WriteLine(x + y);
y = “ Fish”;
act(“Hello”);
}
}
public class C
{
public void M()
{
ActHelper c = new ActHelper();
c.y = “ World”;
Action<string> act = c.act;
c.y = “ Fish”;
act(“Hello”);
}
private sealed class ActHelper
{
public string y;
internal void act(string x)
{
Console.WriteLine(x + y);
}
}
}
@davidwengier
Foreach and lambdas
List<Action> things = new List<Action>();
foreach (int m in values)
{
things.Add(() => Console.WriteLine(m));
}
@davidwengier
Foreach and lambdas
List<Action> things = new List<Action>();
{
var e = values.GetEnumerator();
try
{
ActHelper c = new ActHelper();
while (e.MoveNext())
{
c.m = (int)(int)e.Current;
things.Add(new Action(c.act));
}
}
finally
{
if (e != null && e is IDisposable) ((IDisposable)e).Dispose();
}
}
@davidwengier
Foreach and lambdas (C# 5+)
List<Action> things = new List<Action>();
{
var e = values.GetEnumerator();
try
{
while (e.MoveNext())
{
ActHelper c = new ActHelper();
c.m = (int)(int)e.Current;
things.Add(new Action(c.act));
}
}
finally
{
if (e != null && e is IDisposable) ((IDisposable)e).Dispose();
}
}
@davidwengier
public class C
{
private int z;
public void M()
{
string y = “ World”;
Action<string> act = x => Console.Write(x + y + z);
act(“Hello”);
}
}
public class C
{
private int z;
public void M()
{
ActHelper c = new ActHelper();
c.y = “ World”;
c._this = this;
c.act(“Hello”);
}
private sealed class ActHelper
{
public C _this;
public string y;
internal void act(string x)
{
Console.Write(x + y + _this.z);
}
}
}
@davidwengier
yield
foreach (int x in GetInts())
{
Console.WriteLine(x);
}
public IEnumerable<int> GetInts()
{
yield return 1;
yield return 2;
yield return 3;
yield return 4;
yield return 5;
}
@davidwengier
yield
using (IEnumerator<int> enumerator = this.GetInts().GetEnumerator())
{
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
}
}
public IEnumerable<int> GetInts()
{
return new GetIntsHelper(-2);
}
@davidwengier
yield
private class GetIntsHelper : IEnumerable<int>, IEnumerable, IEnumerator<int>, IDisposable, IEnumerator
{
private int _state;
private int _current;
private int _initialThreadId;
int IEnumerator<int>.Current { get { return this._current; } }
object IEnumerator.Current { get { return this._current; } }
public GetIntsHelper(int initialState)
{
this._state = initialState;
this._initialThreadId = Environment.CurrentManagedThreadId;
}
void IDisposable.Dispose()
{
}
@davidwengier
yield
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
GetIntsHelper result;
if (this._state == -2 && this._initialThreadId == Environment.CurrentManagedThreadId)
{
this._state = 0;
result = this;
}
else
{
result = new GetIntsHelper(0);
}
return result;
}
@davidwengier
yield
bool IEnumerator.MoveNext()
{
switch (this._state)
{
case 0:
this._state = -1;
this._current = 1;
this._state = 1;
return true;
case 1:
this._state = -1;
this._current = 2;
this._state = 2;
return true;
case 2:
this._state = -1;
this._current = 3;
this._state = 3;
return true;
case 3:
this._state = -1;
this._current = 4;
this._state = 4;
return true;
case 4:
this._state = -1;
this._current = 5;
this._state = 5;
return true;
case 5:
this._state = -1;
return false;
default:
return false;
@davidwengier
Yield states
-2 : GetEnumerator() hasn’t been called
-1 : Running – Getting the next value
0 : Before – MoveNext() hasn’t been called
1- 4 : Suspended – Waiting for a MoveNext() call
5 : After – Finished.
@davidwengier
yield
public IEnumerable<int> GetInts()
{
foreach (int x in Enumerable.Range(1, 10))
{
yield return x;
}
}
@davidwengier
yield
private IEnumerator<int> _wrap;
void IDisposable.Dispose()
{
if (this._state == -3 || this._state == 1)
{
this._Finally();
}
}
private void _Finally()
{
this._state = -1;
if (this._wrap != null)
{
this._wrap.Dispose();
}
}
@davidwengier
yield
bool IEnumerator.MoveNext()
{
try
{
// ... Next slide
}
catch
{
this.Dispose();
throw;
}
}
@davidwengier
yield
if (this._state == 0)
{
this._state = -1;
this._wrap = Enumerable.Range(1, 10).GetEnumerator();
this._state = -3;
}
else
{
if (this._state != 1) return false;
this._state = -3;
}
if (this._wrap.MoveNext())
{
this._current = (int)this._wrap.Current;
this._state = 1;
return true;
}
else
{
this._Finally();
this._wrap = null;
return false;
}
@davidwengier
Yield states
-3 : Running – Getting the next value
-2 : GetEnumerator() hasn’t been called
-1 : Running – Getting the range enumerator
0 : Before – MoveNext() hasn’t been called
1 : Suspended (and After) – Waiting for a MoveNext() call
@davidwengier
Captain planet
private int _min;
public void M()
{
int max = 5;
foreach (int x in GetInts(max))
{
Console.WriteLine(x);
}
}
public IEnumerable<int> GetInts(int max)
{
yield return 1;
foreach (int x in Enumerable.Range(this._min, max).OrderBy(i => i * this._min + max))
{
yield return x;
}
}
???
@davidwengier
Want to know more?
• Roslyn source code
• Your favourite decompiler
• http://sharplab.io
@davidwengier
Thank you!
Questions?
Comments?
Quemments?
@davidwengier

More Related Content

What's hot

Lessons Learned Implementing a GraphQL API
Lessons Learned Implementing a GraphQL APILessons Learned Implementing a GraphQL API
Lessons Learned Implementing a GraphQL API
Dirk-Jan Rutten
 
Dependency rejection and TDD without Mocks
Dependency rejection and TDD without MocksDependency rejection and TDD without Mocks
Dependency rejection and TDD without Mocks
Antya Dev
 
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KZepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KThomas Fuchs
 
Dojo and Adobe AIR
Dojo and Adobe AIRDojo and Adobe AIR
Dojo and Adobe AIR
Nikolai Onken
 
Unbreakable: The Craft of Code
Unbreakable: The Craft of CodeUnbreakable: The Craft of Code
Unbreakable: The Craft of Code
Joe Morgan
 
ES6 patterns in the wild
ES6 patterns in the wildES6 patterns in the wild
ES6 patterns in the wild
Joe Morgan
 
Basic Tutorial of React for Programmers
Basic Tutorial of React for ProgrammersBasic Tutorial of React for Programmers
Basic Tutorial of React for Programmers
David Rodenas
 
ES3-2020-P3 TDD Calculator
ES3-2020-P3 TDD CalculatorES3-2020-P3 TDD Calculator
ES3-2020-P3 TDD Calculator
David Rodenas
 
Crossing platforms with JavaScript & React
Crossing platforms with JavaScript & React Crossing platforms with JavaScript & React
Crossing platforms with JavaScript & React
Robert DeLuca
 
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
tdc-globalcode
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6
Ignacio Martín
 
Adopting F# at SBTech
Adopting F# at SBTechAdopting F# at SBTech
Adopting F# at SBTech
Antya Dev
 
Typescript barcelona
Typescript barcelonaTypescript barcelona
Typescript barcelona
Christoffer Noring
 
React lecture
React lectureReact lecture
React lecture
Christoffer Noring
 
Open sourcing the store
Open sourcing the storeOpen sourcing the store
Open sourcing the store
Mike Nakhimovich
 
The Ring programming language version 1.9 book - Part 54 of 210
The Ring programming language version 1.9 book - Part 54 of 210The Ring programming language version 1.9 book - Part 54 of 210
The Ring programming language version 1.9 book - Part 54 of 210
Mahmoud Samir Fayed
 

What's hot (20)

Lessons Learned Implementing a GraphQL API
Lessons Learned Implementing a GraphQL APILessons Learned Implementing a GraphQL API
Lessons Learned Implementing a GraphQL API
 
An intro to cqrs
An intro to cqrsAn intro to cqrs
An intro to cqrs
 
Dependency rejection and TDD without Mocks
Dependency rejection and TDD without MocksDependency rejection and TDD without Mocks
Dependency rejection and TDD without Mocks
 
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KZepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
 
jQuery quick tuts
jQuery quick tutsjQuery quick tuts
jQuery quick tuts
 
Dojo and Adobe AIR
Dojo and Adobe AIRDojo and Adobe AIR
Dojo and Adobe AIR
 
Unbreakable: The Craft of Code
Unbreakable: The Craft of CodeUnbreakable: The Craft of Code
Unbreakable: The Craft of Code
 
ES6 patterns in the wild
ES6 patterns in the wildES6 patterns in the wild
ES6 patterns in the wild
 
Basic Tutorial of React for Programmers
Basic Tutorial of React for ProgrammersBasic Tutorial of React for Programmers
Basic Tutorial of React for Programmers
 
Granada_Perl_Workshop_2014_Google_API_Client
Granada_Perl_Workshop_2014_Google_API_ClientGranada_Perl_Workshop_2014_Google_API_Client
Granada_Perl_Workshop_2014_Google_API_Client
 
ES3-2020-P3 TDD Calculator
ES3-2020-P3 TDD CalculatorES3-2020-P3 TDD Calculator
ES3-2020-P3 TDD Calculator
 
Crossing platforms with JavaScript & React
Crossing platforms with JavaScript & React Crossing platforms with JavaScript & React
Crossing platforms with JavaScript & React
 
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6
 
Adopting F# at SBTech
Adopting F# at SBTechAdopting F# at SBTech
Adopting F# at SBTech
 
Typescript barcelona
Typescript barcelonaTypescript barcelona
Typescript barcelona
 
React lecture
React lectureReact lecture
React lecture
 
Open sourcing the store
Open sourcing the storeOpen sourcing the store
Open sourcing the store
 
Backbone Basics with Examples
Backbone Basics with ExamplesBackbone Basics with Examples
Backbone Basics with Examples
 
The Ring programming language version 1.9 book - Part 54 of 210
The Ring programming language version 1.9 book - Part 54 of 210The Ring programming language version 1.9 book - Part 54 of 210
The Ring programming language version 1.9 book - Part 54 of 210
 

Similar to Lowering in C#: What really happens with your code?, from NDC Oslo 2019

Java весна 2013 лекция 2
Java весна 2013 лекция 2Java весна 2013 лекция 2
Java весна 2013 лекция 2Technopark
 
OBJECTS IN Object Oriented Programming .ppt
OBJECTS IN Object Oriented Programming .pptOBJECTS IN Object Oriented Programming .ppt
OBJECTS IN Object Oriented Programming .ppt
SaadAsim11
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#
Juan Pablo
 
C sharp 8
C sharp 8C sharp 8
C sharp 8
Germán Küber
 
Minicurso Android
Minicurso AndroidMinicurso Android
Minicurso Android
Mario Jorge Pereira
 
662305 10
662305 10662305 10
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
Michael Galpin
 
Android Design Patterns
Android Design PatternsAndroid Design Patterns
Android Design Patterns
Godfrey Nolan
 
TDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETTDC2016SP - Trilha .NET
TDC2016SP - Trilha .NET
tdc-globalcode
 
Infinum Android Talks #20 - DiffUtil
Infinum Android Talks #20 - DiffUtilInfinum Android Talks #20 - DiffUtil
Infinum Android Talks #20 - DiffUtil
Infinum
 
Ipc: aidl sexy, not a curse
Ipc: aidl sexy, not a curseIpc: aidl sexy, not a curse
Ipc: aidl sexy, not a curseYonatan Levin
 
IPC: AIDL is sexy, not a curse
IPC: AIDL is sexy, not a curseIPC: AIDL is sexy, not a curse
IPC: AIDL is sexy, not a curse
Yonatan Levin
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
Dmitry Sheiko
 
Create a class BinarySearchTree- A class that implements the ADT binar.pdf
Create a class BinarySearchTree- A class that implements the ADT binar.pdfCreate a class BinarySearchTree- A class that implements the ADT binar.pdf
Create a class BinarySearchTree- A class that implements the ADT binar.pdf
shyamsunder1211
 
Pragmatic metaprogramming
Pragmatic metaprogrammingPragmatic metaprogramming
Pragmatic metaprogramming
Mårten Rånge
 
2. Design patterns. part #2
2. Design patterns. part #22. Design patterns. part #2
2. Design patterns. part #2
Leonid Maslov
 
Design Patterns
Design PatternsDesign Patterns
Design Patterns
Lorna Mitchell
 
New C# features
New C# featuresNew C# features
New C# features
Alexej Sommer
 

Similar to Lowering in C#: What really happens with your code?, from NDC Oslo 2019 (20)

Java весна 2013 лекция 2
Java весна 2013 лекция 2Java весна 2013 лекция 2
Java весна 2013 лекция 2
 
OBJECTS IN Object Oriented Programming .ppt
OBJECTS IN Object Oriented Programming .pptOBJECTS IN Object Oriented Programming .ppt
OBJECTS IN Object Oriented Programming .ppt
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#
 
C sharp 8
C sharp 8C sharp 8
C sharp 8
 
Minicurso Android
Minicurso AndroidMinicurso Android
Minicurso Android
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
662305 10
662305 10662305 10
662305 10
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
 
Android Design Patterns
Android Design PatternsAndroid Design Patterns
Android Design Patterns
 
Mattbrenner
MattbrennerMattbrenner
Mattbrenner
 
TDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETTDC2016SP - Trilha .NET
TDC2016SP - Trilha .NET
 
Infinum Android Talks #20 - DiffUtil
Infinum Android Talks #20 - DiffUtilInfinum Android Talks #20 - DiffUtil
Infinum Android Talks #20 - DiffUtil
 
Ipc: aidl sexy, not a curse
Ipc: aidl sexy, not a curseIpc: aidl sexy, not a curse
Ipc: aidl sexy, not a curse
 
IPC: AIDL is sexy, not a curse
IPC: AIDL is sexy, not a curseIPC: AIDL is sexy, not a curse
IPC: AIDL is sexy, not a curse
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
Create a class BinarySearchTree- A class that implements the ADT binar.pdf
Create a class BinarySearchTree- A class that implements the ADT binar.pdfCreate a class BinarySearchTree- A class that implements the ADT binar.pdf
Create a class BinarySearchTree- A class that implements the ADT binar.pdf
 
Pragmatic metaprogramming
Pragmatic metaprogrammingPragmatic metaprogramming
Pragmatic metaprogramming
 
2. Design patterns. part #2
2. Design patterns. part #22. Design patterns. part #2
2. Design patterns. part #2
 
Design Patterns
Design PatternsDesign Patterns
Design Patterns
 
New C# features
New C# featuresNew C# features
New C# features
 

Recently uploaded

Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Globus
 
APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)
Boni García
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Łukasz Chruściel
 
Enterprise Resource Planning System in Telangana
Enterprise Resource Planning System in TelanganaEnterprise Resource Planning System in Telangana
Enterprise Resource Planning System in Telangana
NYGGS Automation Suite
 
Text-Summarization-of-Breaking-News-Using-Fine-tuning-BART-Model.pptx
Text-Summarization-of-Breaking-News-Using-Fine-tuning-BART-Model.pptxText-Summarization-of-Breaking-News-Using-Fine-tuning-BART-Model.pptx
Text-Summarization-of-Breaking-News-Using-Fine-tuning-BART-Model.pptx
ShamsuddeenMuhammadA
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
Philip Schwarz
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
abdulrafaychaudhry
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
Paco van Beckhoven
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
Juraj Vysvader
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
Globus
 
AI Genie Review: World’s First Open AI WordPress Website Creator
AI Genie Review: World’s First Open AI WordPress Website CreatorAI Genie Review: World’s First Open AI WordPress Website Creator
AI Genie Review: World’s First Open AI WordPress Website Creator
Google
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket ManagementUtilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
Neo4j
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
rickgrimesss22
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Neo4j
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
Drona Infotech
 
Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
Deuglo Infosystem Pvt Ltd
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
Max Andersen
 

Recently uploaded (20)

Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
 
APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
 
Enterprise Resource Planning System in Telangana
Enterprise Resource Planning System in TelanganaEnterprise Resource Planning System in Telangana
Enterprise Resource Planning System in Telangana
 
Text-Summarization-of-Breaking-News-Using-Fine-tuning-BART-Model.pptx
Text-Summarization-of-Breaking-News-Using-Fine-tuning-BART-Model.pptxText-Summarization-of-Breaking-News-Using-Fine-tuning-BART-Model.pptx
Text-Summarization-of-Breaking-News-Using-Fine-tuning-BART-Model.pptx
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
 
AI Genie Review: World’s First Open AI WordPress Website Creator
AI Genie Review: World’s First Open AI WordPress Website CreatorAI Genie Review: World’s First Open AI WordPress Website Creator
AI Genie Review: World’s First Open AI WordPress Website Creator
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket ManagementUtilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
 
Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
 

Lowering in C#: What really happens with your code?, from NDC Oslo 2019

  • 1. @davidwengier Lowering in C# What’s really going on in your code? David Wengier Microsoft NDC { Oslo } 2019
  • 2. @davidwengier foreach (int item in listOfInts) { // do something with item } for (int i = 0; i < listOfInts.Count; i++) { int item = listOfInts[i]; // do something with item } int i = 0; while (i < listOfInts.Count) { int item = listOfInts[i]; // do something with item i++; } int i = 0; again: int item = listOfInts[i]; // do something with item i++; if (i < listOfInts.Count) { goto again; } IL_0024: ldloc.0 IL_0025: ldloc.1 IL_0026: callvirt instance !0 class [mscorlib]List`1<int32>::get_Item(int32) IL_002b: pop IL_002c: ldloc.1 IL_002d: ldc.i4.1 IL_002e: add IL_002f: stloc.1 IL_0030: ldloc.1 IL_0031: ldloc.0 IL_0032: callvirt instance int32 class [mscorlib]List`1<int32>::get_Count() IL_0037: blt.s IL_0024 What is lowering? IL foreach for while gotogoto while for foreach
  • 3. @davidwengier What is lowering? “A common technique … is to have the compiler “lower” from high-level language features to low-level language features in the same language.” Eric Lippert https://ericlippert.com/2014/04/28/lowering-in-language-design-part-one/
  • 4. @davidwengier LINQ from c in customers where c.Country == “AU” select c;
  • 7. @davidwengier LINQ Enumerable.Select( Enumerable.Where(customers, FilterCustomers), SelectCustomer); bool FilterCustomers(Customer c) { return c.Country == “AU”; } Customer SelectCustomer(Customer c) { return c; }
  • 8. @davidwengier var message = "NDC Oslo"; decimal message = 5M; string message = "NDC " + "Oslo"; string message = part1 + part2;
  • 9. @davidwengier Why do I want to know? string message = "You have " + count + " items"; string message = $"You have {count} items"; string message = string.Format("You have {0} items", count);
  • 10. @davidwengier foreach foreach (int m in values) { Console.WriteLine(m); }
  • 11. @davidwengier IEnumerable interface IEnumerable { IEnumerator GetEnumerator(); } interface IEnumerator { object Current { get; } bool MoveNext(); void Reset(); } interface IEnumerable<T> : IEnumerable { new IEnumerator<T> GetEnumerator(); } interface IEnumerator<T> : IEnumerator, IDisposable { new T Current { get; } }
  • 12. @davidwengier foreach { var e = values.GetEnumerator(); try { int m; while (e.MoveNext()) { m = (int)(int)e.Current; Console.WriteLine(m); } } finally { if (e != null && e is IDisposable) { ((IDisposable)e).Dispose(); } } } object[] v = new [] { 1, 2 }; Write(v); void Write(object[] arr) { foreach (int s in arr) { Console.WriteLine(s); } } Person[] v = new [] { Empl(),..}; Write(v); void Write(Person[] arr) { foreach (Customer c in arr) { Handle(c); } }
  • 13. @davidwengier foreach (C# 5+) { var e = values.GetEnumerator(); try { while (e.MoveNext()) { int m; m = (int)(int)e.Current; Console.WriteLine(m); } } finally { if (e != null && e is IDisposable) { ((IDisposable)e).Dispose(); } } }
  • 14. @davidwengier Lambdas public class C { public void M() { Action<string> act = x => Console.WriteLine(x); act(“hello”); } }
  • 15. @davidwengier Lambdas public class C { public void M() { Action<string> act = _act; act(“hello”); } private void _act(string x) { Console.WriteLine(x); } }
  • 16. @davidwengier Lambdas public class C { public void M() { ActHelper c = new ActHelper(); Action<string> act = c.act; act(“hello”); } private class ActHelper { internal void act(string x) { Console.WriteLine(x); } } }
  • 17. @davidwengier Lambdas public class C { public void M() { if (ActHelper.Instance._act == null) { ActHelper.Instance._act = new Action<string>(ActHelper.Instance.act); } Action<string> act = ActHelper.Instance._act; act(“hello”); } private sealed class ActHelper { public static readonly ActHelper Instance = new ActHelper(); public static Action<string> _act; internal void act(string x) { Console.WriteLine(x); } } }
  • 18. @davidwengier public class C { public void M() { Action<string> act = x => Console.WriteLine(x); act(“Hello”); } } public class C { public void M() { ActHelper c = new ActHelper(); Action<string> act = c.act; act(“Hello”); } private sealed class ActHelper { internal void act(string x) { Console.WriteLine(x); } } }
  • 19. @davidwengier public class C { public void M() { string y = “ World”; Action<string> act = x => Console.WriteLine(x + y); act(“Hello”); } } public class C { public void M() { ActHelper c = new ActHelper(); Action<string> act = c.act; act(“Hello”); } private sealed class ActHelper { internal void act(string x) { Console.WriteLine(x + y); } } } public class C { public void M() { ActHelper c = new ActHelper(); Action<string> act = c.act; act(“Hello”); } private sealed class ActHelper { public string y; internal void act(string x) { Console.WriteLine(x + y); } } } public class C { public void M() { ActHelper c = new ActHelper(); c.y = “ World”; Action<string> act = c.act; act(“Hello”); } private sealed class ActHelper { public string y; internal void act(string x) { Console.WriteLine(x + y); } } }
  • 20. @davidwengier public class C { public void M() { string y = “ World”; Action<string> act = x => Console.WriteLine(x + y); y = “ Fish”; act(“Hello”); } } public class C { public void M() { ActHelper c = new ActHelper(); c.y = “ World”; Action<string> act = c.act; act(“Hello”); } private sealed class ActHelper { public string y; internal void act(string x) { Console.WriteLine(x + y); } } }
  • 21. @davidwengier public class C { public void M() { string y = “ World”; Action<string> act = x => Console.WriteLine(x + y); y = “ Fish”; act(“Hello”); } } public class C { public void M() { ActHelper c = new ActHelper(); c.y = “ World”; Action<string> act = c.act; c.y = “ Fish”; act(“Hello”); } private sealed class ActHelper { public string y; internal void act(string x) { Console.WriteLine(x + y); } } }
  • 22. @davidwengier Foreach and lambdas List<Action> things = new List<Action>(); foreach (int m in values) { things.Add(() => Console.WriteLine(m)); }
  • 23. @davidwengier Foreach and lambdas List<Action> things = new List<Action>(); { var e = values.GetEnumerator(); try { ActHelper c = new ActHelper(); while (e.MoveNext()) { c.m = (int)(int)e.Current; things.Add(new Action(c.act)); } } finally { if (e != null && e is IDisposable) ((IDisposable)e).Dispose(); } }
  • 24. @davidwengier Foreach and lambdas (C# 5+) List<Action> things = new List<Action>(); { var e = values.GetEnumerator(); try { while (e.MoveNext()) { ActHelper c = new ActHelper(); c.m = (int)(int)e.Current; things.Add(new Action(c.act)); } } finally { if (e != null && e is IDisposable) ((IDisposable)e).Dispose(); } }
  • 25. @davidwengier public class C { private int z; public void M() { string y = “ World”; Action<string> act = x => Console.Write(x + y + z); act(“Hello”); } } public class C { private int z; public void M() { ActHelper c = new ActHelper(); c.y = “ World”; c._this = this; c.act(“Hello”); } private sealed class ActHelper { public C _this; public string y; internal void act(string x) { Console.Write(x + y + _this.z); } } }
  • 26. @davidwengier yield foreach (int x in GetInts()) { Console.WriteLine(x); } public IEnumerable<int> GetInts() { yield return 1; yield return 2; yield return 3; yield return 4; yield return 5; }
  • 27. @davidwengier yield using (IEnumerator<int> enumerator = this.GetInts().GetEnumerator()) { while (enumerator.MoveNext()) { Console.WriteLine(enumerator.Current); } } public IEnumerable<int> GetInts() { return new GetIntsHelper(-2); }
  • 28. @davidwengier yield private class GetIntsHelper : IEnumerable<int>, IEnumerable, IEnumerator<int>, IDisposable, IEnumerator { private int _state; private int _current; private int _initialThreadId; int IEnumerator<int>.Current { get { return this._current; } } object IEnumerator.Current { get { return this._current; } } public GetIntsHelper(int initialState) { this._state = initialState; this._initialThreadId = Environment.CurrentManagedThreadId; } void IDisposable.Dispose() { }
  • 29. @davidwengier yield IEnumerator<int> IEnumerable<int>.GetEnumerator() { GetIntsHelper result; if (this._state == -2 && this._initialThreadId == Environment.CurrentManagedThreadId) { this._state = 0; result = this; } else { result = new GetIntsHelper(0); } return result; }
  • 30. @davidwengier yield bool IEnumerator.MoveNext() { switch (this._state) { case 0: this._state = -1; this._current = 1; this._state = 1; return true; case 1: this._state = -1; this._current = 2; this._state = 2; return true; case 2: this._state = -1; this._current = 3; this._state = 3; return true; case 3: this._state = -1; this._current = 4; this._state = 4; return true; case 4: this._state = -1; this._current = 5; this._state = 5; return true; case 5: this._state = -1; return false; default: return false;
  • 31. @davidwengier Yield states -2 : GetEnumerator() hasn’t been called -1 : Running – Getting the next value 0 : Before – MoveNext() hasn’t been called 1- 4 : Suspended – Waiting for a MoveNext() call 5 : After – Finished.
  • 32. @davidwengier yield public IEnumerable<int> GetInts() { foreach (int x in Enumerable.Range(1, 10)) { yield return x; } }
  • 33. @davidwengier yield private IEnumerator<int> _wrap; void IDisposable.Dispose() { if (this._state == -3 || this._state == 1) { this._Finally(); } } private void _Finally() { this._state = -1; if (this._wrap != null) { this._wrap.Dispose(); } }
  • 34. @davidwengier yield bool IEnumerator.MoveNext() { try { // ... Next slide } catch { this.Dispose(); throw; } }
  • 35. @davidwengier yield if (this._state == 0) { this._state = -1; this._wrap = Enumerable.Range(1, 10).GetEnumerator(); this._state = -3; } else { if (this._state != 1) return false; this._state = -3; } if (this._wrap.MoveNext()) { this._current = (int)this._wrap.Current; this._state = 1; return true; } else { this._Finally(); this._wrap = null; return false; }
  • 36. @davidwengier Yield states -3 : Running – Getting the next value -2 : GetEnumerator() hasn’t been called -1 : Running – Getting the range enumerator 0 : Before – MoveNext() hasn’t been called 1 : Suspended (and After) – Waiting for a MoveNext() call
  • 37. @davidwengier Captain planet private int _min; public void M() { int max = 5; foreach (int x in GetInts(max)) { Console.WriteLine(x); } } public IEnumerable<int> GetInts(int max) { yield return 1; foreach (int x in Enumerable.Range(this._min, max).OrderBy(i => i * this._min + max)) { yield return x; } } ???
  • 38. @davidwengier Want to know more? • Roslyn source code • Your favourite decompiler • http://sharplab.io

Editor's Notes

  1. Invented a language, having a language design meeting. Someone suggests “foreach”. Everyone agrees, except the guy in the corner. Lowering. He’s lazy. “why not just use a for loop”
  2. Because I love it! One abstraction layer deeper Debugging Performance
  3. Lets look at one of those previous examples in detail.
  4. Lets look at one of those previous examples in detail.
  5. Simplified generic version. There are specific overloads for arrays, stirngs etc. No type on GetEnumerator. Duck typing. Not really var, the compiler works it out, I just can’t express it. Also checks for implicit implementations and casts to IEnumerable. If necessary. Two casts. One for item type, one for the type of the loop variable (because designed before generics, eg ArrayList). Means you can loop through objects, and ask for strings. EG ANIMATIONS!! Those casts could fail. Disposable is optional. Compiler will work out whether to include it (and will leave off the try..finally entirely if it can Note the brackets to introduce a new scope This is the C# 4 and below version.
  6. Subtle difference. Variable declaration inside while loop. This is a breaking change. Why? Answer is closures, which brings us to our next bit of lowering.
  7. To talk about closures, I think its easiest to talk about lambdas.
  8. This is what it logically does, however this has a problem. Without knowing what Console.WriteLine does, and depending on what is passed in, we can’t guarantee this doesn’t hold a reference to class C. So instead this is what the compiler does:
  9. By using a new class, even if an instance is held in memory the compiler knows its as small as it can be. Obviously these method and class names would be different. In fact, compiler deliberately uses names that are invalid C#
  10. This is _really_ what the compiler does though. Apologies for the size.. Various optimizations. So far so good? Cool. The other thing we can do wth lambdas and delegates is create closures.
  11. Lets go back to our original lamba, but make a small change. This action now creates a closure over y. Now the compiler has to put y in the new class, and store a reference to it. This looks like this.
  12. Lets go back to our original lamba, but make a small change. This action now creates a closure over y. Now the compiler has to put y in the new class, and store a reference to it. This looks like this.
  13. So, can you see the problem? It doesn’t matter when you create the delegate, we’ve capture the variable y, not the value of the variable y. So the code uses the value of the variable y as at the time it is executed.
  14. So, can you see the problem? It doesn’t matter when you create the delegate, we’ve capture the variable y, not the value of the variable y. So the code uses the value of the variable y as at the time it is executed.
  15. So lets revisit our foreach loop, but now add a lambda in the middle. We’ll just collect a list of things to do later.. Call it poor mans async 
  16. Now this gets expanded as we know. I’ve highlighted the new bits.
  17. In C# 5 however, we now move the declaration of m inside the loop, therefore we don’t have a problem.. Essentially when C# 4 came out everyone was so lambda happy that it exposed this quirk. Why did they do it the other way first? Matches the “for” semantics, of having one loop variable that is redefined. Just that with “for” its much more obvious, because the user is writing that redefinition.
  18. One last word on closures, is what the difference is when we close over a class level field, property, method etc. The field is not hoisted, instead the helper class has a reference to the original object. This can potentially lead to memory leaks. Solved by introducing local variables to capture the value, though does change the semantics (value capture not variable capture)
  19. Kinda still on foreaches, lets look at the yield statement. Things get pretty tricky with this one.. So any questions before we continue?
  20. The foreach part we know, and GetInts is still a method that returns an enumerable. The content of GetInts has been moved to a new class though, like we saw with lambdas. Lets look at that class
  21. So, it implements a few interfaces. And mose of these things are obvious. It captures the thread id, which we’ll see later is used for thread safety. It implements Idisposable as a just in case, and in this case doesn’t need to dispose anything. Will see more later. Current we’ve seen before from Ienumerable, and there is a local variable to track it. And it stores state. As you might know, or have guessed, the yield enumerator uses a state machine. The intial state, if you remember, is -2
  22. Here is the GetEnumerator method. This is where we do some thread checking. So if GetEnumerator() is called from the same thread, and we have our initial state, then this is the thing we use. This is what allows our class to be an enumerable, that can be returned from GetInts(), and an enumerator, that can do the enumeration. This sets the state to 0. If something else calls GetEnumerator(), or we’re in a different state, then return a new instance with a 0 initial state.
  23. Pretty basic state machine. Essentially its an unrolled loop, which makes sense because if you think about our yield statement, that was too. 4 states: Before (-2, 0), Running (-1), Suspended and After (positive integers) Questions? More realistic uses get a bit harder, so lets look at one.
  24. This is a bit more typical, where in your method you’d be looping through something else, and yield returning. If the yield return unrolls the loop, well what happens when you put a loop in your loop unrolling? Lets look at the differences.
  25. A new Enumerator field, called wrap. In Dispose we call Finally, and that disposes of the wrapped enumerator. The weird empty try..finally block, I cannot explain!. Could be a decompilation problem.
  26. Just to save space on the next slide, MoveNext has nothing new that’s interesting.. Just a dispose call in a catch
  27. Hopefully still big enough.. This looks very different! But its still a state machine. Initial state is 0, so first we set state to -3 (another type of “Running” - about get next), and get a reference to the range enumerator. Then we call MoveNext, set state to 1. Each call to this MoveNext calls the wrapped MoveNext, until we run out. At the end we call Finally() again. -1 is running the GetEnumerator, -3 is running the MoveNext
  28. This instance doesn’t really have an “After” because it doesn’t know when to stop on its own, it simply passes calls on to the wrapped enumerator, and hence relies on that enumerators After state.
  29. And of course you can combine these things, by having multiple yield returns, the iterator can close over variables, and fields, and can include a lambda that does the same! This is why lowering is good. No need to implement all of this lot in IL. We know this bit will become a class, closing over some things.. And this… At the end it will just be classes with straight forward code, containing pretty much just gotos