The document discusses concepts from functional programming like immutability, pure functions, and monads and how they are implemented in different programming languages like Haskell, Scala, and Java. It provides definitions for object-oriented programming, functional programming, and describes languages like Haskell, Scala, and Java. It shows examples of implementing immutable data structures, pure functions, and the Option monad in each language. The conclusions are that Java has adapted rather than adopted FP concepts by making types immutable rather than using persistent data structures and using Optional as a monad rather than in its full sense, and this level of adaptation may be limited as FP concepts represent different ways of managing state than object-oriented languages.
3. Object-oriented
Programming
● Model of programming based on entities
(“objects”) which combine state with
behaviour(s)
● Objects correspond to nouns in a system
● Objects interact by invoking methods (verbs) on
objects
● Methods with side effects are quite common
○ State updates
○ Interacting with OS resources
● Objects are often mutable
○ Although immutable objects are not prohibited
● Objects must safely manage concurrent access
to mutable state when multiple objects are at
play
4. Functional
Programming
● “Programming that emphasizes programming
with functions” [1]
● Side effects in functions should be avoided
○ Functions should compute and return a value
based on arguments
○ No statements; everything returns a value
● Values are immutable
● State is a value for a participant in the system
(an “identity”) at some point in time
● Seriously, just watch the video
○ Rich explains it much better than I do!
6. Haskell ● Purely functional
○ No side effects
■ That’s what we have monads for
● Lazy evaluation
○ Values aren’t computed until needed
● Static typing
● Paragon of functional programming
7. Scala ● In a bit of a weird spot here
● Scala is explicitly a multi-paradigm language
○ Intent is to support OOP, FP or both
● Over time a bias has emerged
○ Something like “a gentle nudge” towards:
■ Immutability
■ FP concepts
● Not by any means required
○ Don’t have to use scalaz to use Scala
○ Could happily write imperative code all day long
● Plenty of other benefits
○ Advanced type system
○ Type inference
○ Strong pattern matching
8. Java ● Adamantly object-oriented
○ Everything is an object
■ Well, except primitives…
● Statically typed
● Simpler type system than Scala
● Paragon of OO programming
○ For good and for bad
● An important distinction: “Java” can mean:
○ A programming language
○ The virtual machine it runs on
○ The community and practices surrounding them
● We mostly focus on the language here
○ Although community/practices will figure in
13. Java: And Now We Are Sad
$ ./gradlew test
> Task :compileTestJava FAILED
/home/mersault/git/working/src/test/java/com/datastax/FunctionsTest.java:50: error: method transform in class FluentIterable<E> cannot be applied to given types;
assertEquals(expected, FluentIterable.from(base).transform(foo).toList());
^
required: com.google.common.base.Function<? super String,T>
found: java.util.function.Function<String,String>
reason: cannot infer type-variable(s) T
(argument mismatch; java.util.function.Function<String,String> cannot be converted to com.google.common.base.Function<? super String,T>)
where T,E are type-variables:
T extends Object declared in method <T>transform(com.google.common.base.Function<? super E,T>)
E extends Object declared in class FluentIterable
/home/mersault/git/working/src/test/java/com/datastax/FunctionsTest.java:54: error: method transform in class FluentIterable<E> cannot be applied to given types;
FluentIterable.from(base).transform(baz).toList());
^
required: com.google.common.base.Function<? super String,T>
found: java.util.function.Function<String,String>
reason: cannot infer type-variable(s) T
(argument mismatch; java.util.function.Function<String,String> cannot be converted to com.google.common.base.Function<? super String,T>)
where T,E are type-variables:
T extends Object declared in method <T>transform(com.google.common.base.Function<? super E,T>)
E extends Object declared in class FluentIterable
2 errors
14. Where We Went
Wrong
● Lambdas are implemented as a compile-time
feature
○ Think “pre-processor” if that weren’t such a dirty
notion in some quarters
● If a lambda is used in a context where a
“functional interface” is expected the lambda
will be converted to the type of that “functional
interface”
○ Over time Java has created many types which
are in essence functions (listeners, event
handlers, etc.)
○ Changing all these types to inherit from a
common type would’ve been… painful
● Upshot: once this conversion happens the
lambda is just another instance of that type
○ When we assign the lambda to a variable or
return it from a function we do just that
15. This Is Very Definitely An Improvement
private static class Foo implements com.google.common.base.Function<String, String> {
public String apply(String arg) { return arg.toUpperCase(); }
}
private static com.google.common.base.Function<String, String> bar(String prefix) {
return new com.google.common.base.Function<String, String>() {
public String apply(String arg) { return prefix + arg; }
};
}
@Test
public void testOldSchoolGuava() {
List<String> base = ImmutableList.of("one", "two", "three");
List<String> expected = ImmutableList.of("ONE", "TWO", "THREE");
assertEquals(expected, Lists.transform(base, new Foo()));
com.google.common.base.Function<String, String> baz = bar("hi ");
assertEquals(ImmutableList.of("hi one", "hi two", "hi three"),
Lists.transform(base, baz));
}
17. Haskell: Things Don’t Change
GHCi, version 8.6.3
Prelude> let foo = [1,2,3]
Prelude> let bar = [4,5,6]
Prelude> foo ++ bar
[1,2,3,4,5,6]
Prelude> foo
[1,2,3]
Prelude> let baz = foo ++ bar
Prelude> baz
[1,2,3,4,5,6]
Prelude> foo
[1,2,3]
Prelude> bar
[4,5,6]
18. Haskell: ADTs Don’t Change Either
GHCi, version 8.6.3
Prelude> data OneTwo = OneTwo { one :: Int, two :: String } deriving Show
Prelude> let foo = OneTwo { one = 1, two = "one" }
Prelude> let bar = foo { two = "oops" }
Prelude> foo
OneTwo {one = 1, two = "one"}
Prelude> bar
OneTwo {one = 1, two = "oops"}
19. Scala: This Looks Familiar...
Welcome to Scala 2.11.8 (OpenJDK 64-Bit Server VM, Java 1.8.0_181).
scala> val foo = List(1,2,3)
foo: List[Int] = List(1, 2, 3)
scala> val bar = List(4,5,6)
bar: List[Int] = List(4, 5, 6)
scala> foo ++ bar
res0: List[Int] = List(1, 2, 3, 4, 5, 6)
scala> foo
res1: List[Int] = List(1, 2, 3)
scala> val baz = foo ++ bar
baz: List[Int] = List(1, 2, 3, 4, 5, 6)
scala> baz
res2: List[Int] = List(1, 2, 3, 4, 5, 6)
scala> foo
res3: List[Int] = List(1, 2, 3)
scala> bar
res4: List[Int] = List(4, 5, 6)
20. Java: In The
Beginning
● Java has certainly not ignored the notion of
immutable data
○ Collections.unmodifiable* has been around
since… Java 1.2-ish
■ Return wrapped versions of collection
types which throw exceptions on
mutation methods
○ Value object
■ No language-level support
■ Several recipes/patterns for doing so
● “Effective Java” recipe
● JCIP discusses the idea
● Discussion centers on concrete benefits of
immutable objects
○ Thread safety
○ Ease of reasoning
○ No notion of the deeper way of thinking about
values, identity
21. Java: The Middle
Ages
● Collections: google-collections (later folded into
Guava) comes along and offers Immutable*,
truly immutable collection classes
● These implementations address two major
problems with Collections.unmodifiable*
○ The wrapped collections are unmodifiable, not
immutable
■ Changes to the wrapped (presumably
mutable) collection would appear in the
wrapper
○ Return types are general List, Map, Set interfaces
■ No indication to the type system that
these objects have different
characteristics
● Value objects: not much change
○ Still no language-level support
○ Developers largely left to roll their own
22. Java: It’s A Brave New World!
public class OneTwoTest {
@Value.Immutable
public interface OneTwo {
Integer one();
String two();
}
@Test
public void testOneTwo() {
OneTwo onetwo = ImmutableOneTwo.builder().one(1).two("one").build();
assertEquals(1, onetwo.one().intValue());
assertEquals("one",onetwo.two());
}
}
25. Some Things About
Monads
● Remind me what they are again?
○ A wrapped value and…
○ A “unit” function
■ To put a value into a monad
○ A “bind” function
■ Given (M T) and a function T -> M T’ apply
the function to the value wrapped in the
moand to generate a new monad
26. An example: Option ● The Option monad contains a value with one of
two variant types:
○ None (has no value)
○ Some (contains some value)
● The “bind” operation will apply it’s fn to the
wrapped value if the monad val is Some
○ Otherwise return None
● These behaviours allow Option to serve as “a
simple kind of error monad”
○ If a set of operations on a monad are successful
you get a Some containing the result
○ If any step fails you get None
27. Haskell: All About Option
data Maybe a = Nothing | Just a
deriving ( Eq
, Ord
)
instance Monad Maybe where
(Just x) >>= k = k x
Nothing >>= _ = Nothing
(>>) = (*>)
fail _ = Nothing
The type declaration: Maybe is an ADT with two
distinct variant types
While we’re here let’s make it a monad as well
28. Haskell: Option In Practice
GHCi, version 8.6.3
Prelude> (Just 1) >>= t -> Just(t + 1)
Just 2
Prelude> Nothing >>= t -> Just(t + 1)
Nothing
30. Java: A Pair of
Optionals
● Java has two common implementations of the
option/maybe type
○ Guava’s com.google.common.base.Optional
■ First on the scene
■ Before this everybody rolled their own
○ java.util.Optional
■ Standard as of Java8
● Overwhelming use case here is to avoid
returning null
○ Goal: minimize NullPointerExceptions (NPEs)
● This is not a small thing
○ Since null references have cost us exactly one
billion dollars [3]
31. Java: The Good Side of Optional
public class OptionTest {
private Integer findFirstNegativeInt(Integer...integers) {
for (Integer integer : integers) {
if (integer < 0) { return integer; }
}
return null;
}
private Optional<Integer> findFirstNegativeIntOption(Integer...integers) {
for (Integer integer : integers) {
if (integer < 0) { return Optional.<Integer>of(integer); }
}
return Optional.empty();
}
@Test
public void testOption() {
assertNotNull(findFirstNegativeInt(1,2,3,-100,4));
assertNull(findFirstNegativeInt(1,2,3,4));
assertNotNull(findFirstNegativeIntOption(1,2,3,-100,4));
assertNotNull(findFirstNegativeIntOption(1,2,3,4));
}
32. Java: The Other Side of Optional
public class OtherOptionTest {
private Optional<String> thisIsSafeRight(List<Integer> integers, Integer thingIWant) {
Map<Integer,Optional<String>> options = new HashMap<Integer,Optional<String>>();
for (Integer integer : integers) {
options.put(integer, Optional.<String>of(integer.toString()));
}
return options.get(Collections.binarySearch(integers, thingIWant));
}
@Test
public void testOption() {
assertNotNull(thisIsSafeRight(ImmutableList.of(1,2,3,4), 1)); // oops, this didn't pass
assertNotNull(thisIsSafeRight(ImmutableList.of(1,2,3,4), 4));
assertNotNull(thisIsSafeRight(ImmutableList.of(10,20,30,40), 10)); // hmmm, this didn't pass either
}
}
33. Some Other Things
About Option and
Java...
● So… Java doesn’t use monads
○ In practice, no
○ But...
34. Java: It’s a Monad After All!
public class OptionMonadTest {
public Optional<Integer> doTheThing(Optional<String> in) {
return in.filter(v -> !v.isEmpty()).map(v -> v.length()).map(v -> v * 10);
}
@Test
public void testOptionAsMonad() {
assertFalse(doTheThing(Optional.empty()).isPresent());
assertFalse(doTheThing(Optional.of("")).isPresent());
assertEquals(30, doTheThing(Optional.of("abc")).orElse(-1).intValue());
assertEquals(60, doTheThing(Optional.of("abcdef")).orElse(-1).intValue());
}
}
36. Conclusion The
First: Adaptation
Not Adoption
● We’ve seen Java “adapt” ideas from FP into
something that works within Java
○ Immutable types rather than persistent data
structures
○ Option type rather than use as monad
● Even these adapted uses can be terribly
powerful
○ These ideas represent significant improvements
to the OOP process
37. Conclusion The
Second: Perhaps
This Can Only Go So
Far
● Is it possible that adoption of these ideas
(persistent data structures and/or monads) at a
deeper level is limited because they represent
ways of managing state?
● State management in an object-oriented system
is (for better or worse) a solved problem
38. Conclusion The
Third: One-Way
Flow of Ideas
● We’ve seen a few examples of Java “converging
on” ideas from functional programming
● No equivalent adoption of ideas from OOP in
Haskell
● Not as if OOP is suffering for new ideas
○ Both theoretical…
■ Seriously, look at any OOPSLA program
○ … and practical
■ Proliferation of traits in object systems
■ Go’s radical approach to composition
● Closest I could get: Scala’s use of traits for
bottom-up composition of behaviours
○ More of a function of Scala implementing OOP
○ Not really FP absorbing something from OOP
● Did I miss something?
● Hypothesis: OOP’s focus on explicit entities
within the system (and their taxonomies) just
doesn’t apply to FP
39. References
1. Rich Hickey, “Persistent Data Structures and Managed References”
(https://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey)
2. Simon Peyton-Jones, “Wearing the Hairshirt” (http://www.cs.nott.ac.uk/~pszgmh/appsem-
slides/peytonjones.ppt)
3. Tony Hoare, “Null References: The Billion Dollar Mistake” (https://www.infoq.com/presentations/Null-
References-The-Billion-Dollar-Mistake-Tony-Hoare)
Notes de l'éditeur
A few introductory comments
This topic (convergence of OO and FP) is… large
Third or fourth generation of these slides
At one point you were gonna get a lengthy discussion of Alan Kay
All you can do is find some avenue into this conversation and run with it
A few quick notes about me
I started out writing Perl and later Scheme as an undergrad
Then went on to be a Java programmer for 20 years
Early and eager embrace of Clojure and Scala
Now I write Clojure at my day job
Try to keep a foot in both these camps
Putting slides together is always an effort for me
Feel pretty good about this one
The theme is called “Paradigm”
Quick definitions for OO and FP
Note that this is a perilous exercise
There are no universally agreed upon definitions for either of these things
Doing this mainly to orient some of the discussion…
What does it mean to say functions are a first-class entity of your language?
It means kinda what you’d expect… you can do everything with them you can do with other things (like objects, say)
You can:
Assign them to a variable
Pass them as an arg to something else
Return them from a function
Note: the first test (the one with the lambda inline) actually passed
Anybody wanna guess about where we went wrong?
No one is dying to go back to this kind of nonsense
Having lambdas is better than not having lambdas
And yes, in large part this approach was taken because Java has been around for a long time and is very concerned about not breaking existing code
My goal here is not to bash on Java or how it solved this problem
My goal here is to make the following observations:
The idea of lambdas (anonymous functions) were incorporated
This idea has a long history in other languages (some of them functional, some OO)
This feature was brought in in a way that doesn’t really support treating these entities as first-class functions
This is still described as “functional” in many resources (and victory is declared)
Not just immutable here; call out the persistent data structures at play
Scala has a suite of mutable collections which parallel the immutable ones… but we get immutable behaviour by default
The Java Collections framework came in with Java 1.2… and I believe the unmodifiable entities were there the beginning
Value object - loose equivalent to ADT in Java (very, very loose)
“Effective Java” - even included methods to return new versions of immutable structures from modification operations as programming “in a functional style”
New frameworks (such as Immutables, used here) facilitate creation of immutable value objects
But the conversation here is still limited to “immutable objects are thread-safe and easy to reason about”
Which is true… but the next step isn’t usually taken
Why does FP care so much about immutability
What’s a value and how do I work with it?
What are persistent collections?
And, far more importantly… _why_ do I care about them?
There are some Java impls of persistent collections… they’re just on the margins
Simon Peyton Jones suggestion for the term that should’ve been used instead of “monad”... from the “Wearing the Hair Shirt” slides
Don’t worry, we won’t be going through Yet Another Monad Tutorial
We do need to highlight a couple things though…
We’re simplifying a lot here to highlight the things we actually care about
“Simple kind of error monad”... from Haskell’s hackage docs on Data.Maybe… look it up, I swear it’s there
“Everybody rolled their own” - and that’s never been a problem ever
It’s also not foolproof…
So, I’m not a very good programmer and I think it’s a great idea to compute all possible return values upfront just ‘cause… well, because I read it on a blog post somewhere
So I do that, and then I search for my object and return the corresponding Optional from my pre-computed map
Sure, you wouldn’t actually do this… but the point is (a) Optional references can still themselves be null and (b) it’s fairly easy to write code which obscures when you’re returning nulls or not
Unfortunately most of the usages (at least that I’ve come across), documentation, design patterns, etc. don’t worry about this kind of thing
Very focused on returning Optional as an object to avoid NPEs
Nothing from OO -> FP… outside of CLOS, that is, and that is… a stretch