Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2...

37
Directembedding Concealing the Deep Embedding of DSLs Ólafur Páll Geirsson École Polytechnique Fédérale de Lausanne School of Computer and Communication Sciences June 11, 2015 Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 1 / 36

Transcript of Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2...

Page 1: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

DirectembeddingConcealing the Deep Embedding of DSLs

Ólafur Páll Geirsson

École Polytechnique Fédérale de LausanneSchool of Computer and Communication Sciences

June 11, 2015

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 1 / 36

Page 2: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Motivation

Overview

1 Motivation

2 Directembedding

3 Case study: slick-direct v2

4 Conclusion

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 2 / 36

Page 3: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Motivation

Motivation

Mission statementEnable wider adoption of embedded DSLs

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 3 / 36

Page 4: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Motivation

The StruggleDeeply embedded vs. Shallowly embedded

Author User

Deep

Shallow

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 4 / 36

Page 5: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Directembedding

Overview

1 Motivation

2 DirectembeddingArchitectureLanguage virtualizationType overridingImproved error messagesConfiguration

3 Case study: slick-direct v2

4 Conclusion

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 5 / 36

Page 6: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Directembedding Architecture

Pipeline

PreProcessing DSL Virtualization

Reification Transformation

Shallow DSL

DeepDSL

PostProcessing

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 6 / 36

Page 7: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Directembedding Language virtualization

Language Virtualization

Override standard language features

if (cond) 1 else 2 => __ifThenElse(cond, 1, 2)x == y => infix_==(x, y)var x = "str" => __newVar("str")while (cond) body => __while(cond, body)// etc.

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 7 / 36

Page 8: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Directembedding Type overriding

Type overriding

Override behavior predefined and third-party types

class MyInt {@reifyAs(IntPlus)def +(x: Int): Int = ???

}// Shallowdsl {val x = 1x + 2

}// DeepIntPlus(x, lift(1))

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 8 / 36

Page 9: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Directembedding Improved error messages

Improved error messages

// Shallowdsl {val s = "foobar"s.charAt(1)

}// Compiler error[error] method charAt on class String is not

supported in example.dsl:s.charAt(1)^

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 9 / 36

Page 10: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Directembedding Configuration

Configuration@reifyAs

// Inside Query trait.@reifyAs(Take)def take(i: Long): Query[T, C] = ???// Shallow query.query {Query.take(1)

}// Deep query.Take(Query, lift(1))

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 10 / 36

Page 11: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Directembedding Configuration

Configuration@reifyAsInvoked

// Inside Query trait.@reifyAsInvokeddef take(i: Long): Query[T, C] = ???// Shallow query.query {Query.take(1)

}// Deep query.lift(Query).take(lift(1))

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 11 / 36

Page 12: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Directembedding Configuration

Configuration@passThrough

// Inside Query trait.@passThroughdef take(i: Long): Query[T, C]def missingAnnotation(): Int = 1// Shallow query.query {Query.take(missingAnnotation())

}// Deep query.lift(Query).take(missingAnnotation())

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 12 / 36

Page 13: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2

Overview

1 Motivation

2 Directembedding

3 Case study: slick-direct v2Lifted embeddingDirect embedding v1Shadow embeddingDirect embedding v2

4 Conclusion

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 13 / 36

Page 14: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2

Problem statement

Problem statementDevelop an awesome embedded query language in Scala

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 14 / 36

Page 15: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Lifted embedding

Lifted embeddingaka Slick

Currently supported API in Slick 3.0

The good parts1 Uses standard Scala2 Feature rich

The bad parts1 Lifted embedding table requires boilerplate2 Cryptic error messages

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 15 / 36

Page 16: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Lifted embedding

Problem 1Lifted embedding table requires boilerplate

case class User(id: Int, name: String)

// Lifted embedding tableclass Users(tag: Tag)extends Table[User](tag, "User") {

def id: Rep[Int] = column[Int]("id")def name: Rep[String] = column[String]("name")

def * = ProvenShape.proveShapeOf((id, name) <>((User.apply _).tupled, User.unapply))

}

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 16 / 36

Page 17: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Lifted embedding

Problem 2Cryptic error messages

[Error] User.scala:25: No matching Shape found.Slick does not know how to map the given types.Possible causes: T in Table[T] does notmatch your * projection. Or you use anunsupported type in a Query (e.g. scala List).Required level: slick.lifted.FlatShapeLevel

Source type:(slick.lifted.Rep[Int], slick.lifted.Rep[String],

slick.lifted.Rep[Int])Unpacked type: (Int, String)

Packed type: Anydef * = ProvenShape.proveShapeOf((id, name, id) <> ((User.apply _).tupled,User.unapply))

^

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 17 / 36

Page 18: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Direct embedding v1

Direct embeddingDeprecated in Slick 3.0

The good parts1 No more boilerplate2 Comprehensible error messages

The bad parts1 Queries can fail at runtime2 Difficult to develop and maintain

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 18 / 36

Page 19: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Direct embedding v1

Benefit 1No more boilerplate

@Table("USER")case class User(@PrimaryKey @Column("ID")id: Int,@Column("NAME")name: String

)

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 19 / 36

Page 20: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Direct embedding v1

Problem 1Queries can fail at runtime

// Compiles!Query[User].map(_.id.toDouble)// But runtime error...

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 20 / 36

Page 21: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Shadow embedding

Shadow embeddingPowered by Yin-Yang

Master project of Amir Shaikhha, August 2013

