33
Max Bureck, 08. June 2016 XTEND – API AND DSL DESIGN PATTERNS

Xtend api and_dsl_design_patterns_eclipse_confrance2016

Embed Size (px)

Citation preview

Max Bureck, 08. June 2016

XTEND – API AND DSL DESIGN PATTERNS

2

XTEND – API AND DSL DESIGN PATTERNS

Intro – Xtend

- Xtend is a general purpose programming language transpiling to Java source

- Its syntax is flexible allowing definition of internal DSLs and interesting APIs

- This presentation will show some ways how the syntax can be utilized

- No detailed explanation of Xtend‘s features though

© Fraunhofer FOKUS

©M

atth

ias

Hey

de /

Frau

nhof

er F

OK

US

© M

atth

ias

Hey

de /

Frau

nhof

er F

OK

US

3

XTEND – API AND DSL DESIGN PATTERNS

Intro – Patterns

- Based on some observations from designing Xtend APIs

- Some ideas inspired by other languages (e.g. Scala, F#)

- Some patterns may or should be implemented via active annotations in future

© Fraunhofer FOKUS

©M

atth

ias

Hey

de /

Frau

nhof

er F

OK

US

© M

atth

ias

Hey

de /

Frau

nhof

er F

OK

US

4

XTEND – API AND DSL DESIGN PATTERNS

Intro – The Tools Provided By Xtend- Lambdas

- Call with lambda as last parameter: place after brackets; omit empty brackets strProv.apply([String s | println(s)]) ⇨ strProv.apply [println(it)]

- Setter call can be written as assignment

button.setText("Press Me") ⇨ button.text = "Press Me"

- Extension methods

emphasize("boo") ⇨ "boo".emphasize

- Operator overloading

operator_plus(1e15bd, 1e-4bd) ⇨ 1e15bd + 1e-4bd

- Active annotations

© Fraunhofer FOKUS

©M

atth

ias

Hey

de /

Frau

nhof

er F

OK

US

© M

atth

ias

Hey

de /

Frau

nhof

er F

OK

US

5

XTEND – API AND DSL DESIGN PATTERNS

Pattern Overview

- Nested Block Syntax

- Fluent Case Distinction

- Immutable Data Structure Patterns

- Implicit Parameter Values

- Type Providers

- API Xtendification

© Fraunhofer FOKUS

6

Nested Block Syntax, Use Case

- Lambda as last argument looks like a named block

- Can be exploited to create internal DSLs that look like nested blocks- Declarative look, while being imperative

- Especially useful when building up object trees, e.g.- UI elements- Configuration- Etc.

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

7

Nested Block Syntax, Callback API Example in Java 8

server( (conf) -> { conf.setPort(80); conf.get("/hello?name=$name", (response) -> { response.header(Pair.of("content", "text/html")); return HtmlBuilder.html(response, (builder) -> { builder.h1("Hello " + builder.param("name")); }); });});

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

8

Nested Block Syntax, Callback API Example

server [ port = 80 get("/hello?name=$name") [ header("Content-Type" -> "text/html") html [ h1("Hello " + param('name')) ] ]]

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Assignment to setter on default argument

default argument it

Implicit return of last expression result

Extension method

Method with lambda argument

Mapping operator

9

Nested Block Syntax, Summary

- Nested block APIs reflect logical containment structures in code

- Xtend reduces visual noise and enables declarative look

- Can improve maintainability due to clear intent and readability of code

- "Traditional" APIs may be used as nested blocks, using => operator

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

10

Fluent Case Distinction, Example: Object Decomposition in Java 8

ParentalStatus parentalStatus = bob.getParentalStatus();if(parentalStatus instanceof Parents) { Parents parents = (Parents) parentalStatus; Optional<Person> momOpt = parents.getMom(); Optional<Person> dadOpt = parents.getDad(); momOpt.ifPresent((mom) -> dadOpt.ifPresent((dad) -> { System.out.println("Mother: "+mom.getName()+", Father: "+ dad.getName()); }));} else { if(parentalStatus instanceof Orphan) { String orphanage = ((Orphan) parentalStatus).getOrphanage(); System.out.println("Orphanage: "+orphanage); } else { System.out.println("Unknown parental status"); }}

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

11

Signal / Noise

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

12

Fluent Case Distinction, Example: Pattern Matching in Rust

match bob.parental_status { Parents { mom: Some(ref mother), dad: Some(ref father) } => println!("Mother: {:?}, Father: {:?}", father.name, mother.name), Orphan { orphanage: ref institute } => println!("Orphanage: {:?}", institute), Unknown => println!("Parental status unknown"), _ => {}}

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

15

Fluent Case Distinction, Example

val daredevil = Person::orphan("Matt Murdock", "St Agnes Orphanage")

daredevil.parentalStatus.caseParents [ mom, dad |

println('''Mother: «mom.name», Father: «dad.name»''')

].caseOrphan [ orphanage |println("Orphanage: " + orphanage)

].caseUnknown [println("Unknown parental status")

]

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

👿

16

Fluent Case Distinction, Downsides

- Complex to implement, only makes sense if used multiple times

- No flexible nested decomposition and variable binding by caller

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Not the original I am

17

Fluent Case Distinction, Summary / Use Cases

- Most times the powerful switch statement or multiple dispatch is good enough

- Still, this pattern can be useful for several use cases:

- Short notation for reoccurring, non trivial object decomposition

- Null-safe data access

- Can enforce exhaustive case handling or at least default case

- Alternative to inheritance hierarchies: No looking for all possible subclasses

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

19

Immutable Data Structure Patterns – Intro

- Immutable objects are easier to reason about

- No unexpected changes when passed to methods

- Can safely be shared between threads

- Interestingly better for Java GC (according to Brian Goetz)

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

20

Immutable Data Structure Patterns

- Immutable objects are tricky in some cases

- Especially demanding are:

- Object manipulation and

- Circular references

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

What??? You said immutable!

Bear with me, explanation in3 slides

21

Immutable Data Structure Patterns: Object Instantiation

- Initialization using mutable builder objects

- Especially nice: Lambda builder pattern

- Example:

val p = ImmutablePerson.create [firstName = "Mack"lastName = "The Knife"

]

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

🔨

23

Immutable Data Structure Patterns: Object Manipulation

- So called “persistent data structures“

- For simple structures: Fields may have ”update” method

- Takes lambda parameter mapping old field value to new value

- Returns new immutable updated object

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

24

Immutable Object Patterns: Object Manipulation Example

class ImmutablePerson { // ... def ImmutablePerson firstName((String)=>String mapper) { val newFirstName = mapper.apply(firstName) new ImmutablePerson(newFirstName, lastName) }}

var p = ImmutablePerson.create […]p = p.firstName["max"]p = p.firstName[toFirstUpper]

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

25

Immutable Data Structure Patterns: Object Manipulation - Problem

- Cyclic references will come back to bite you on manipulation!

- Especially when automatically generating manipulators

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

26

Immutable Data Structure Patterns: Object Manipulation - Alternative

Manipulation by builder

- Create pre-filled builder from existing object

- Add some sugar for ease of use, similar to lambda builder

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

27

Immutable Data Structure Patterns: Manipulation By Builder Example

var homer = ImmutablePerson.create [firstName = "Homer"lastName = "Simpson"town = "Springfield"

]

homer = homer.with [firstName = "Max"lastName = "Power"

]

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

29

API Xtendification – Intro

- Java APIs are not written with Xtend in mind

- Some language features of Xtend only shine when API is shaped in a certain way

- Extension methods to the rescue!

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

30

API Xtendification, Builder Extension Method; Example Before

Example calling constructor of type from JDK:

val queue = new LinkedBlockingDequeval corePoolSize = 1val maximumPoolSize = 5val keepAliveTime = 200val keepAliveTimeUnit = TimeUnit.MILLISECONDS

val pool = new ThreadPoolExecutor(maximumPoolSize, corePoolSize, keepAliveTime, keepAliveTimeUnit, queue)

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Whoops, wrong parameter order

32

API Xtendification, Builder Extension Method; Example Definition

Let’s define an extension method:

static def ThreadPoolExecutor create(Class<ThreadPoolExecutor> clazz, (ThreadPoolExecutorBuilder)=>void config) { val builder = new ThreadPoolExecutorBuilder config.apply(builder) builder.build

}

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

???

33

API Xtendification, Builder Extension Method; Example Usage

Example using extension method

val pool = ThreadPoolExecutor.create [corePoolSize = 1maximumPoolSize = 5keepAliveTime = 200keepAliveTimeUnit = TimeUnit.MILLISECONDS

workQueue = new LinkedBlockingDeque]

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

🔨

35

Further Xtend Patterns

10 Java Idioms Stomped with Xtendhttps://www.youtube.com/watch?v=n7LUgXX_3cE

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

36

Summary

- Xtend language is pretty flexible, due to its syntax features

- Declarative looking internal DSLs are possible

- Enables new types of API patterns

- Patterns can be used to make Java APIs friendlier to use in Xtend

- Some patterns can be automated with Active Annotations

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

37© Fraunhofer FOKUS

38

Feedback and Opinions?

- Examples repository: https://github.com/Boereck/eclipsecon_france_2016-xtend_patterns

- Useful?

- Interesting?

- Impractical?

- Too obvious?

- What are your favorite patterns?

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

39

Image Sources

- Max Power:http://25.media.tumblr.com/tumblr_lxxowbwXTs1qhkm9yo1_400.gif

- Joda Pug:https://unsplash.com/photos/2Ts5HnA67k8

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

41© Fraunhofer FOKUS

Fraunhofer FOKUSKaiserin-Augusta-Allee 3110589 Berlin, Germanywww.fokus.fraunhofer.de

Max BureckSenior [email protected] +49 (0)30 3463-7321

CONTACT