Mixing functional and object oriented approaches to programming in C#

  • View
    2.308

  • Download
    0

Embed Size (px)

DESCRIPTION

A talk I did at DDD8, January 20th 2010.

Text of Mixing functional and object oriented approaches to programming in C#

  • 1.Mixing functional and object oriented approaches to programming in C# Mark Needham

2. A bit of context 3. ThoughtWorks delivery projects 4. Web applications with somewhat complicated domains 5. 5-15 developers on a team 6. Projects running for 6-12 months 7. All this means that we want to write code which is 8. Easy to understand 9. Easy to change 10. Which leads us to what this talk is all about 11. Organisation of code

  • The Lush Landscape of Languages - The ThoughtWorks Anthology
  • Rebecca Parsons

12. How might functional programming help us with that? 13. First class functions 14. A programming language is said to support first class functionsif functions can be created during the execution of a program, stored in data structures, passed as arguments to other functions, and returned as the values of other functions

  • Wikipedia

15. Immutability 16. Lazy evaluation 17. Recursion 18. Pattern matching 19. This is all very cool but 20. Object Oriented design still has its place 21. Encapsulation 22. Abstraction 23. So how do these two paradigms work together? 24. Programming in the small/medium/large

  • http://weblogs.asp.net/podwysocki/archive/2009/12/14/going-hybrid-implementing-a-shopping-cart-in-f.aspx

25. In the largea high level that affects as well as crosscuts multiple classes and functions 26. In the mediuma single API or group of related APIs in such things as classes, interfaces, modules 27. In the smallindividual function/method bodies 28. Large Medium Small 29. Large Medium Small 30. LINQ 31. a.k.a. Functional collection parameters

  • http://billsix.blogspot.com/2008/03/functional-collection-patterns-in-ruby.html

32. powerful abstractions over collections 33. the use of high-order functions isextremely useful for separating the collection's concerns from the user of the collection 34. for loop becomes less useful 35. Dont just use ForEach! 36. Code becomes more declarative 37. Declarative? a statement specifies some aspect of the desired answer with no notion of how that answer is to be determined

  • The Lush Landscape of Languages - The ThoughtWorks Anthology
  • Rebecca Parsons

38. Requires a mental shift from imperative thinking 39. Transformational mindset

  • Patrick Logan in the comments section
  • http://www.markhneedham.com/blog/2010/01/20/functional-collectional-parameters-some-thoughts/

