Mixing Functional and Object Oriented approaches to programming in C# Mike Wagg & Mark Needham
C# 1.0
http://www.impawards.com/2003/posters/back_in_the_day.jpg
int[] ints = new int[] {1, 2, 3, 4, 5}  
int[] Filter(int[] ints) {     ArrayList results = new ArrayList();     foreach (int i in ints)     { if (i % 2 == 0) { re...
int[] ints = new int[] {1, 2, 3, 4, 5}  
int[] Filter(int[] ints) {     ArrayList results = new ArrayList();     foreach (int i in ints)     { if (i >3) { results....
int[] Filter(int[] ints) {     ArrayList results = new ArrayList();     foreach (int i in ints)     { if ( i % 2 == 0 ) { ...
int[] Filter(int[] ints) {     ArrayList results = new ArrayList();     foreach (int i in ints)     { if ( i > 3 ) { resul...
interface IIntegerPredicate { bool Matches(int value); }
class EvenPredicate : IIntegerPredicate { bool Matches(int value) { return value % 2 == 0; } }
class GreaterThanThreePredicate : IIntegerPredicate { bool Matches(int value) { return value > 3; } }
int[] Filter(int[] ints, IIntegerPredicate predicate) {     ArrayList results = new ArrayList();     foreach (int i in int...
int[] ints = new int[] {1, 2, 3, 4, 5 }; int[] even = Filter(ints, new EvenPredicate()); int[] greaterThanThree = Filter(i...
interface IIntegerPredicate { bool Matches(int value); }
bool delegate IntegerPredicate(int value);
bool Even(int value) { return value % 2 == 0; }
bool GreaterThanThree(int value) { return value > 3; }
int[] Filter(int[] ints, IntegerPredicate predicate) {     ArrayList results = new ArrayList();     foreach (int i in ints...
int[] ints = new int[] {1, 2, 3, 4, 5 }; int[] even = Filter(ints,  new IntegerPredicate(Even)); Int[] greaterThanThree = ...
C# 2.0  
Inference int[] ints = new int[] {1, 2, 3, 4, 5 }; int[] even = Filter(ints,  new IntegerPredicate(Even)); Int[] greaterTh...
Inference int[] ints = new int[] {1, 2, 3, 4, 5 }; int[] even = Filter(ints, Even); Int[] greaterThanThree = Filter(ints, ...
Generics delegate bool IntegerPredicate(int value);
Generics delegate bool Predicate<T> (T value);
Generics int[] Filter(int[] ints, IntegerPredicate predicate) { ArrayList results = new ArrayList(); foreach (int i in int...
Generics T[] Filter<T>(T[] values, Predicate<T> predicate) { List<T> results = new List<T>(); foreach (T i in value) { if ...
Generics IEnumerable<T> Filter<T>(IEnumerable<T> values,  Predicate<T> predicate) { List<T> results = new List<T>(); forea...
Iterators IEnumerable<T> Filter<T>(IEnumerable<T> values,  Predicate<T> predicate) { List<T> results = new List<T>(); fore...
Iterators IEnumerable<T> Filter<T>(IEnumerable<T> values,  Predicate<T> predicate) { foreach (T i in value) { if (predicat...
Anonymous Methods IEnumerable<int> greaterThanThree = Filter(ints, GreaterThanThree);
Anonymous Methods IEnumerable<int> greaterThanThree = Filter(ints,  delegate(int value) { return value > 3; });
Anonymous Methods int minimumValue = 3; IEnumerable<int> greaterThanThree = Filter(ints,  delegate(int value) { return val...
C# 3.0  
Lambdas int minimumValue = 3; IEnumerable<int> greaterThanThree = Filter(ints,  delegate(int value) { return value > minim...
Lambdas int minimumValue = 3; IEnumerable<int> greaterThanThree = Filter(ints,  value => value > minimumValue);
More Type Inference int minimumValue = 3; IEnumerable<int> greaterThanThree = Filter(ints,  value => value > minimumValue);
More Type Inference int minimumValue = 3; var greaterThanThree = Filter(ints, value => value > minimumValue);
Extension Methods int minimumValue = 3; var greaterThanThree = Filter(ints, value => value > minimumValue);
Extension Methods int minimumValue = 3; var greaterThanThree = ints.Filter(value => value > minimumValue);
Anonymous Types var anonymous = new { Foo = 1, Bar = “Bar” }
LINQ
LINQ New delegates in System namespace Action<T>, Action<T1, T2>, Func<TResult>, Func<T1, TResult> etc.
LINQ New delegates in System namespace Action<T>, Action<T1, T2>, Func<TResult>, Func<T1, TResult> etc. System.Linq Extens...
LINQ New delegates in System namespace Action<T>, Action<T1, T2>, Func<TResult>, Func<T1, TResult> etc. System.Linq Extens...
LINQ var even = ints.Where(value => value % 2 == 0)   var greaterThanThree = ints.Where(value => value > minimumValue)   o...
A (little) bit of theory
http://www.flickr.com/photos/stuartpilbrow/2938100285/sizes/l/
Higher order functions
Immutability
Lazy evaluation
Recursion & Pattern Matching
Transformational Mindset We can just pass functions around instead in most cases - find an example where it still makes se...
Input  -> ??? -> ??? -> ??? ->  Output
http://www.emt-india.net/process/petrochemical/img/pp4.jpg
So why should you care?
Functional can fill in the gaps in OO code  
Abstractions over common operations means less code and less chances to make mistakes
So what do we get out of the box?
Projection
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>  people.Select(person => person.Name) </li></ul><ul><li>  </li></ul><ul...
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.SelectMany(person => person.Pets)  </li></ul>
Restriction  
  <ul><li>         </li></ul><ul><li>  </li></ul><ul><li>people.Where(person => person.HasPets) </li></ul><ul><li>  </li><...
Partitioning  
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Take(5) </li></ul>
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Skip(5) </li></ul>
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>             people.TakeWhile(person =>  </li></ul><ul><li>             ...
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>             people.SkipWhile(person =>  </li></ul><ul><li>             ...
Set  
  <ul><li>people.Select(person => person.Name) </li></ul><ul><li>.Distinct()  </li></ul>
  <ul><li>  people.Union(someOtherPeople) </li></ul><ul><li>  </li></ul>
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Intersect(someOtherPeople) </li></ul>
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Except(someOtherPeople) </li></ul>
Ordering and Grouping  
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.OrderBy(person => person.Name) </li></ul><ul><li>  </li></ul><ul>...
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.GroupBy(person => person.Name) </li></ul>
Aggregation  
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Count() </li></ul>
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Select(person => person.Age) </li></ul><ul><li>.Sum() </li></ul>
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Select(person => person.Age) </li></ul><ul><li>.Min() </li></ul>
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Select(person => person.Age) </li></ul><ul><li>.Max() </li></ul>
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Select(person => person.Age) </li></ul><ul><li>.Average() </li></ul>
  <ul><li>Things can get more complex </li></ul>
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>        people.Select(person => person.Age) </li></ul><ul><li>          ...
  <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>         people.Join(addresses,            </li></ul><ul><li>           ...
We can just pass functions around instead in most cases - find an example where it still makes sense to use the GOF approa...
 
  <ul><li>  </li></ul>public class SomeObject {  private readonly IStrategy strategy; public SomeObject(IStrategy strategy...
  <ul><li>  </li></ul>public class Strategy : IStrategy {  public void DoSomething(string value) { // do something with st...
  <ul><li>  </li></ul>public class SomeObject {  private readonly Action<string> strategy; public SomeObject(Action<string...
  <ul><li>Hole in the middle pattern </li></ul>
  <ul><li>  </li></ul>public class ServiceCache<Service> {  protected Res FromCacheOrService            <Req, Res>(Func<Re...
  <ul><li>  </li></ul>public class CachedService : ServiceCache<IService> {  public MyResult GetMyResult(MyRequest request...
  <ul><li>Passing functions around </li></ul>
<ul><li>  </li></ul>private void AddErrorIf<T>(Expression<Func<T>> fn,    ModelStateDictionary modelState,    Func<ModelSt...
  <ul><li>Continuation Passing Style </li></ul>
<ul><li>  </li></ul>static void Identity<T>(T value, Action<T> k)  {  k(value);  }
<ul><li>  </li></ul>Identity(&quot;foo&quot;, s => Console.WriteLine(s));
<ul><li>  </li></ul>Identity(&quot;foo&quot;, s => Console.WriteLine(s));  as compared to var foo = Identity(“foo”); Conso...
<ul><li>  </li></ul>public ActionResult Submit(string id, FormCollection form) {     var shoppingBasket = CreateShoppingBa...
<ul><li>  </li></ul>private RedirectToRouteResult IsValid(ShoppingBasket shoppingBasket,                                  ...
<ul><li>  </li></ul>http://www.thegeekshowpodcast.com/home/mastashake/thegeekshowpodcast.com/wp-content/uploads/2009/07/wt...
So what could possibly go wrong?   http://icanhascheezburger.files.wordpress.com/2009/06/funny-pictures-cat-does-not-think...
Hard to diagnose errors  
var people = new []  {  new Person { Id=1, Address = new Address { Road = &quot;Ewloe Road&quot; }},   new Person { Id=2},...
Null Reference Exception on line 23
http://www.flickr.com/photos/29599641@N04/3147972713/
public T Tap(T t, Action action)  {     action();     return t; }
people     .Select(p => Tap(p, logger.debug(p.Id))     .Select(p => p.Address.Road); 
Readability  
Lazy evaluation can have unexpected consequences  
  <ul><li>         IEnumerable<string> ReadNamesFromFile()         {             using(var fileStream = new FileStream(&qu...
  <ul><li>         IEnumerable<Person> GetPeople()         {             return ReadNamesFromFile() </li></ul><ul><li>    ...
  <ul><li>      IEnumerable<Person> people = GetPeople();           foreach (var person in people)      {          Console...
Encapsulation is still important  
  <ul><li>Total salary for a company </li></ul><ul><li>  </li></ul><ul><li>company.Employees.Select(employee => </li></ul>...
Linq isn't the problem here, it's where we have put it  
Company naturally has the responsibility so encapsulate the logic here
<ul><li>class Company </li></ul><ul><li>{ </li></ul><ul><li>     public int TotalSalary </li></ul><ul><li>     { </li></ul...
Sometimes we need to go further  
If both Company and Division have employees do we duplicate the logic for total salary?
IEnumerable<T> and List<T> make collections easy but sometimes it is still better to create a class to represent a collect...
  <ul><li>class EmployeeCollection </li></ul><ul><li>{ </li></ul><ul><li>     private List<Employee> employees;  </li></ul...
In conclusion…  
 
Mike Wagg mikewagg.blogspot.com [email_address] Mark Needham markhneedham.com [email_address]
Upcoming SlideShare
Loading in …5
×

Mixing Functional and Object Oriented Approaches to Programming in C#

1,424
-1

Published on

Mixing Functional and Object Oriented Approaches to Programming in C#, Michael Wagg, Mark Needham

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
1,424
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • Lazy evaluation
  • Go faster!!!
  • origins of functional programming are found in lambda calculation/maths
  • functions that take in a function or return a function. Need to have first class functions in the language to do that. We have that with all the LINQ methods - select, where, and so on.
  • the whole premise of functional programming with side effect free functions assumes that we have immutable data. We can&apos;t achieve this idiomatically in C# because the language isn&apos;t really designed for it. I want to put an example of how immutability is easy in F#, can that go in this section?
  • iterators in C# do this with yield keyword It&apos;s not necessary to have lazy evaluation to be functional but it&apos;s a characteristic of some functional languages.
  • seems quite obvious but the most extreme guideline to follow is that we shouldn&apos;t need to store anything in variables. Look at the data as a whole if we don&apos;t store any intermediate values then we truly do have some data that we are passing through different filters and applying some transformation
  • it&apos;s quite like the pipes and filters architectural pattern in fact. This is the way that we can combine functions on the unix command line.
  • what is CPS?   is where we pass in a function that represents the rest of the program which will be called with the result of another function.
  • what is CPS?   is where we pass in a function that represents the rest of the program which will be called with the result of another function.
  • what is CPS?   is where we pass in a function that represents the rest of the program which will be called with the result of another function.
  • the idea is that the rest of the program is contained in the continuation so we don&apos;t need to come back to the call site.
  • the idea is that the rest of the program is contained in the continuation so we don&apos;t need to come back to the call site.
  • the idea is that the rest of the program is contained in the continuation so we don&apos;t need to come back to the call site.
  • Encapsulates the state but over complicates the program flow perhaps
  • Encapsulates the state but over complicates the program flow perhaps
  • Mixing Functional and Object Oriented Approaches to Programming in C#

    1. 1. Mixing Functional and Object Oriented approaches to programming in C# Mike Wagg & Mark Needham
    2. 2. C# 1.0
    3. 3. http://www.impawards.com/2003/posters/back_in_the_day.jpg
    4. 4. int[] ints = new int[] {1, 2, 3, 4, 5}  
    5. 5. int[] Filter(int[] ints) {     ArrayList results = new ArrayList();     foreach (int i in ints)     { if (i % 2 == 0) { results.Add(i); }     }     return results.ToArray(typeof(int)); }
    6. 6. int[] ints = new int[] {1, 2, 3, 4, 5}  
    7. 7. int[] Filter(int[] ints) {     ArrayList results = new ArrayList();     foreach (int i in ints)     { if (i >3) { results.Add(i); }     }     return results.ToArray(typeof(int)); }
    8. 8. int[] Filter(int[] ints) {     ArrayList results = new ArrayList();     foreach (int i in ints)     { if ( i % 2 == 0 ) { results.Add(i); }     }     return results.ToArray(typeof(int)); }
    9. 9. int[] Filter(int[] ints) {     ArrayList results = new ArrayList();     foreach (int i in ints)     { if ( i > 3 ) { results.Add(i); }     }     return results.ToArray(typeof(int)); }
    10. 10. interface IIntegerPredicate { bool Matches(int value); }
    11. 11. class EvenPredicate : IIntegerPredicate { bool Matches(int value) { return value % 2 == 0; } }
    12. 12. class GreaterThanThreePredicate : IIntegerPredicate { bool Matches(int value) { return value > 3; } }
    13. 13. int[] Filter(int[] ints, IIntegerPredicate predicate) {     ArrayList results = new ArrayList();     foreach (int i in ints)     { if (predicate.Matches(i)) { results.Add(i); }     }     return results.ToArray(typeof(int)); }
    14. 14. int[] ints = new int[] {1, 2, 3, 4, 5 }; int[] even = Filter(ints, new EvenPredicate()); int[] greaterThanThree = Filter(ints, new GreaterThanThreePredicate());
    15. 15. interface IIntegerPredicate { bool Matches(int value); }
    16. 16. bool delegate IntegerPredicate(int value);
    17. 17. bool Even(int value) { return value % 2 == 0; }
    18. 18. bool GreaterThanThree(int value) { return value > 3; }
    19. 19. int[] Filter(int[] ints, IntegerPredicate predicate) {     ArrayList results = new ArrayList();     foreach (int i in ints)     {                 if (predicate(i)) { results.Add(i); }     }     return results.ToArray(typeof(int)); }
    20. 20. int[] ints = new int[] {1, 2, 3, 4, 5 }; int[] even = Filter(ints,  new IntegerPredicate(Even)); Int[] greaterThanThree = Filter(ints,  new IntegerPredicate(GreaterThanThree));
    21. 21. C# 2.0  
    22. 22. Inference int[] ints = new int[] {1, 2, 3, 4, 5 }; int[] even = Filter(ints,  new IntegerPredicate(Even)); Int[] greaterThanThree = Filter(ints,  new IntegerPredicate(GreaterThanThree));
    23. 23. Inference int[] ints = new int[] {1, 2, 3, 4, 5 }; int[] even = Filter(ints, Even); Int[] greaterThanThree = Filter(ints, GreaterThanThree); The compiler can infer what the type of the delegate is so we don’t have to write it.
    24. 24. Generics delegate bool IntegerPredicate(int value);
    25. 25. Generics delegate bool Predicate<T> (T value);
    26. 26. Generics int[] Filter(int[] ints, IntegerPredicate predicate) { ArrayList results = new ArrayList(); foreach (int i in ints) { if (predicate(i)) { results.Add(i); } } return results.ToArray(typeof(int)); }
    27. 27. Generics T[] Filter<T>(T[] values, Predicate<T> predicate) { List<T> results = new List<T>(); foreach (T i in value) { if (predicate(i)) { results.Add(i); } } return results.ToArray(); }
    28. 28. Generics IEnumerable<T> Filter<T>(IEnumerable<T> values, Predicate<T> predicate) { List<T> results = new List<T>(); foreach (T i in value) { if (predicate(i)) { results.Add(i); } } return results; }
    29. 29. Iterators IEnumerable<T> Filter<T>(IEnumerable<T> values, Predicate<T> predicate) { List<T> results = new List<T>(); foreach (T i in value) { if (predicate(i)) { results.Add(i); } } return results; }
    30. 30. Iterators IEnumerable<T> Filter<T>(IEnumerable<T> values, Predicate<T> predicate) { foreach (T i in value) { if (predicate(i)) { yield return i; } } }
    31. 31. Anonymous Methods IEnumerable<int> greaterThanThree = Filter(ints, GreaterThanThree);
    32. 32. Anonymous Methods IEnumerable<int> greaterThanThree = Filter(ints, delegate(int value) { return value > 3; });
    33. 33. Anonymous Methods int minimumValue = 3; IEnumerable<int> greaterThanThree = Filter(ints, delegate(int value) { return value > minimumValue; }); Anonymous methods add support for closures. The delegate captures the scope it was defined in.
    34. 34. C# 3.0  
    35. 35. Lambdas int minimumValue = 3; IEnumerable<int> greaterThanThree = Filter(ints, delegate(int value) { return value > minimumValue; });
    36. 36. Lambdas int minimumValue = 3; IEnumerable<int> greaterThanThree = Filter(ints, value => value > minimumValue);
    37. 37. More Type Inference int minimumValue = 3; IEnumerable<int> greaterThanThree = Filter(ints, value => value > minimumValue);
    38. 38. More Type Inference int minimumValue = 3; var greaterThanThree = Filter(ints, value => value > minimumValue);
    39. 39. Extension Methods int minimumValue = 3; var greaterThanThree = Filter(ints, value => value > minimumValue);
    40. 40. Extension Methods int minimumValue = 3; var greaterThanThree = ints.Filter(value => value > minimumValue);
    41. 41. Anonymous Types var anonymous = new { Foo = 1, Bar = “Bar” }
    42. 42. LINQ
    43. 43. LINQ New delegates in System namespace Action<T>, Action<T1, T2>, Func<TResult>, Func<T1, TResult> etc.
    44. 44. LINQ New delegates in System namespace Action<T>, Action<T1, T2>, Func<TResult>, Func<T1, TResult> etc. System.Linq Extension methods Where, Select, OrderBy etc.
    45. 45. LINQ New delegates in System namespace Action<T>, Action<T1, T2>, Func<TResult>, Func<T1, TResult> etc. System.Linq Extension methods Where, Select, OrderBy etc.   Some compiler magic to translate sql style code to method calls
    46. 46. LINQ var even = ints.Where(value => value % 2 == 0)   var greaterThanThree = ints.Where(value => value > minimumValue)   or var even = from value in ints                   where value % 2 == 0                   select value   var greaterThanThree = from value in ints                                         where value > minimumValue                                                   select value                                       
    47. 47. A (little) bit of theory
    48. 48. http://www.flickr.com/photos/stuartpilbrow/2938100285/sizes/l/
    49. 49. Higher order functions
    50. 50. Immutability
    51. 51. Lazy evaluation
    52. 52. Recursion & Pattern Matching
    53. 53. Transformational Mindset We can just pass functions around instead in most cases - find an example where it still makes sense to use the GOF approach though.
    54. 54. Input -> ??? -> ??? -> ??? ->  Output
    55. 55. http://www.emt-india.net/process/petrochemical/img/pp4.jpg
    56. 56. So why should you care?
    57. 57. Functional can fill in the gaps in OO code  
    58. 58. Abstractions over common operations means less code and less chances to make mistakes
    59. 59. So what do we get out of the box?
    60. 60. Projection
    61. 61.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>  people.Select(person => person.Name) </li></ul><ul><li>  </li></ul><ul><li>  </li></ul>
    62. 62.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.SelectMany(person => person.Pets) </li></ul>
    63. 63. Restriction  
    64. 64.   <ul><li>         </li></ul><ul><li>  </li></ul><ul><li>people.Where(person => person.HasPets) </li></ul><ul><li>  </li></ul>
    65. 65. Partitioning  
    66. 66.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Take(5) </li></ul>
    67. 67.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Skip(5) </li></ul>
    68. 68.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>             people.TakeWhile(person =>  </li></ul><ul><li>                             person.Name != &quot;David&quot;) </li></ul>
    69. 69.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>             people.SkipWhile(person =>  </li></ul><ul><li>                                 person.Name != &quot;David&quot;) </li></ul>
    70. 70. Set  
    71. 71.   <ul><li>people.Select(person => person.Name) </li></ul><ul><li>.Distinct() </li></ul>
    72. 72.   <ul><li>  people.Union(someOtherPeople) </li></ul><ul><li>  </li></ul>
    73. 73.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Intersect(someOtherPeople) </li></ul>
    74. 74.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Except(someOtherPeople) </li></ul>
    75. 75. Ordering and Grouping  
    76. 76.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.OrderBy(person => person.Name) </li></ul><ul><li>  </li></ul><ul><li>  </li></ul>
    77. 77.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.GroupBy(person => person.Name) </li></ul>
    78. 78. Aggregation  
    79. 79.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Count() </li></ul>
    80. 80.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Select(person => person.Age) </li></ul><ul><li>.Sum() </li></ul>
    81. 81.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Select(person => person.Age) </li></ul><ul><li>.Min() </li></ul>
    82. 82.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Select(person => person.Age) </li></ul><ul><li>.Max() </li></ul>
    83. 83.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>people.Select(person => person.Age) </li></ul><ul><li>.Average() </li></ul>
    84. 84.   <ul><li>Things can get more complex </li></ul>
    85. 85.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>       people.Select(person => person.Age) </li></ul><ul><li>             .Aggregate(0, (totalAge, nextAge) =>  </li></ul><ul><li>                     nextAge % 2 == 0  </li></ul><ul><li>                         ? nextAge + totalAge  </li></ul><ul><li>                         : totalAge) </li></ul>
    86. 86.   <ul><li>  </li></ul><ul><li>  </li></ul><ul><li>        people.Join(addresses,           </li></ul><ul><li>                person => person.PersonId,   </li></ul><ul><li>                 address => address.PersonId,      </li></ul><ul><li>                (person, address) => new {  </li></ul><ul><li>                                         person, address}) </li></ul>
    87. 87. We can just pass functions around instead in most cases - find an example where it still makes sense to use the GOF approach though.
    88. 89.   <ul><li>  </li></ul>public class SomeObject { private readonly IStrategy strategy; public SomeObject(IStrategy strategy) { this.strategy = strategy; } public void DoSomething(string value) { strategy.DoSomething(value); } }
    89. 90.   <ul><li>  </li></ul>public class Strategy : IStrategy { public void DoSomething(string value) { // do something with string } }
    90. 91.   <ul><li>  </li></ul>public class SomeObject { private readonly Action<string> strategy; public SomeObject(Action<string> strategy) { this.strategy = strategy; } public void DoSomething(string value) { strategy(value); } }
    91. 92.   <ul><li>Hole in the middle pattern </li></ul>
    92. 93.   <ul><li>  </li></ul>public class ServiceCache<Service> { protected Res FromCacheOrService            <Req, Res>(Func<Res> serviceCall, Req request) {      var cachedRes = cache.RetrieveIfExists( typeof(Service), typeof(Res), request);   if(cachedRes == null)   { cachedRes = serviceCall(); cache.Add(typeof(Service), request, cachedRes); }      return (Res) cachedRes; } }
    93. 94.   <ul><li>  </li></ul>public class CachedService : ServiceCache<IService> { public MyResult GetMyResult(MyRequest request) {           return FromCacheOrService(()                   => service.GetMyResult(request), request); } }
    94. 95.   <ul><li>Passing functions around </li></ul>
    95. 96. <ul><li>  </li></ul>private void AddErrorIf<T>(Expression<Func<T>> fn, ModelStateDictionary modelState, Func<ModelStateDictionary, Func<T,string, string, bool>> checkFn) { var fieldName = ((MemberExpression)fn.Body).Member.Name; var value = fn.Compile().Invoke(); var validationMessage = validationMessages[fieldName]); checkFn.Invoke(modelState)(value, fieldName, validationMessage); } AddErrorIf(() => person.HasPets, modelState, m => (value, field, error) => m.AddErrorIfNotEqualTo(value,true, field, error)); AddErrorIf(() => person.HasChildren, modelState, m => (value, field, error) => m.AddErrorIfNull(value, field, error));
    96. 97.   <ul><li>Continuation Passing Style </li></ul>
    97. 98. <ul><li>  </li></ul>static void Identity<T>(T value, Action<T> k) { k(value); }
    98. 99. <ul><li>  </li></ul>Identity(&quot;foo&quot;, s => Console.WriteLine(s));
    99. 100. <ul><li>  </li></ul>Identity(&quot;foo&quot;, s => Console.WriteLine(s)); as compared to var foo = Identity(“foo”); Console.WriteLine(foo);
    100. 101. <ul><li>  </li></ul>public ActionResult Submit(string id, FormCollection form) {    var shoppingBasket = CreateShoppingBasketFrom(id, form);      return IsValid(shoppingBasket, ModelState,          () => RedirectToAction(&quot;index&quot;, &quot;ShoppingBasket&quot;, new { shoppingBasket.Id} ),   () => LoginUser(shoppingBasket,                  () =>                  {                    ModelState.AddModelError(&quot;Password&quot;, &quot;User name/email address was incorrect - please re-enter&quot;);                      return RedirectToAction(&quot;index&quot;, &quot;&quot;ShoppingBasket&quot;, new { Id = new Guid(id) });                 }, user =>                  {                    shoppingBasket.User = user;                      UpdateShoppingBasket(shoppingBasket);                      return RedirectToAction(&quot;index&quot;, &quot;Purchase&quot;,    new { Id = shoppingBasket.Id }); }         )); }
    101. 102. <ul><li>  </li></ul>private RedirectToRouteResult IsValid(ShoppingBasket shoppingBasket,                                       ModelStateDictionary modelState,                                        Func<RedirectToRouteResult> failureFn,                      Func<RedirectToRouteResult> successFn) {   return validator.IsValid(shoppingBasket, modelState) ? successFn() : failureFn(); }   private RedirectToRouteResult LoginUser(ShoppingBasket shoppingBasket,                                                                  Func<RedirectToRouteResult> failureFn,                                                                Func<User,RedirectToRouteResult> successFn) { User user = null; try { user = userService.CreateAccountOrLogIn(shoppingBasket); }   catch (NoAccountException) { return failureFn(); }   return successFn(user); }
    102. 103. <ul><li>  </li></ul>http://www.thegeekshowpodcast.com/home/mastashake/thegeekshowpodcast.com/wp-content/uploads/2009/07/wtf-cat.jpg
    103. 104. So what could possibly go wrong?   http://icanhascheezburger.files.wordpress.com/2009/06/funny-pictures-cat-does-not-think-plan-will-fail.jpg
    104. 105. Hard to diagnose errors  
    105. 106. var people = new [] { new Person { Id=1, Address = new Address { Road = &quot;Ewloe Road&quot; }}, new Person { Id=2}, new Person { Id=3, Address = new Address { Road = &quot;London Road&quot;}} }; people.Select(p => p.Address.Road); 
    106. 107. Null Reference Exception on line 23
    107. 108. http://www.flickr.com/photos/29599641@N04/3147972713/
    108. 109. public T Tap(T t, Action action)  {     action();     return t; }
    109. 110. people     .Select(p => Tap(p, logger.debug(p.Id))     .Select(p => p.Address.Road); 
    110. 111. Readability  
    111. 112. Lazy evaluation can have unexpected consequences  
    112. 113.   <ul><li>        IEnumerable<string> ReadNamesFromFile()         {             using(var fileStream = new FileStream(&quot;names.txt&quot;, </li></ul><ul><li>                                                         FileMode.Open))             using(var reader = new StreamReader(fileStream))             {                 var nextLine = reader.ReadLine();                 while(nextLine != null)                 {                     yield return nextLine;                     nextLine = reader.ReadLine();                 }             }         } </li></ul>
    113. 114.   <ul><li>        IEnumerable<Person> GetPeople()         {             return ReadNamesFromFile() </li></ul><ul><li>                     .Select(name => new Person(name));         } </li></ul>
    114. 115.   <ul><li>      IEnumerable<Person> people = GetPeople();           foreach (var person in people)      {          Console.WriteLine(person.Name);      }       </li></ul><ul><li>     Console.WriteLine(&quot;Total number of people: &quot; + </li></ul><ul><li>                                     people.Count()); </li></ul>
    115. 116. Encapsulation is still important  
    116. 117.   <ul><li>Total salary for a company </li></ul><ul><li>  </li></ul><ul><li>company.Employees.Select(employee => </li></ul><ul><li>                                             employee.Salary)  </li></ul><ul><li>                                 .Sum() </li></ul><ul><li>This could lead to duplication </li></ul><ul><li>What if we add rules to the calculation? </li></ul><ul><li>Who should really have this responsibility? </li></ul><ul><li>.Sum() </li></ul>
    117. 118. Linq isn't the problem here, it's where we have put it  
    118. 119. Company naturally has the responsibility so encapsulate the logic here
    119. 120. <ul><li>class Company </li></ul><ul><li>{ </li></ul><ul><li>    public int TotalSalary </li></ul><ul><li>    { </li></ul><ul><li>        get  </li></ul><ul><li>        { </li></ul><ul><li>            return employees.Select(e => </li></ul><ul><li>                                     e.Salary).Sum(); </li></ul><ul><li>        } </li></ul><ul><li>    } </li></ul><ul><li>} </li></ul>
    120. 121. Sometimes we need to go further  
    121. 122. If both Company and Division have employees do we duplicate the logic for total salary?
    122. 123. IEnumerable<T> and List<T> make collections easy but sometimes it is still better to create a class to represent a collection
    123. 124.   <ul><li>class EmployeeCollection </li></ul><ul><li>{ </li></ul><ul><li>    private List<Employee> employees; </li></ul><ul><li>  </li></ul><ul><li>     public int TotalSalary </li></ul><ul><li>    { </li></ul><ul><li>        get </li></ul><ul><li>         { </li></ul><ul><li>            return employees.Select(e => e.Salary).Sum(); </li></ul><ul><li>         } </li></ul><ul><li>    } </li></ul><ul><li>} </li></ul>
    124. 125. In conclusion…  
    125. 126.  
    126. 127. Mike Wagg mikewagg.blogspot.com [email_address] Mark Needham markhneedham.com [email_address]

    ×