functional vaadin talk at oscon 2014

Post on 27-Aug-2014

532 Views

Category:

Software

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

An introduction on how to utilize functional programming techniques in Java 8 and Scala with Vaadin code.

TRANSCRIPT

Functional Vaadin

Henri Muurimaa, SVP of Serviceshenri@vaadin.com +358 400 474778 @henrimuurimaa

7

MissionMissionWhy do we exist

Make building amazing web applications easy

Building blocks

Developer

Productivity

Rich

UX

Web application layers

JavaScriptWeb serverBackend Communication

JS required required required requiredVaadin

required optionalrequired optional

Web application layers

JavaScriptWeb serverBackend Communication

JS required required required required

Vaadin

required optionalrequired optional

1 layer vs

3 layers

Less code Less bugs Faster time-to-market

Wrong, but the community is very active there

> 100.000 developers from > 10.000 cities > 450 add-ons in the marketplace

Other 4 %Asia

20 %

Americas 22 %

Europe 54 %

Open Source community

Apache-licensed

Demo time

github.com/hezamu/WorkoutTracker

What is Functional Programming?

A style of programming that expresses computation as the evaluation of mathematical functions

Recursion

Lazy evaluation

Lambda expressionsType theory

MonadsReferential transparency

Currying

Entscheidungsproblem

Pattern matching

Tuples

Something practical?

Side effects?

State?

Denied

Denied

Okay…

What’s in it for me?

A new way of thinking

A new way of programming

Write tight, robust and scalable code

What’s hot in Java 8

Improved Date API

New Java 8 Date API in action

public int monthAge() { return (new Date().getYear() - date.getYear()) * 12 + (new Date().getMonth() - date.getMonth()); }

// Java 8 version with the new Date API public int monthAge() { return (int) Period.between(date, LocalDate.now()).toTotalMonths(); }

Lambda expressions

Anonymous functions

