Refactoring to functional

http://www.higherorderlogic.com/refactoring-to-functional.zip

Refactoring to
functional

Steve Freeman @sf105

Julian Kelsey @scrawlings, Andy Parker @aparker42

Requires access to a laptop with Java 1.6+ and a refactoring IDE

Today

  • What? Why?
  • Quick tour of Guava
  • Practice on some exercises
  • Discuss/Questions
  • Try out a larger problem
  • Wrap up

Functional programming?

  • Stateless
  • Immutable
val a = doubled(b)
  
val doubledCounts = eachDoubled(counts)

First class functions

  • Unit of behaviour
  • Higher-order programming
val plusOne = lambda x: x + 1
  
val incremented = applied(count, plusOne)
def applied(value, oneArgFunction):
  return oneArgFunction(value)

Lots of collections

  • Filters, mapping, etc.
  • Return a copy
  • Might be lazy
val backwards = reversed(forwards)
  
val incremented = map(counts, plusOne)
val shouty = map(inputStream, inUpperCase)
incremented = [x + 1 for x in counts]

Collection manipulation

  • Convert a collection to a different shape
  • concat(), reduce(), split(), index()
  • Some can't be lazy
val plusThenMinus = concat(
  filter(values, isPositive),
  filter(values, isNegative))

val total = reduce(values, 0, add)
val idToAccount =
  uniqueIndex(accounts, account => account.id)
  

Why functional?

  • Separation of concerns
  • Higher-level coding
  • Stateless is safer
val allPostiveRecordsAreValid =
  all(filter(records, isPositive), isValid)
  records select (r => r.value > 0)
          all (r => r.isValid)
  all([r.isValid for r in records
                       if r.value > 0])

What will be different?

  • Lots of “noise” underneath to make the magic happen
  • Name results rather than actions
  • Radically small components
daily = values.getConvertedToDaily()
daily = values asDailyResults
def sum(values):
  return reduce(values, 0, adder)

In the real world

  • Flush out mutability
  • Takes time to learn to see
  • Learn a proper functional language
  • OO outside and functional inside

In the real world (Java)

  • Guava changes the game
  • – or other tools that manipulate bytecode
  • Excessive amounts of boiler-plate and “<>”
  • – lots of helper methods
  • – compact code formatting
  • Sometimes Java just isn't Haskell
  • – watch out for lazy functions that aren't
  • Jam tomorrow (Java 8)

Quick intro to Guava

  • Google collections library
  • Iterator-based
  • Lazy (kinda)

Function<I,O>

  • Convert from one thing to another
Function<Integer, String> asString
  = new Function<Integer, String>() {
      public String apply(Integer input) {
        return String.valueOf(input);
      }
    };
assertEquals("123", asString.apply(123));

Predicate<T>

  • Check a condition on a value
Predicate<String> isBlank 
  = new Predicate<String>() {
      public boolean apply(String input) {
        return input.matches("\\s*");
      }
    };

assertFalse(isBlank.apply("Some Input")); 
assertTrue(isBlank.apply("  "));

transform()

  • Equivalent of map() in other systems
Iterable<O> transform(Iterable<I>, Function<I, O>)
Iterable<Integer> numbers = asList(1, 2, 3);

Iterable<String> strings =
    Iterables.transform(numbers, asString);
  
assertThat(strings, contains("1", "2", "3"));

filter()

  • Selects items from an Iterable
Iterable<T> filter(Iterable<T>, Predicate<T>)
List<Integer> strings =
    asList("a", " ", "c", "  ");

Iterable<String> blanks = 
    Iterables.filter(strings, isBlank);
  
assertThat(blanks, contains(" ", "  "));

Boolean queries

  • Whether items match a predicate
boolean all(Iterable<T>, Predicate<T>)
boolean any(Iterable<T>, Predicate<T>)
assertTrue(
  Iterables.all(asList(" ", "  "), isBlank));
assertFalse(all(asList("s", " "), isBlank));

assertTrue(
  Iterables.any(asList("a", " "), isBlank));
assertFalse(any(asList("a", "b"), isBlank));
    

reduce()

  • Accumulate a result across a collection
  • We've provided one in RtfIterables
    (not in Guava)
R reduce(Iterable<I>, R, Function<I, R>)
assertThat(
    reduce(asList(1, 2, 3), 0, addition),
    equalTo(6));
assertThat(
    reduce(asList(1, 2, 3), 10, subtraction),
    equalTo(4));




Your Privacy

By clicking "Accept Non-Essential Cookies" you agree ACCU can store non-essential cookies on your device and disclose information in accordance with our Privacy Policy and Cookie Policy.

Current Setting: Non-Essential Cookies REJECTED


By clicking "Include Third Party Content" you agree ACCU can forward your IP address to third-party sites (such as YouTube) to enhance the information presented on this site, and that third-party sites may store cookies on your device.

Current Setting: Third Party Content EXCLUDED



Settings can be changed at any time from the Cookie Policy page.