40. Current Input ??? ??? ??? Desired Output 41. Going from one collection to another 42. varwords =newList{ hello, world }; varupperCaseWords =newList(); foreach(var wordinwords) { upperCaseWords.Add(word.ToUpper()); } 43. a.k.a. map 44. hello, world ???? HELLO, WORLD 45. hello, world Select HELLO, WORLD 46. varwords =newList{ hello, world }; varupperCaseWords =words.Select(w => w.ToUpper()); 47. Remove values we dont want 48. varwords =newList {hello, world}; varwordsWithH =newList(); foreach(var wordinwords) { if(word.Contains(h) wordsWithH.Add(word); } 49. a.k.a. filter 50. hello, world ???? hello 51. hello, world Where hello 52. varwords =newList {hello, world} ; varwordsWithH =words.Where(w => w.Contains(h)); 53. Summing some values 54. varvalues =newList { 1,2,3 }; vartotal =0; foreach(var valueinvalues) { total += value; } 55. a.k.a. reduce 56. 1, 2, 3 ??? 6 57. 1, 2, 3 Sum 6 58. varvalues =newList { 1,2,3 }; vartotal = val ues.Sum(v => v); 59. Some examples from projects 60. Getting the first value that matches a criteria 61. Foo(mark, true), Foo(dave, false), Foo(mike, true) ???? Foo(mark, true) 62. Foo(mark, true), Foo(dave, false), Foo(mike, true) Where Foo(mark, true), Foo(mike, true) ??? Foo(mark, true) 63. Foo(mark, true), Foo(dave, false), Foo(mike, true) Where Foo(mark, true), Foo(mike, true) First Foo(mark, true) 64. varfoos =newList{ new Foo(mark, true),new Foo(dave, false), new Foo(mike, true)}; varfirstSpecialFoo =foos. Where(f => f.HasSpecialFlag()). First()); 65. varfoos =newList{ new Foo(mark, true),new Foo(dave, false), new Foo(mike, true)}; varfirstSpecialFoo =foos.First(f => f.HasSpecialFlag()); 66. Removing some columns from a dataset 67. a,b,c,d,e,f ???? a,d,e,f 68. a,b,c,d,e,f Where IEnumerable of a, d, e, f ??? a,d,e,f 69. a,b,c,d,e,f Where IEnumerable of a, d, e, f ??? String.Joinon [a, d, e, f] a,d,e,f 70. a,b,c,d,e,f Where IEnumerable of a, d, e, f ToArray() String.Joinon [a, d, e, f]a,d,e,f 71. varaRow =a, b, c, d, e, f; varnewRow =String.Join(,, aRow .Split(,) .Where((_, idx) => !(idx == 1 || idx == 2)) .ToArray()); 72. varaRow =a, b, c, d, e, f; varrowWithColumnsRemoved =aRow .Split(,) .Where((_, idx) => !(idx == 1 || idx == 2)) .ToArray());varnewRow = String.Join(,, rowWithColumnsRemoved); 73. Checking if any parameters are null 74. public classSomeObject { publicSomeObject(string p1, string p2,string p3) { if(p1 ==null )throw new Exception(...); if(p2 ==null )throw new Exception(...); if(p3 ==null )throw new Exception(...); // rest of constructor logic } } 75. public classSomeObject { publicSomeObject(string p1, string p2,string p3) { varparams = new List {p1, p2, p3}; if(params.Any(p => p == null)throw new Exception(...);// rest of constructor logic } } 76. Some lessons from the wild 77. Dealing with the null collection 78.

  • public intSumNumbers(List< int > list)
  • {
  • if(list ==null )
  • return 0;
  • return list.Sum(v => v);
  • }

79.

  • publicIEnumerable EmptyIfNull( thisIEnumerable collection)
  • {
  • if(collection ==null )
  • returnnewList();
  • return collection;
  • }

Chris Ammerman in the comments section http://www.markhneedham.com/blog/2009/06/16/functional-collection-parameters-handling-the-null-collection/ 80.

  • public intSumNumbers(List< int > list)
  • {
  • return list.
  • EmptyIfNull().
  • Sum(v => v);
  • }

81. LINQ and the forgotten abstraction 82. Avoid passing lists around 83.

  • public classQuote
  • {
  • publicList Coverages
  • {
  • get; set;
  • }
  • }

84. Later on in the view 85.

  • c.Name == coverageType1) %>
  • ...
  • c.Name == coverageType2) %>
  • ...
  • c.Name == coverageType3) %>

86. Objects as the mechanism for encapsulation 87.

  • public classCoverages
  • {
  • private readonlyList coverages;
  • publicCoverages(List coverages)
  • {
  • this.coverages = new List(coverages);
  • }
  • publicCoverage CoverageType1
  • {
  • get
  • {
  • returncoverages.Where(
  • c => c.Name == coverageType1;
  • }
  • }
  • }

88. LINQ is duplication too! 89.

  • public classCoverages
  • {
  • publicCoverage CoverageType1
  • {
  • get
  • {
  • returncoverages.Where(
  • c => c.Name == coverageType1;
  • }
  • }
  • publicCoverage CoverageType2
  • {
  • get
  • {
  • returncoverages.Where(
  • c => c.Name == coverageType2;
  • }
  • }
  • }

90.

  • public classCoverages
  • {
  • publicCoverage CoverageType1
  • {
  • get {return CoverageByName(coverageType1); }
  • }
  • publicCoverage CoverageType2
  • {
  • get {return CoverageByName(coverageType2); }
  • }
  • publicCoverage CoverageBy(string name)
  • {
  • returncoverages.Where(c => c.Name == name);
  • }
  • }

91. Dont forget extract method 92.

  • varsomeFoos =newList()
  • // put some foos in the list
  • someFoos.Select(f =>newNewFoo
  • {
  • Property1 = f.Property1
  • ...
  • });

93.

  • varsomeFoos =newList()
  • // put some foos in the list
  • someFoos.Select(f => CreateNewFooFrom(f));

94. Naming lambda variables 95. Putting functions in maps 96. public voidSomeMethodParsing( stringinput) { if(input == input1){ someMethod(input); } else if(input == input2) { someOtherMethod(input); } // and so on } 97. Dictionary< string , Action< string >> inputs =new Dictionary< string , Action< string >>{ { input1 , someMethod },{ input2 , someOtherMethod } }; public voidSomeMethodParsing( stringinput) { varmethod = inputs[input]; method(input); } 98. Large Medium Small 99. Using functions to simplify some GOF patterns 100. Action 101. Func 102.

  • public classSomeObject
  • {
  • private readonly IStrategy strategy;
  • public Foo(IStrategy strategy)
  • {
  • this.strategy = strategy;
  • }
  • public void DoSomething(string val