SlideShare a Scribd company logo
Poly-paradigm Java
Speaker
@pavletko
pav@p12v.comPavel Tcholakov
Poly-what?
Programming styles
• Imperative
• Object-oriented
• Aspect-oriented
• Functional
• Concurrent
• Actor
• Message-passing
• Logic, or rule-based
Poly-paradigm Java
Lambda expressions
(Pojo p) -> {
return p.getProperty();
}
Poly-paradigm Java
Streams
IntStream.range(0, 100)
.filter(i -> i % 2 == 0)
.map(i -> i * i)
.sum();
Longest string’s length
public int longestStringLength(List<String> strings) {
return strings.stream()
.mapToInt(String::length)
.max()
.getAsInt();
}
Longest string’s length
public String longestString(List<String> strings) {
return strings.stream()
.mapToInt(String::length)
.max()
// Ehh, now what???
}
Longest string’s length
public String longestString(List<String> strings) {
final String[] maxString = {null};
strings.stream()
.forEach(s -> {
if (s.length() > maxString[0].length()) {
maxString[0] = s;
}
});
return maxString[0];
}
Longest string
public String longestString(List<String> strings) {
return strings.stream()
.reduce((s1, s2) ->
s1.length() > s2.length() ? s1 : s2)
.get();
}
Longest string
public String longestString(List<String> strings) {
return strings.stream()
.max(Comparator.comparingInt(s -> s.length()))
.get();
}
Streams and functions
public List<String> findAllPalindromes(List<String> strings) {
return strings.stream()
.filter(s -> Objects.equals(s, StringUtils.reverse(s)))
.collect(Collectors.toList());
}
Functions, continued
public List<String> findAllPalindromes(List<String> strings) {
return strings.stream()
.filter(s -> Objects.equals(s, StringUtils.reverse(s)))
.collect(Collectors.toList());
}
Higher order function
public List<String> findUnchangedStrings(
List<String> strings,
Function<String, String> transformation) {
return strings.stream()
.filter(s -> Objects.equals(s, transformation.apply(s)))
.collect(Collectors.toList());
}
Higher order, continued
public List<String> palindromes(List<String> strings) {
return findUnchangedThings(strings, StringUtils::reverse);
}
public List<String> findShouting(List<String> strings) {
return findUnchangedThings(strings, StringUtils::capitalize);
}
Generic enough?
public List<String> findUnchangedStrings(
List<String> strings,
Function<String, String> transformation) {
return strings.stream()
.filter(s -> Objects.equals(s, transformation.apply(s)))
.collect(Collectors.toList());
}
Type parameters
public <T> List<T> findUnchangedThings(
List<? extends T> things,
Function<? super T, ? extends T> transformation) {
return things.stream()
.filter(t -> Objects.equals(t, transformation.apply(t)))
.collect(Collectors.toList());
}
public List<String> palindromes(List<String> strings) {
return findUnchangedThings(strings, StringUtils::reverse);
}
public List<String> findShouting(List<String> strings) {
return findUnchangedThings(strings, StringUtils::capitalize);
}
public List<Integer> nonNegative(List<Integer> ints) {
return findUnchangedThings(ints, Math::abs);
}
public <T> List<T> findUnchangedThings(
List<? extends T> things,
Function<? super T, ? extends T> transformation) {
return things.stream()
.filter(t -> Objects.equals(t, transformation.apply(t)))
.collect(Collectors.toList());
}
Monads?
Poly-paradigm Java
Poly-paradigm Java
Poly-paradigm Java
Poly-paradigm Java
Poly-paradigm Java
Poly-paradigm Java
Poly-paradigm Java
Poly-paradigm Java
Internal DSLs
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
config.vm.provision :shell, path: "bootstrap.sh"
config.vm.network :forwarded_port, guest: 80, host: 4567
end
JavaSlang pattern matching
Stream.of(0, 1, 2, 3, 13, 14, null, -1)
.peek(n -> out.print(format("%d -> ", n)))
.map(Match.as(Object.class)
.when(Objects::isNull).then("!")
.whenIs(0).then("zero")
.whenIsIn(1, 13, 14).then(i -> "first digit 1: " + i)
.whenType(Double.class).then(d -> "Found a double: " + d)
.whenApplicable((Number num) -> "number: " + num).thenApply()
.otherwise(() -> "no match"))
.map(Object::toString)
Actor model
Concurrency-oriented
programming
• We identify all the truly concurrent activities in our
real world activity.
• We identify all message channels between the
concurrent activities.
• We write down all the messages which can flow on
the different message channels.
— Joe Armstrong
Akka actor in Java
public class Greeter extends AbstractActor {
String greeting = "";
public Greeter() {
receive(ReceiveBuilder.
match(WhoToGreet.class,
message -> greeting = "hello, " + message.who).
match(Greet.class,
message -> sender()
.tell(new Greeting(greeting), self())).
build());
}
}
Logic programming
Prolog
fact.
another_fact.
jug(jozi_jug).
jug(virtual_jug).
java_meetup(java_day).
attendee(pavel, java_day).
attendee(nitsan, java_day).
attendee(richard, linux_meetup).
interested(java, Who) :-
attendee(Who, Meetup),
java_meetup(Meetup).
Poly-paradigm Java
Demo
N-queens in Prolog
solution([]).
solution([X/Y|Others]) :-
solution(Others),
member(Y, [1,2,3,4,5,6,7,8]),
noattack(X/Y, Others).
noattack(_, []).
noattack(X/Y, [X1/Y1|Others]) :-
Y == Y1,
Y1 - Y == X1 - X,
Y1 - Y == X - X1,
noattack(X/Y,Others).
Sudoku in Clojure core.logic
(defn sudokufd [hints]
(let [vars (repeatedly 81 lvar)
rows (->> vars (partition 9) (map vec) (into []))
cols (apply map vector rows)
sqs (for [x (range 0 9 3)
y (range 0 9 3)]
(get-square rows x y))]
(run 1 [q]
(== q vars)
(everyg #(fd/in % (fd/domain 1 2 3 4 5 6 7 8 9)) vars)
(init vars hints)
(everyg fd/distinct rows)
(everyg fd/distinct cols)
(everyg fd/distinct sqs))))
Ok, how about some Java?
Poly-paradigm Java
Rule-driven DCFT pattern
Poly-paradigm Java
Poly-paradigm Java
public interface Task {
boolean isInGoalState();
void handleEvents(Set<Event> events);
void applyRules(Consumer<Event> bus);
}
public boolean isInGoalState() {
return state == MemberState.FOLLOWER &&
lastHeartbeat.plus(ELECTION_TIMEOUT).isAfter(clock.now());
}
public void handleEvents(Set<Event> events) {
for (Event evt : events) {
if (evt instanceof AppendEntriesRpcReceived) {
lastHeartbeat = clock.now();
}
}
}
public void applyRules(Consumer<Event> eventBus) {
if (state == MemberState.FOLLOWER) {
if (lastHeartbeat.plus(ELECTION_TIMEOUT).isAfter(clock.now())) {
state = MemberState.CANDIDATE;
eventBus.accept(new MemberStateChange(state));
eventBus.accept(new LeaderVote(serverId));
} else {
// keep calm and carry on
}
} else {
// nothing to do in other states
}
}
Poly-paradigm Java
Causes of complexity
• State
• Control
• Code volume
• Others: complexity breeds complexity
FRP architecture
• Essential State
➡ A Relational definition of the stateful components of the
system
• Essential Logic
➡ Derived-relation definitions, integrity constraints and (pure)
functions
• Accidental State and Control
➡ A declarative specification of a set of performance
optimisations for the system
Poly-paradigm Java
for (int i = 1; i <= 100; i++) {
if (i % 15 == 0) {
out.println("FizzBuzz");
} else if (i % 3 == 0) {
out.println("Fizz");
} else if (i % 5 == 0) {
out.println("Buzz");
} else {
out.println(i);
}
}
for (int i = 1; i <= 100; i++) {
if (i % 15 == 0) {
out.println("FizzBuzz");
} else if (i % 3 == 0) {
out.println("Fizz");
} else if (i % 5 == 0) {
out.println("Buzz");
} else {
out.println(i);
}
}
static Predicate<Integer> divisibleBy(Integer div) {
return (i) -> i % div == 0;
}
class Replacement {
final Predicate<Integer> when; final String output;
public Replacement(Predicate<Integer> when, String output) {
this.when = when; this.output = output;
}
}
List<Replacement> fizzAndOrBuzz =
Collections.unmodifiableList(Arrays.asList(
new Replacement(divisibleBy(3), "Fizz"),
new Replacement(divisibleBy(5), "Buzz")));
static String replace(Integer i, List<Replacement> rules) {
return rules.stream()
.filter(replacement -> replacement.when.test(i))
.map(replacement -> replacement.output)
.reduce(String::concat)
.orElse(i.toString());
}
static String replace(Integer i, List<Replacement> rules) {
return rules.stream()
.filter(replacement -> replacement.when.test(i))
.map(replacement -> replacement.output)
.reduce(String::concat)
.orElse(i.toString());
}
static String replace(Integer i, List<Replacement> rules) {
Stream<String> applicableReplacements = rules.stream()
.filter(replacement -> replacement.when.test(i))
.map(replacement -> replacement.output);
return applicableReplacements
.reduce(String::concat)
.orElse(i.toString());
}
static String fizzBuzz(Integer i) {
return replace(i, fizzAndOrBuzz);
}
// …
IntStream.rangeClosed(1, 100)
.mapToObj(FizzBuzz::fizzBuzz)
.forEach(out::println);
static Stream<String> fizzBuzz(IntStream intStream) {
return intStream.mapToObj(FizzBuzz::fizzBuzz);
}
// …
IntStream infiniteInts = IntStream.iterate(1, i -> i + 1);
fizzBuzz(infiniteInts)
.limit(100)
.forEach(out::println);
public interface FizzBuzz {
class Replacement { final Predicate<Integer> when; final String output; … }
static Predicate<Integer> divisibleBy(Integer d) { return i -> i % d == 0; }
List<Replacement> fizzBuzzRules = unmodifiableList(asList(
new Replacement(divisibleBy(3), "Fizz"),
new Replacement(divisibleBy(5), "Buzz")));
static String replace(Integer i, List<Replacement> rules) {
return rules.stream()
.filter(replacement -> replacement.when.test(i))
.map(replacement -> replacement.output)
.reduce(String::concat)
.orElse(i.toString());
}
static void main(String... args) {
IntStream.rangeClosed(1, 100)
.mapToObj(i -> replace(i, fizzBuzzRules))
.forEach(out::println);
}
}
Performance
Benchmark Mode Cnt Score Error Units
FizzBenchmark.functionalSolution avgt 5 13.122 ± 4.030 us/op
FizzBenchmark.functionalSolution2 avgt 5 16.922 ± 2.558 us/op
FizzBenchmark.imperativeSolution avgt 5 1.579 ± 0.142 us/op
2015 MacBook Pro 15”, i7 2.2GHz
Poly-paradigm Java
Conclusions
Questions?
Feedback
@pavletko
pav@p12v.comPavel Tcholakov
“Simplicity can only be attained if it is
recognised, sought and prized.”
— Excerpt From: Ben Moseley, “Out of the Tar Pit.”
Thank you!

More Related Content

What's hot (20)

PDF
Go ahead, make my day
Tor Ivry
 
PDF
sizeof(Object): how much memory objects take on JVMs and when this may matter
Dawid Weiss
 
PDF
Python tour
Tamer Abdul-Radi
 
PDF
C# - What's next
Christian Nagel
 
PPTX
Python 내장 함수
용 최
 
PDF
JNI - Java & C in the same project
Karol Wrótniak
 
PDF
Good Code
Kevlin Henney
 
PPT
java 8 Hands on Workshop
Jeanne Boyarsky
 
KEY
Code as data as code.
Mike Fogus
 
PDF
Functional Programming with Groovy
Arturo Herrero
 
PDF
Madrid gug - sacando partido a las transformaciones ast de groovy
Iván López Martín
 
PDF
かとうの Kotlin 講座 こってり版
Yutaka Kato
 
PDF
G3 Summit 2016 - Taking Advantage of Groovy Annotations
Iván López Martín
 
PPTX
Programming Java - Lection 07 - Puzzlers - Lavrentyev Fedor
Fedor Lavrentyev
 
PDF
Logic programming a ruby perspective
Norman Richards
 
PDF
The Error of Our Ways
Kevlin Henney
 
PPTX
Groovy puzzlers по русски с Joker 2014
Baruch Sadogursky
 
PDF
Python Puzzlers
Tendayi Mawushe
 
PDF
Presentatie - Introductie in Groovy
Getting value from IoT, Integration and Data Analytics
 
Go ahead, make my day
Tor Ivry
 
sizeof(Object): how much memory objects take on JVMs and when this may matter
Dawid Weiss
 
Python tour
Tamer Abdul-Radi
 
C# - What's next
Christian Nagel
 
Python 내장 함수
용 최
 
JNI - Java & C in the same project
Karol Wrótniak
 
Good Code
Kevlin Henney
 
java 8 Hands on Workshop
Jeanne Boyarsky
 
Code as data as code.
Mike Fogus
 
Functional Programming with Groovy
Arturo Herrero
 
Madrid gug - sacando partido a las transformaciones ast de groovy
Iván López Martín
 
かとうの Kotlin 講座 こってり版
Yutaka Kato
 
G3 Summit 2016 - Taking Advantage of Groovy Annotations
Iván López Martín
 
Programming Java - Lection 07 - Puzzlers - Lavrentyev Fedor
Fedor Lavrentyev
 
Logic programming a ruby perspective
Norman Richards
 
The Error of Our Ways
Kevlin Henney
 
Groovy puzzlers по русски с Joker 2014
Baruch Sadogursky
 
Python Puzzlers
Tendayi Mawushe
 
Presentatie - Introductie in Groovy
Getting value from IoT, Integration and Data Analytics
 

Similar to Poly-paradigm Java (20)

ODP
Pick up the low-hanging concurrency fruit
Vaclav Pech
 
PDF
Flink Forward Berlin 2017: David Rodriguez - The Approximate Filter, Join, an...
Flink Forward
 
PPTX
ProgrammingwithGOLang
Shishir Dwivedi
 
PDF
Are we ready to Go?
Adam Dudczak
 
PPTX
Scala
suraj_atreya
 
PDF
Introduction to Go
Jaehue Jang
 
PDF
Go 프로그래밍 소개 - 장재휴, DomainDriven커뮤니티
JaeYeoul Ahn
 
PDF
Functional concepts in C#
Blend Interactive
 
PDF
Hw09 Hadoop + Clojure
Cloudera, Inc.
 
ODP
AST Transformations at JFokus
HamletDRC
 
PPTX
The definitive guide to java agents
Rafael Winterhalter
 
PDF
Refactoring to Macros with Clojure
Dmitry Buzdin
 
PDF
Java 5 New Feature
xcoda
 
PPTX
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Domenic Denicola
 
PDF
Generics and Inference
Richard Fox
 
PPSX
Tuga IT 2017 - What's new in C# 7
Paulo Morgado
 
PDF
Scala vs Java 8 in a Java 8 World
BTI360
 
PDF
What's in Kotlin for us - Alexandre Greschon, MyHeritage
DroidConTLV
 
PDF
C Language Lecture 17
Shahzaib Ajmal
 
PDF
Java puzzles
Nikola Petrov
 
Pick up the low-hanging concurrency fruit
Vaclav Pech
 
Flink Forward Berlin 2017: David Rodriguez - The Approximate Filter, Join, an...
Flink Forward
 
ProgrammingwithGOLang
Shishir Dwivedi
 
Are we ready to Go?
Adam Dudczak
 
Introduction to Go
Jaehue Jang
 
Go 프로그래밍 소개 - 장재휴, DomainDriven커뮤니티
JaeYeoul Ahn
 
Functional concepts in C#
Blend Interactive
 
Hw09 Hadoop + Clojure
Cloudera, Inc.
 
AST Transformations at JFokus
HamletDRC
 
The definitive guide to java agents
Rafael Winterhalter
 
Refactoring to Macros with Clojure
Dmitry Buzdin
 
Java 5 New Feature
xcoda
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Domenic Denicola
 
Generics and Inference
Richard Fox
 
Tuga IT 2017 - What's new in C# 7
Paulo Morgado
 
Scala vs Java 8 in a Java 8 World
BTI360
 
What's in Kotlin for us - Alexandre Greschon, MyHeritage
DroidConTLV
 
C Language Lecture 17
Shahzaib Ajmal
 
Java puzzles
Nikola Petrov
 
Ad

Recently uploaded (20)

PPTX
In From the Cold: Open Source as Part of Mainstream Software Asset Management
Shane Coughlan
 
PDF
Open Chain Q2 Steering Committee Meeting - 2025-06-25
Shane Coughlan
 
PDF
iTop VPN With Crack Lifetime Activation Key-CODE
utfefguu
 
PDF
Technical-Careers-Roadmap-in-Software-Market.pdf
Hussein Ali
 
PDF
AI + DevOps = Smart Automation with devseccops.ai.pdf
Devseccops.ai
 
PDF
IDM Crack with Internet Download Manager 6.42 Build 43 with Patch Latest 2025
bashirkhan333g
 
PPTX
OpenChain @ OSS NA - In From the Cold: Open Source as Part of Mainstream Soft...
Shane Coughlan
 
PPTX
Agentic Automation: Build & Deploy Your First UiPath Agent
klpathrudu
 
PDF
Digger Solo: Semantic search and maps for your local files
seanpedersen96
 
PDF
NEW-Viral>Wondershare Filmora 14.5.18.12900 Crack Free
sherryg1122g
 
PPTX
Agentic Automation Journey Session 1/5: Context Grounding and Autopilot for E...
klpathrudu
 
PDF
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
PDF
MiniTool Power Data Recovery 8.8 With Crack New Latest 2025
bashirkhan333g
 
PPTX
Empowering Asian Contributions: The Rise of Regional User Groups in Open Sour...
Shane Coughlan
 
PDF
Download Canva Pro 2025 PC Crack Full Latest Version
bashirkhan333g
 
PDF
IObit Driver Booster Pro 12.4.0.585 Crack Free Download
henryc1122g
 
PDF
Top Agile Project Management Tools for Teams in 2025
Orangescrum
 
PPTX
Coefficient of Variance in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
PPTX
Foundations of Marketo Engage - Powering Campaigns with Marketo Personalization
bbedford2
 
PPTX
Customise Your Correlation Table in IBM SPSS Statistics.pptx
Version 1 Analytics
 
In From the Cold: Open Source as Part of Mainstream Software Asset Management
Shane Coughlan
 
Open Chain Q2 Steering Committee Meeting - 2025-06-25
Shane Coughlan
 
iTop VPN With Crack Lifetime Activation Key-CODE
utfefguu
 
Technical-Careers-Roadmap-in-Software-Market.pdf
Hussein Ali
 
AI + DevOps = Smart Automation with devseccops.ai.pdf
Devseccops.ai
 
IDM Crack with Internet Download Manager 6.42 Build 43 with Patch Latest 2025
bashirkhan333g
 
OpenChain @ OSS NA - In From the Cold: Open Source as Part of Mainstream Soft...
Shane Coughlan
 
Agentic Automation: Build & Deploy Your First UiPath Agent
klpathrudu
 
Digger Solo: Semantic search and maps for your local files
seanpedersen96
 
NEW-Viral>Wondershare Filmora 14.5.18.12900 Crack Free
sherryg1122g
 
Agentic Automation Journey Session 1/5: Context Grounding and Autopilot for E...
klpathrudu
 
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
MiniTool Power Data Recovery 8.8 With Crack New Latest 2025
bashirkhan333g
 
Empowering Asian Contributions: The Rise of Regional User Groups in Open Sour...
Shane Coughlan
 
Download Canva Pro 2025 PC Crack Full Latest Version
bashirkhan333g
 
IObit Driver Booster Pro 12.4.0.585 Crack Free Download
henryc1122g
 
Top Agile Project Management Tools for Teams in 2025
Orangescrum
 
Coefficient of Variance in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
Foundations of Marketo Engage - Powering Campaigns with Marketo Personalization
bbedford2
 
Customise Your Correlation Table in IBM SPSS Statistics.pptx
Version 1 Analytics
 
Ad

Poly-paradigm Java

  • 4. Programming styles • Imperative • Object-oriented • Aspect-oriented • Functional • Concurrent • Actor • Message-passing • Logic, or rule-based
  • 6. Lambda expressions (Pojo p) -> { return p.getProperty(); }
  • 8. Streams IntStream.range(0, 100) .filter(i -> i % 2 == 0) .map(i -> i * i) .sum();
  • 9. Longest string’s length public int longestStringLength(List<String> strings) { return strings.stream() .mapToInt(String::length) .max() .getAsInt(); }
  • 10. Longest string’s length public String longestString(List<String> strings) { return strings.stream() .mapToInt(String::length) .max() // Ehh, now what??? }
  • 11. Longest string’s length public String longestString(List<String> strings) { final String[] maxString = {null}; strings.stream() .forEach(s -> { if (s.length() > maxString[0].length()) { maxString[0] = s; } }); return maxString[0]; }
  • 12. Longest string public String longestString(List<String> strings) { return strings.stream() .reduce((s1, s2) -> s1.length() > s2.length() ? s1 : s2) .get(); }
  • 13. Longest string public String longestString(List<String> strings) { return strings.stream() .max(Comparator.comparingInt(s -> s.length())) .get(); }
  • 14. Streams and functions public List<String> findAllPalindromes(List<String> strings) { return strings.stream() .filter(s -> Objects.equals(s, StringUtils.reverse(s))) .collect(Collectors.toList()); }
  • 15. Functions, continued public List<String> findAllPalindromes(List<String> strings) { return strings.stream() .filter(s -> Objects.equals(s, StringUtils.reverse(s))) .collect(Collectors.toList()); }
  • 16. Higher order function public List<String> findUnchangedStrings( List<String> strings, Function<String, String> transformation) { return strings.stream() .filter(s -> Objects.equals(s, transformation.apply(s))) .collect(Collectors.toList()); }
  • 17. Higher order, continued public List<String> palindromes(List<String> strings) { return findUnchangedThings(strings, StringUtils::reverse); } public List<String> findShouting(List<String> strings) { return findUnchangedThings(strings, StringUtils::capitalize); }
  • 18. Generic enough? public List<String> findUnchangedStrings( List<String> strings, Function<String, String> transformation) { return strings.stream() .filter(s -> Objects.equals(s, transformation.apply(s))) .collect(Collectors.toList()); }
  • 19. Type parameters public <T> List<T> findUnchangedThings( List<? extends T> things, Function<? super T, ? extends T> transformation) { return things.stream() .filter(t -> Objects.equals(t, transformation.apply(t))) .collect(Collectors.toList()); }
  • 20. public List<String> palindromes(List<String> strings) { return findUnchangedThings(strings, StringUtils::reverse); } public List<String> findShouting(List<String> strings) { return findUnchangedThings(strings, StringUtils::capitalize); } public List<Integer> nonNegative(List<Integer> ints) { return findUnchangedThings(ints, Math::abs); } public <T> List<T> findUnchangedThings( List<? extends T> things, Function<? super T, ? extends T> transformation) { return things.stream() .filter(t -> Objects.equals(t, transformation.apply(t))) .collect(Collectors.toList()); }
  • 30. Internal DSLs Vagrant.configure("2") do |config| config.vm.box = "hashicorp/precise64" config.vm.provision :shell, path: "bootstrap.sh" config.vm.network :forwarded_port, guest: 80, host: 4567 end
  • 31. JavaSlang pattern matching Stream.of(0, 1, 2, 3, 13, 14, null, -1) .peek(n -> out.print(format("%d -> ", n))) .map(Match.as(Object.class) .when(Objects::isNull).then("!") .whenIs(0).then("zero") .whenIsIn(1, 13, 14).then(i -> "first digit 1: " + i) .whenType(Double.class).then(d -> "Found a double: " + d) .whenApplicable((Number num) -> "number: " + num).thenApply() .otherwise(() -> "no match")) .map(Object::toString)
  • 33. Concurrency-oriented programming • We identify all the truly concurrent activities in our real world activity. • We identify all message channels between the concurrent activities. • We write down all the messages which can flow on the different message channels. — Joe Armstrong
  • 34. Akka actor in Java public class Greeter extends AbstractActor { String greeting = ""; public Greeter() { receive(ReceiveBuilder. match(WhoToGreet.class, message -> greeting = "hello, " + message.who). match(Greet.class, message -> sender() .tell(new Greeting(greeting), self())). build()); } }
  • 38. Demo
  • 39. N-queens in Prolog solution([]). solution([X/Y|Others]) :- solution(Others), member(Y, [1,2,3,4,5,6,7,8]), noattack(X/Y, Others). noattack(_, []). noattack(X/Y, [X1/Y1|Others]) :- Y == Y1, Y1 - Y == X1 - X, Y1 - Y == X - X1, noattack(X/Y,Others).
  • 40. Sudoku in Clojure core.logic (defn sudokufd [hints] (let [vars (repeatedly 81 lvar) rows (->> vars (partition 9) (map vec) (into [])) cols (apply map vector rows) sqs (for [x (range 0 9 3) y (range 0 9 3)] (get-square rows x y))] (run 1 [q] (== q vars) (everyg #(fd/in % (fd/domain 1 2 3 4 5 6 7 8 9)) vars) (init vars hints) (everyg fd/distinct rows) (everyg fd/distinct cols) (everyg fd/distinct sqs))))
  • 41. Ok, how about some Java?
  • 46. public interface Task { boolean isInGoalState(); void handleEvents(Set<Event> events); void applyRules(Consumer<Event> bus); }
  • 47. public boolean isInGoalState() { return state == MemberState.FOLLOWER && lastHeartbeat.plus(ELECTION_TIMEOUT).isAfter(clock.now()); } public void handleEvents(Set<Event> events) { for (Event evt : events) { if (evt instanceof AppendEntriesRpcReceived) { lastHeartbeat = clock.now(); } } } public void applyRules(Consumer<Event> eventBus) { if (state == MemberState.FOLLOWER) { if (lastHeartbeat.plus(ELECTION_TIMEOUT).isAfter(clock.now())) { state = MemberState.CANDIDATE; eventBus.accept(new MemberStateChange(state)); eventBus.accept(new LeaderVote(serverId)); } else { // keep calm and carry on } } else { // nothing to do in other states } }
  • 49. Causes of complexity • State • Control • Code volume • Others: complexity breeds complexity
  • 50. FRP architecture • Essential State ➡ A Relational definition of the stateful components of the system • Essential Logic ➡ Derived-relation definitions, integrity constraints and (pure) functions • Accidental State and Control ➡ A declarative specification of a set of performance optimisations for the system
  • 52. for (int i = 1; i <= 100; i++) { if (i % 15 == 0) { out.println("FizzBuzz"); } else if (i % 3 == 0) { out.println("Fizz"); } else if (i % 5 == 0) { out.println("Buzz"); } else { out.println(i); } }
  • 53. for (int i = 1; i <= 100; i++) { if (i % 15 == 0) { out.println("FizzBuzz"); } else if (i % 3 == 0) { out.println("Fizz"); } else if (i % 5 == 0) { out.println("Buzz"); } else { out.println(i); } }
  • 54. static Predicate<Integer> divisibleBy(Integer div) { return (i) -> i % div == 0; }
  • 55. class Replacement { final Predicate<Integer> when; final String output; public Replacement(Predicate<Integer> when, String output) { this.when = when; this.output = output; } } List<Replacement> fizzAndOrBuzz = Collections.unmodifiableList(Arrays.asList( new Replacement(divisibleBy(3), "Fizz"), new Replacement(divisibleBy(5), "Buzz")));
  • 56. static String replace(Integer i, List<Replacement> rules) { return rules.stream() .filter(replacement -> replacement.when.test(i)) .map(replacement -> replacement.output) .reduce(String::concat) .orElse(i.toString()); }
  • 57. static String replace(Integer i, List<Replacement> rules) { return rules.stream() .filter(replacement -> replacement.when.test(i)) .map(replacement -> replacement.output) .reduce(String::concat) .orElse(i.toString()); }
  • 58. static String replace(Integer i, List<Replacement> rules) { Stream<String> applicableReplacements = rules.stream() .filter(replacement -> replacement.when.test(i)) .map(replacement -> replacement.output); return applicableReplacements .reduce(String::concat) .orElse(i.toString()); }
  • 59. static String fizzBuzz(Integer i) { return replace(i, fizzAndOrBuzz); } // … IntStream.rangeClosed(1, 100) .mapToObj(FizzBuzz::fizzBuzz) .forEach(out::println);
  • 60. static Stream<String> fizzBuzz(IntStream intStream) { return intStream.mapToObj(FizzBuzz::fizzBuzz); } // … IntStream infiniteInts = IntStream.iterate(1, i -> i + 1); fizzBuzz(infiniteInts) .limit(100) .forEach(out::println);
  • 61. public interface FizzBuzz { class Replacement { final Predicate<Integer> when; final String output; … } static Predicate<Integer> divisibleBy(Integer d) { return i -> i % d == 0; } List<Replacement> fizzBuzzRules = unmodifiableList(asList( new Replacement(divisibleBy(3), "Fizz"), new Replacement(divisibleBy(5), "Buzz"))); static String replace(Integer i, List<Replacement> rules) { return rules.stream() .filter(replacement -> replacement.when.test(i)) .map(replacement -> replacement.output) .reduce(String::concat) .orElse(i.toString()); } static void main(String... args) { IntStream.rangeClosed(1, 100) .mapToObj(i -> replace(i, fizzBuzzRules)) .forEach(out::println); } }
  • 62. Performance Benchmark Mode Cnt Score Error Units FizzBenchmark.functionalSolution avgt 5 13.122 ± 4.030 us/op FizzBenchmark.functionalSolution2 avgt 5 16.922 ± 2.558 us/op FizzBenchmark.imperativeSolution avgt 5 1.579 ± 0.142 us/op 2015 MacBook Pro 15”, i7 2.2GHz
  • 67. “Simplicity can only be attained if it is recognised, sought and prized.” — Excerpt From: Ben Moseley, “Out of the Tar Pit.”

Editor's Notes

  • #2: Thanks for coming! Thanks Oracle and day’s sponsors for bringing the Java community together.
  • #3: Engineer @ AWS Cape Town (opinions my own) Current job: operate a moderately successful cloud service, we run many EC2 control plane services from CT office Past: Sys architect @ Discovery; financial services, web, mobile, systems integration, network systems, security builder Java tinkerer for many years: encountered java in ~99-2k; prod since 2003 Also: Groovy, Scala, Clojure (<3), & others (Ruby) Multiple Java 8 applications in production
  • #4: Polyglot -> poly-paradigm. By analogy, instead of picking up French, we could learn more idioms in English. Perhaps by studying other approaches and languages we could pick up some useful tricks. Design patterns have perhaps fallen off the radar a bit since the horrors of EJB 2 - time to reconsider? Human performance aspect
  • #5: AOP: Who’s using Java EE and/or Spring Framework?
  • #6: FP building systems out of functions treating functions as a first-class citizen in the language design pure functions have no side effects Anyone using: Scala / Groovy?
  • #7: Simple syntax for creating instances of functional interfaces. Pass around like any other value. How do we use them?
  • #8: Introduce some FP concepts with the help of Streams, new in Java 8 Who’s on Java 8?
  • #9: Streams looks neat! how nifty is this example?!
  • #10: We can do more complicated things, still easy!
  • #11: Ehh?
  • #12: Bad! Don’t do this. Side effects outside streams can lead to unpredictable results! Also, if we switched to parallel stream this will produce incorrect results.
  • #13: Note the .get() call - we have an Optional result.
  • #14: Turns out Streams authors thought of this!
  • #16: Extract function parameter.
  • #17: Ta-da!
  • #18: Same shape problem, different function parameters give us different behavior
  • #20: Introduced type parameter. Still same shape problem, now reusable with different data types.
  • #21: Reuse through composition. FP = higher-order thinking!
  • #22: Anyone using pure FP languages such as Haskell, ML, OCaml, F#?
  • #24: Monad: just a design pattern Used to construct computations by chaining pure functions It helps provide some context to the functions; basically a box
  • #26: what if the domain of the function is a box?
  • #27: flatMap to the rescue! unpacks the box before passing on
  • #30: Optional, Stream, CompletableFuture
  • #31: Brief aside: Lambdas make internal DSLs way nicer. Anyone seen a Vagrant config file? It’s just Ruby
  • #32: Pattern matching: a language feature in e.g. Scala, implemented as a DSL. Fluent builder API with heavy reliance on lambda.
  • #35: Characterised by: many, many concurrent actors. Pushing the limits of JVM - new lightweight threading models needed to scale to millions of actors per JVM; fast concurrent primitives like JCTools super important building blocks.
  • #36: Who has worked with Prolog or other constraint programming environment?
  • #37: Atoms: facts; facts with variables. Rules: used to infer new facts and answer queries.
  • #38: Unification: start with DB of facts; look at rules with unbound variables - generate something valid in place of a variable; does it unify with existing facts? yes -> keep going; no -> backtrack.
  • #42: Demo of Java / core.logic Tinkering with Raft. Hand rolled Actors but encountered difficulties dealing with handling all the states.
  • #43: Came across this paper… –– Tinkering with Raft. Hand rolled Actors but encountered difficulties dealing with handling all the states.
  • #44: A task consists of three elements: a collection of state variables, a set of rules, and a goal. We did not consciously choose a rules-based approach for RAMCloud’s DCFT modules: the code gradually as- sumed this form as we added functionality over a series of refactorings. We use the term rules-based to describe a style of pro- gramming where there is not a crisp algorithm that pro- gresses monotonically from beginning to end.
  • #45: It’s an actor! Spot the state monad
  • #46: It’s a state machine! The state machine definition is broad enough that it in- cludes the rules-based approach as a special case. However, in most state machines the actions are determined directly from the events. Rules use a two-step approach where event handlers only modify state and never take actions. Rules then trigger based on the resulting state, which reflects the sum of the outside events. The difference between these two approaches is subtle, but the rules-based approach results in a cleaner code factoring.
  • #48: Can you spot the state dependency that’s crept in?
  • #49: All this made me think of an older paper, OOTTP by Moseley and Marks
  • #50: “Avoid accidental state and complexity whenever you can, and if you can’t, then separate it from the rest of the system.”
  • #51: The logic component determines the meaning, whereas the control component only affects efficiency. I.e. we should still get the correct results even if we remove any accidental control (think removing a hot index from a DB table) Separate all three; avoid useless accidental state & control
  • #52: “We have argued that complexity causes more problems in large software systems than anything else. We have also argued that it can be tamed — but only through a concerted effort to avoid it where possible, and to separate it where not. Specifically we have argued that a system can usefully be separated into three main parts: the essential state, the essential logic, and the accidental state and control.” — Separate all three; avoid useless accidental state & control — Frege (islands of functional purity), relational/logic programming languages — The logic component determines the meaning, whereas the control component only affects efficiency. I.e. we should still get the correct results even if we remove any accidental control (think removing a hot index from a DB table)
  • #53: Check how we’re doing for time first! Skip this section if running late. Anybody recognise this? That’s right, FizzBuzz!
  • #55: Start by defining a factory method that spits out Predicate instances, using a Lambda expression. Predicate is a functional interface defined in Java 8 which is a function from something to a boolean.
  • #56: Next, we’ll continue to model our domain: “Replacement” groups a predicate that matches something, and the appropriate alternative string.
  • #58: We could break up this long chaining for better understanding.
  • #60: Now we can finally define a fizzBuzz helper that turns an integer into a string, using the rules we’ve defined. Applying it to a stream of ints is trivial.
  • #61: Another possibility: return a brand new stream transformed with our replacement rule. We can apply it to infinite streams! Works because of laziness.
  • #62: Upside: no dependency injection or AbstractFactoryFactories in sight! Downside: ~10x slower Decision: human costs, is this any easier to read / understand / maintain?
  • #64: Excellent rant, keynote by Joe Armstrong @ StrangeLoop 2014 5.2 32-bit words have as many possible states as all the atoms of the Earth! Our systems have enormous state spaces; not always necessary Who can program without Google & StackOverflow? We’ve made a mess and we need to reverse entropy in order to fix it
  • #65: Learning new languages is great, exposure to new paradigms. Read academic papers! Think about design - and design patterns. More constrained tools sometimes force creativity by enforcing simplicity. (Prime lens photography) State is bad. Manage the combinatorial explosion of state, compounded by explicit control. Eliminate accidental complexity wherever you recognise it. Don’t optimise prematurely. Is multi-paradigm truly possible? In Java? (Scala?) Is it a good idea? Even if it isn't, some of these ideas at least give us a framework for decomposing polyglot systems. Java is and will remain blue-collar programming language. Apply polyglot judiciously (e.g. Frege). “Simplicity can only be attained if it is recognised, sought and prized.” — Excerpt From: Ben Moseley. “Out of the Tar Pit.” Have fun!
  • #67: Feedback is the breakfast of champions!
  • #69: And our host and sponsors!