functional principles for object-oriented
Imperative Procedural Object-Oriented Functional Aspect-Oriented Logic
Data In, Data Out Immutability Verbs Are People Too Declarative Style Specific Typing Lazy Evaluation
What is it? Principle What is it? We already do it What’s the point? What is it? Scala / F# Java / C#
Data In, Data Out
access global state modify input change the world
Data In -> ? -> Data out input output
Testable Easier to understand
the flow of data
List List > List
Problem easier, because we know each step of the way of data.
public string CreateAccount(UserDbService db, String , String password) { … }
String password; String ; private boolean invalidPassword() { return !password.contains( ); }
private boolean invalidPassword(String password, String ) { return !password.contains( ); }
Immutability
modify anything
Concurrency fewer possibilities
NPE
c c
String Effective Java Effective C#
Scala val qty = 4 // immutable var n = 2 // mutable
let qty = 4 // immutable let mutable n = 2 // mutable n = 4 // false n <- 4 // destructive update F#
C#: easy public struct Address { private readonly string city; public Address(string city) : this() { this.city = city; } public string City { get { return city; } }
Java: defensive copy private final ImmutableList phones; public Customer (Iterable phones) { this.phones = ImmutableList.copyOf(phones); }
Java: copy on mod public Customer addPhone(Phone newPhone) { Iterable morePhones = ImmutableList.builder().addAll(phones).add(newPhone).build(); return new Customer(morePhones); }
fruit fruit.add(tomato)
F#: copy on mod member this.AddPhone (newPhone : Phone) { new Customer(newPhone :: phones) }
C#: shallow copy public Customer AddPhone(Phone newPhone) { IEnumerable morePhones = // create list return new Customer(morePhones, name, address, birthday, cousins); }
this talk is brought to you by… the Option type! NPE Thing doStuff() NullThing doStuff() {} SomeThing doStuff() {…} Option None Some
… because null is not a valid object reference. Optional FSharpOption
Verbs Are People Too
Imperative Procedural Object-Oriented Functional Aspect-Oriented Logic !=
Strategy Command OnClick() release ( )
class CostInflation implements FunctionOverTime { public float valueAt(int t) { return // some calculated value; } Java
val costInflation = Variable ( “Cost Inflation”, t => Math.pow(1.15,t)) val seasonalVolume = Array(0.95,0.99,1.01,…) val seasonalAdjustment = Variable(“Season”, t => seasonalVolume(t)) Scala
C# private readonly Func calc; public Func ValueAt { get { return calc; } }
C# var inflation = new Variable(“Inflation”, t => Math.Pow(1.15,t)); inflation.ValueAt(3);
Java Variable inflation = new Variable (“Inflation”, new Function () public Double apply(Integer input) { return Math.pow(1.15, input); } });
Java 8 Variable inflation = new Variable (“Inflation”, t => Math.pow(1.15, t) );
Declarative Style
say what you’re doing, not how you’re doing it
Select ROLE_NAME, UPDATE_DATE From USER_ROLES Where USER_ID = :userId
smaller pieces readable code
familiar != readable
Java public List findBugReports(List lines) { List output = new LinkedList(); for(String s : lines) { if(s.startsWith(“BUG”)) { output.add(s); } return output; }
Scala lines.filter( _.startsWith(“BUG”)) lines.par.filter( _.startsWith(“BUG”))
Java final Predicate startsWithBug = new Predicate () { public boolean apply(String s) { return s.startsWith("BUG"); } }; filter(list, startsWithBug);
C# lines.Where(s => s.StartsWith(“BUG”)).ToList
this talk is brought to you by… the Tuple type! function new Tuple (“You win!”, )
When one return value is not enough! Tuple
Specific Typing
expressiveness catch errors early
The beginning of wisdom is to call things by their right names.
F# [ ] type cents let price = 599
Scala type FirstName = String // type alias Customer(name : FirstName, home : Address)
Scala case class FirstName(value : String) let friend = FirstName(“Ivana”);
Java public User(FirstName name, Address login) public class FirstName { public final String stringValue; public FirstName(final String value) { this.stringValue = value; } public String toString() {...} public boolean equals() {...} public int hashCode() {...} }
State everything you need State only what you need
Scala List [+A] def indexOf [B >: A] (elem: B): IntInt def sameElements (that: GenIterable[A]): BooleanIterable[A]
C#: weak public boolean Valid(Customer cust) { Address = cust. Address; // exercise business logic return true; }
C#: weak public boolean Valid(IHas Address anything) { Address = anything. Address; // exercise business logic return true; } interface IHas Address { string Address {get; } }
Lazy Evaluation
delay evaluation until the last responsible moment
save work separate “what to do” from “when to stop”
int bugCount = 0; String nextLine = file.readLine(); while (bugCount < 40) { if (nextLine.startsWith("BUG")) { String[] words = nextLine.split(" "); report("Saw "+words[0]+" on "+words[1]); bugCount++; } waitUntilFileHasMoreData(file); nextLine = file.readLine(); } Java
for (String s : FluentIterable.of(new RandomFileIterable(br)).filter(STARTS_WITH_BUG_PREDICATE).transform(TRANSFORM_BUG_FUNCTION).limit(40).asImmutableList()) { report(s); } Java Iterable: laziness is a virtue
C# IEnumerable ReadLines(StreamReader r) { while (true) { WaitUntilFileHasMoreData(r); yield return r.ReadLine(); }
Data In, Data Out Immutability Verbs Are People Too Declarative Style Specific Typing Lazy Evaluation
I promise not to exclude from consideration any idea based on its source, but to consider ideas across schools and heritages in order to find the ones that best suit the current situation.
Man, the living creature, the creating individual, is always more important than any established style or system. – Bruce Jessica Kerr blog.jessitron.com github.com/jessitron/fp4ood