Runnable r = () -> System.out.println("hello lambda!”);

Comparator<Integer> cmp1 = (x, y) -> (x < y) ? -1 : ((x > y) ? 1 : 0);

// Anonymous onsite functions button.addClickListener(event -> System.out.println("Button clicked!"));

Comparator<Integer> cmp2 = (x, y) -> { return (x < y) ? -1 : ((x > y) ? 1 : 0); // Need return if not one liner };

Workout Tracker example

editor.clear.addClickListener(new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { editor.clearValues(); updateRating(); } });

// Java 8 version with a lambda editor.clear.addClickListener(event -> { editor.clearValues(); updateRating(); });

Method references with the :: notation

! private void eventHandler(Button.ClickEvent event) { // do something about the button click }

button.addClickListener(this::eventHandler);

// If the handler method is static button.addClickListener(MyClass::eventHandler);

Workout Tracker example

!editor.activity.addValueChangeListener(new Property.ValueChangeListener() { @Override public void valueChange(ValueChangeEvent event) { updateRating(); } });

// Java 8 version with a method reference editor.date.addValueChangeListener(this::updateRating);

Streams

Composable with higher order functions

Streams != collections

As lazy as possible

Can be infinite

Input validation

private boolean areInputsValid() { Component component = null; for (Iterator<Component> iter = editor.iterator(); iter.hasNext(); iter.next()) { if (fieldNotValidating(component)) return false; } return true; }

// Java 8 version with anyMatch and a method reference private boolean areInputsValid() { return !StreamSupport.stream(editor.spliterator(), true) .anyMatch(this::fieldNotValidating); }

Higher order functions

A function that takes one or more functions as input

Returns a new stream by applying the given function to all elements of this stream. !

MapReturns a new stream consisting of the elements of this stream that match the given predicate.

Filter

SQL analogue: SELECT SQL analogue: WHERE

Workout Tracker Example

!

!

!

// Java 8 version with stream operations private Stream<Workout> findByAge(int maxMonths) { return workouts.stream() .filter(w -> w.monthAge() < maxMonths) .sorted(Comparator.comparing(Workout::monthAge).reversed()); }

private List<Workout> findByAge(int maxMonths) { List<Workout> result = new ArrayList<>(); for (Workout w : workouts) { if (w.monthAge() < maxMonths) { result.add(w); } } Collections.sort(result, new Comparator<Workout>() { @Override public int compare(Workout o1, Workout o2) { return o2.monthAge() - o1.monthAge(); } }); ! return result; }

Scratching the surface of Scala syntax

class Cat(name: String) { initLitterBox() def meow(volume: Int = 5) = { println(s"$name meows " + (if (volume <= 5) "quietly" else "loudly")) volume <= 5 } }

Class body is the constructor

identifier: type notation

Functions with def keyword

Arguments can have default values

Return keyword optional

No semicolons needed

Burn the boilerplate - Workout.java

!

!

!

public void setDuration(int duration) { this.duration = duration; } ! public double getAvgHR() { return avgHR; } ! public void setAvgHR(double avgHR) { this.avgHR = avgHR; } ! public double getMaxHR() { return maxHR; } ! public void setMaxHR(double maxHR) { this.maxHR = maxHR; } ! public int getCalories() { return calories; } ! public void setCalories(int calories) { this.calories = calories; } ! public String getComment() { return comment; } ! public void setComment(String comment) { this.comment = comment; } }

public class Workout { private String activity; private Date date; private int duration, calories; private double avgHR, maxHR; private String comment; ! public Workout(String activity, Date date, int time, double avgHR, double maxHR, int kcal, String comment) { this.activity = activity; this.date = date; this.duration = time; this.avgHR = avgHR; this.maxHR = maxHR; this.calories = kcal; this.comment = comment; } ! public int monthAge() { return (int) Period.between(date, LocalDate.now()).toTotalMonths(); } ! public String getActivity() { return activity; } ! public void setActivity(String activity) { this.activity = activity; } ! public Date getDate() { return date; } ! public void setDate(Date date) { this.date = date; } ! public int getDuration() { return duration; }

Equivalent Workout.scala

!

!

!

case class Workout(activity: String, date: LocalDate, duration: Int, avgHR: Double, maxHR: Double, calories: Int, comment: String) { def monthAge = Period.between(date, LocalDate.now).toTotalMonths }

github.com/henrikerola/scaladin

An example

// Scaladin val layout = new VerticalLayout { margin = true ! add(Label("Hello, OSCON!"), alignment = Alignment.TopCenter) add(Button("Click me”, handleButtonClick)) }

// Java 7 VerticalLayout layout = new VerticalLayout(); layout.setMargin(true); Label label = new Label(“Hello, OSCON!”); layout.addComponent(title); layout.setComponentAlignment(label, Alignment.TOP_CENTER); !Button button = new Button(“Click me", new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { handleButtonClick(); } }); layout.addComponent(button);

Input validation, Java 8 & Scala

// Scaladin version of the editor gives us the components as a Scala Set // which supports functional operations. private def areInputsValid = !editor.components.exists(fieldNotValidating)

// Java 8 version with anyMatch and a method reference private boolean areInputsValid() { return !StreamSupport.stream(editor.spliterator(), true) .anyMatch(this::fieldNotValidating); }

Summary

SLOC comparison

Java 7 Java 8 Scala

UI 267 264 175

Presenter 168 128 84

POJO 82 82 8All versions: zero lines of HTML, JavaScript, RPC code or browser specific tweaks

Je zult maar letter wezen. Goed, ik ben niet ontevredet. Maar het valt niet mee in deze zeventiger jaren tot het vaderlandse alfabet te behoren. Foto-zetterijen wringen je steeds in steeds ingevikkelder. Je zult maar letter wezen. Goed, ik ben

Henri Muurimaa, SVP of Serviceshenri@vaadin.com +358 400 474778 @henrimuurimaa

top related