Top Banner
Max Bureck, 08. June 2016 XTEND – API AND DSL DESIGN PATTERNS
41

Xtend API and DSL Design Patterns EclipseConFrance2016

Jan 04, 2017

Download

Documents

vukhuong
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Xtend API and DSL Design Patterns EclipseConFrance2016

Max Bureck, 08. June 2016

XTEND – API AND DSL DESIGN PATTERNS

Page 2: Xtend API and DSL Design Patterns EclipseConFrance2016

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 /

Fra

unho

fer

FO

KU

Mat

thia

s H

eyde

/ F

raun

hofe

r F

OK

US

Page 3: Xtend API and DSL Design Patterns EclipseConFrance2016

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 /

Fra

unho

fer

FO

KU

Mat

thia

s H

eyde

/ F

raun

hofe

r F

OK

US

Page 4: Xtend API and DSL Design Patterns EclipseConFrance2016

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 /

Fra

unho

fer

FO

KU

Mat

thia

s H

eyde

/ F

raun

hofe

r F

OK

US

Page 5: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 6: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 7: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 8: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 9: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 10: Xtend API and DSL Design Patterns EclipseConFrance2016

10

Fluent Case Distinction, Example: Object Decomposit ion 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

Page 11: Xtend API and DSL Design Patterns EclipseConFrance2016

11

Signal /

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Page 12: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 13: Xtend API and DSL Design Patterns EclipseConFrance2016

13

Fluent Case Distinction, Pattern Matching: Short De scription

− Comparable to switch statement in C like languages

− Matches a structural pattern of an object and it‘s fields

− Expression of first matching pattern will be executed

− Allows binding of field values to variable names (e.g. ref mother in example)

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Page 14: Xtend API and DSL Design Patterns EclipseConFrance2016

14

Fluent Case Distinction – Intro

− Generic pattern matching with type-matching, decomposition and variable binding?

− Xtend switch expression “only” has instance check, no decomposition

− A library solution would be best

− But readable solution seems to be impossible without language support

− Next best thing are data type specific solutions

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Page 15: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 16: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 17: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 18: Xtend API and DSL Design Patterns EclipseConFrance2016

18

Fluent Case Distinction, Summary

− Fluent Case APIs can encapsulate reusable object decompositions

− They are an alternative to language-level pattern matching

− Come with implementation overhead

− Depending on usage (capturing in lambdas), may have runtime and memory overhead

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Page 19: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 20: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 21: Xtend API and DSL Design Patterns EclipseConFrance2016

21

Immutable Data Structure Patterns: Object Instantia tion

− 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

�λ

Page 22: Xtend API and DSL Design Patterns EclipseConFrance2016

22

Immutable Data Structure Patterns: Lambda Builder E xplained

− Static create method taking lambda

− Create method instantiates builder and calls lambda with it

− Lambda calls setters on builder

− Create method uses configured builder to create object and returns it

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Page 23: Xtend API and DSL Design Patterns EclipseConFrance2016

23

Immutable Data Structure Patterns: Object Manipulat ion

− 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

Page 24: Xtend API and DSL Design Patterns EclipseConFrance2016

24

Immutable Object Patterns: Object Manipulation Exam ple

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

Page 25: Xtend API and DSL Design Patterns EclipseConFrance2016

25

Immutable Data Structure Patterns: Object Manipulat ion - Problem

− Cyclic references will come back to bite you on man ipulation!

− Especially when automatically generating manipulators

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Page 26: Xtend API and DSL Design Patterns EclipseConFrance2016

26

Immutable Data Structure Patterns: Object Manipulat ion - 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

Page 27: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 28: Xtend API and DSL Design Patterns EclipseConFrance2016

28

Immutable Data Structure Patterns: Manipulation Spe cifics

− Always needs manipulation from "root" object to ensure consistency

− Pushing side effects to boundaries

− Advantage of “update” methods: Manipulation may be nested

− Cyclic references must be set lazy (same as in constructor)

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Page 29: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 30: Xtend API and DSL Design Patterns EclipseConFrance2016

30

API Xtendification, Builder Extension Method; Examp le Before

Example calling constructor of type from JDK:

val queue = new LinkedBlockingDeque

val corePoolSize = 1

val maximumPoolSize = 5

val keepAliveTime = 200

val keepAliveTimeUnit = TimeUnit.MILLISECONDS

val pool = new ThreadPoolExecutor(maximumPoolSize, corePoolSize,

keepAliveTime, keepAliveTimeUnit, queue)

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Whoops, wrong parameter order

Page 31: Xtend API and DSL Design Patterns EclipseConFrance2016

31

API Xtendification, Builder Extension Method; Probl em Statement

− When not using variables, long parameter lists are hard to understand

− When using variables

− It is possible to mess up parameter order

− Wrong variables might be used

− Code will compile, but might be wrong

− Solution: Use a builder class …

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Page 32: Xtend API and DSL Design Patterns EclipseConFrance2016

32

API Xtendification, Builder Extension Method; Examp le 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

Page 33: Xtend API and DSL Design Patterns EclipseConFrance2016

33

API Xtendification, Builder Extension Method; Examp le Usage

Example using extension method

val pool = ThreadPoolExecutor.create [

corePoolSize = 1

maximumPoolSize = 5

keepAliveTime = 200

keepAliveTimeUnit = TimeUnit.MILLISECONDS

workQueue = new LinkedBlockingDeque

]

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

�λ

Page 34: Xtend API and DSL Design Patterns EclipseConFrance2016

34

API Xtendification, Builder Extension Method Explai ned

− Example shows alternative to overloaded constructors with different parameter lists

− It is supposed to look like a create method is called in class ThreadPoolExecutor

− Actual static method is located in different class

− Extension method call with class object of class ThreadPoolExecutor as first param

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Page 35: Xtend API and DSL Design Patterns EclipseConFrance2016

35

Further Xtend Patterns

10 Java Idioms Stomped with Xtend

https://www.youtube.com/watch?v=n7LUgXX_3cE

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Page 36: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 37: Xtend API and DSL Design Patterns EclipseConFrance2016

37© Fraunhofer FOKUS

Page 38: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 39: Xtend API and DSL Design Patterns EclipseConFrance2016

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

Page 40: Xtend API and DSL Design Patterns EclipseConFrance2016

40

My Xtend Most Wanted Whish List

− Method references

− Default methods

− Compile auto-lambda-type-conversions to Java 8 method references, where possible

− Overloading call operator (also allow as extension method)

val nomnom = ["banana"]

nomnom()

− Pattern matching with decomposition

− More flexible active annotations

© Fraunhofer FOKUS

XTEND – API AND DSL DESIGN PATTERNS

Page 41: Xtend API and DSL Design Patterns EclipseConFrance2016

41© Fraunhofer FOKUS

Fraunhofer FOKUSKaiserin-Augusta-Allee 3110589 Berlin, Germany

www.fokus.fraunhofer.de

Max Bureck

Senior Researcher

[email protected]

Phone +49 (0)30 3463-7321

CONTACT