The good parts1 User-friendly API2 Comprehensive and comprehensible error messages3 Great performance

The not so good parts1 Challenging for the DSL author

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 21 / 36

Page 22: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Shadow embedding

Shadow embeddingPowered by Yin-Yang

Master project of Amir Shaikhha, August 2013

The good parts1 User-friendly API2 Comprehensive and comprehensible error messages3 Great performance

The not so good parts1 Challenging for the DSL author

We are almost there!

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 21 / 36

Page 23: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Shadow embedding

ProblemAuto generated SlickCake

trait YYSlickCakeTuples {type Tuple2[T1,T2] = YYTuple2[T1,T2]implicit def yyRepTuple2ToYYTuple[T1,T2](x:

CakeRep[scala.Tuple2[T1,T2]]): Tuple2[T1,T2]= x.asInstanceOf[Tuple2[T1,T2]]

// 1300 more LOC for up to Tuple22...}trait YYSlickCake with YYSlickCakeTuples {

implicit def yyColumnOptionToYYOption[T](x:YYColumn[scala.Option[T]]): YYOption[T]

= YYOption.fromYYColumn(x)// ...

}

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 22 / 36

Page 24: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Shadow embedding

Problem3 layers of Query

trait Query[T] // Shallowdef map[S](projection: T => S): Query[S]

trait YYQuery[T] // Shadowdef map[S](projection: YYRep[T] => YYRep[S]):

YYQuery[S]= YYQuery.fromQuery(query.map(underlyingProjection(projection))(YYShape.ident[S]))

trait Query[E, T] // Lifteddef map[F, G, T](f: E => F)(implicit shape:

Shape[F, T, G]): Query[G, T]

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 23 / 36

Page 25: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Direct embedding v2

DirectembeddingFrom shallow to deep in one step

slick-direct v2

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 24 / 36

Page 26: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Direct embedding v2

Pipeline reminder

PreProcessing DSL Virtualization

Reification Transformation

Shallow DSL

DeepDSL

PostProcessing

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 25 / 36

Page 27: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Direct embedding v2

Shallow configurationSimplified example

trait Query[T, C[_]]@reifyAsInvokeddef filter(f: T => Boolean): Query[T, C]

@reifyAs(SlickReification.column _)def column[T, C](e: T, name: String,

tt: TypedType[C]): C@reifyAs(SlickReification.slick_=== _)def infix_==(a: Int, b: Int): Boolean = ???

object SlickPredef@passThroughdef implicitly[T]: T

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 26 / 36

Page 28: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Direct embedding v2

Deep configurationSimplified example

object SlickReification {def slick_===[T](lhs: lifted.Rep[T], rhs:

lifted.Rep[T]): Rep[Option[Boolean]] = {columnExtensionMethods(lhs) === rhs

}def column[T, C](e: AnyRef,

field: Rep[String],tt: TypedType[C]): Rep[C]

// 20 more LOC}

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 27 / 36

Page 29: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Direct embedding v2

Directembedding transformationPipeline

Shallow query

query {Query[User].filter(_.name == "Olafur")

}

PreProcessing DSL Virtualization

Reification Transformation

Shallow DSL

DeepDSL

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 28 / 36

Page 30: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Direct embedding v2

Directembedding transformationPipeline

PreProcessing

class UserTable extends Table[User] { /* ... */ }UserTable.filter { u =>column(u, "name", implicitly[TypedType[String]])

== "Olafur"}

PreProcessing DSL Virtualization

Reification Transformation

Shallow DSL

DeepDSL

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 29 / 36

Page 31: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Direct embedding v2

Directembedding transformationPipeline

DSL Virtualization

import DslConfig._class UserTable extends Table[User] { /* ... */ }UserTable.filter { u => infix_==(

shallowColumn(u, "name",implicitly[TypedType[String]]),

"Olafur")

}

PreProcessing DSL Virtualization

Reification Transformation

Shallow DSL

DeepDSL

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 30 / 36

Page 32: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Direct embedding v2

Directembedding transformationPipeline

Reification Transformation

import DslConfig._class UserTable extends Table[User] { /* ... */ }lift(UserTable).filter { u => slick_===(

deepColumn(u, lift("name"),implicitly[TypedType[String]]),

lift("Olafur"))

}

PreProcessing DSL Virtualization

Reification Transformation

Shallow DSL

DeepDSL

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 31 / 36

Page 33: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Case study: slick-direct v2 Direct embedding v2

It works!

FilterSpec

"filter" should "work with string equality" in {equalQueries(query {directUsers.filter(_.name == "Olafur")

}.result,liftedUsers.filter(_.name === "Olafur").result

)} // Success

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 32 / 36

Page 34: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Conclusion

Overview

1 Motivation

2 Directembedding

3 Case study: slick-direct v2

4 Conclusion

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 33 / 36

Page 35: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Conclusion

Conclusion

DirectembeddingLanguage virtualizationType overridingMore reification optionsImproved configuration

Slick-direct v2Under 300 LOC, developed in less than 2 weeksQueries supported: select *, join, filter, map, flatMap, take,(custom column types)

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 34 / 36

Page 36: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Conclusion

Future work

More case studiesImprove slick-direct

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 35 / 36

Page 37: Directembedding Concealing the Deep Embedding of DSLs · The good parts 1 Uses standard Scala 2 Feature rich The bad parts 1 Lifted embedding table requires boilerplate ... [Error]

Conclusion

The End

Thank you!

Ólafur Páll Geirsson (EPFL) Directembedding June 11, 2015 36 / 36