Poly-paradigm Java

68
Poly-paradigm Java

Transcript of Poly-paradigm Java

Page 1: Poly-paradigm Java

Poly-paradigm Java

Page 2: Poly-paradigm Java

Speaker

@[email protected] Tcholakov

Page 3: Poly-paradigm Java

Poly-what?

Page 4: Poly-paradigm Java

Programming styles• Imperative

• Object-oriented

• Aspect-oriented

• Functional

• Concurrent

• Actor

• Message-passing

• Logic, or rule-based

Page 5: Poly-paradigm Java
Page 6: Poly-paradigm Java

Lambda expressions(Pojo p) -> { return p.getProperty();}

Page 7: Poly-paradigm Java
Page 8: Poly-paradigm Java

Streams

IntStream.range(0, 100) .filter(i -> i % 2 == 0) .map(i -> i * i) .sum();

Page 9: Poly-paradigm Java

Longest string’s length

public int longestStringLength(List<String> strings) { return strings.stream() .mapToInt(String::length) .max() .getAsInt();}

Page 10: Poly-paradigm Java

Longest string’s length

public String longestString(List<String> strings) { return strings.stream() .mapToInt(String::length) .max() // Ehh, now what???}

Page 11: Poly-paradigm Java

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];}

Page 12: Poly-paradigm Java

Longest string

public String longestString(List<String> strings) { return strings.stream() .reduce((s1, s2) -> s1.length() > s2.length() ? s1 : s2) .get();}

Page 13: Poly-paradigm Java

Longest string

public String longestString(List<String> strings) { return strings.stream() .max(Comparator.comparingInt(s -> s.length())) .get();}

Page 14: Poly-paradigm Java

Streams and functions

public List<String> findAllPalindromes(List<String> strings) { return strings.stream() .filter(s -> Objects.equals(s, StringUtils.reverse(s))) .collect(Collectors.toList());}

Page 15: Poly-paradigm Java

Functions, continued

public List<String> findAllPalindromes(List<String> strings) { return strings.stream() .filter(s -> Objects.equals(s, StringUtils.reverse(s))) .collect(Collectors.toList());}

Page 16: Poly-paradigm Java

Higher order functionpublic List<String> findUnchangedStrings( List<String> strings, Function<String, String> transformation) {

return strings.stream() .filter(s -> Objects.equals(s, transformation.apply(s))) .collect(Collectors.toList());}

Page 17: Poly-paradigm Java

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);}

Page 18: Poly-paradigm Java

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());}

Page 19: Poly-paradigm Java

Type parameterspublic <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());}

Page 20: Poly-paradigm Java

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());}

Page 21: Poly-paradigm Java

Monads?

Page 22: Poly-paradigm Java
Page 23: Poly-paradigm Java
Page 24: Poly-paradigm Java
Page 25: Poly-paradigm Java
Page 26: Poly-paradigm Java
Page 27: Poly-paradigm Java
Page 28: Poly-paradigm Java
Page 29: Poly-paradigm Java
Page 30: 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: 4567end

Page 31: Poly-paradigm Java

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)

Page 32: Poly-paradigm Java

Actor model

Page 33: Poly-paradigm Java

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

Page 34: Poly-paradigm Java

Akka actor in Javapublic 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()); }}

Page 35: Poly-paradigm Java

Logic programming

Page 36: Poly-paradigm Java

Prologfact.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).

Page 37: Poly-paradigm Java
Page 38: Poly-paradigm Java

Demo

Page 39: Poly-paradigm Java

N-queens in Prologsolution([]).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).

Page 40: Poly-paradigm Java

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))))

Page 41: Poly-paradigm Java

Ok, how about some Java?

Page 42: Poly-paradigm Java
Page 43: Poly-paradigm Java

Rule-driven DCFT pattern

Page 44: Poly-paradigm Java
Page 45: Poly-paradigm Java
Page 46: Poly-paradigm Java

public interface Task {

boolean isInGoalState();

void handleEvents(Set<Event> events);

void applyRules(Consumer<Event> bus);

}

Page 47: Poly-paradigm Java

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 }}

Page 48: Poly-paradigm Java
Page 49: Poly-paradigm Java

Causes of complexity

• State

• Control

• Code volume

• Others: complexity breeds complexity

Page 50: Poly-paradigm Java

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

Page 51: Poly-paradigm Java
Page 52: 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); }}

Page 53: 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); }}

Page 54: Poly-paradigm Java

static Predicate<Integer> divisibleBy(Integer div) { return (i) -> i % div == 0;}

Page 55: Poly-paradigm Java

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")));

Page 56: Poly-paradigm Java

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());}

Page 57: Poly-paradigm Java

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());}

Page 58: Poly-paradigm Java

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());}

Page 59: Poly-paradigm Java

static String fizzBuzz(Integer i) { return replace(i, fizzAndOrBuzz);}

// …

IntStream.rangeClosed(1, 100) .mapToObj(FizzBuzz::fizzBuzz) .forEach(out::println);

Page 60: Poly-paradigm Java

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);

Page 61: Poly-paradigm Java

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); }

}

Page 62: Poly-paradigm Java

PerformanceBenchmark Mode Cnt Score Error UnitsFizzBenchmark.functionalSolution avgt 5 13.122 ± 4.030 us/opFizzBenchmark.functionalSolution2 avgt 5 16.922 ± 2.558 us/opFizzBenchmark.imperativeSolution avgt 5 1.579 ± 0.142 us/op

2015 MacBook Pro 15”, i7 2.2GHz

Page 63: Poly-paradigm Java
Page 64: Poly-paradigm Java

Conclusions

Page 65: Poly-paradigm Java

Questions?

Page 66: Poly-paradigm Java

Feedback

@[email protected] Tcholakov

Page 67: Poly-paradigm Java

“Simplicity can only be attained if it is recognised, sought and prized.”

— Excerpt From: Ben Moseley, “Out of the Tar Pit.”

Page 68: Poly-paradigm Java

Thank you!