and paradigms • But some constructs are deeply integrated • Functions • Tuples • Arrays • Ordering • Numeric for { conn getConnection \/> "Could not connect" ← ids conn.get("id") \/> "Coult not get ids" ← } yield user
x Extending Function1 behavior? Sure, add an implicit. Function syntax is sugar for anonymous classes extending FunctionX traits (or for Java8 lambdas)
x Extending Function1 behavior? Sure, add an implicit. Changing behavior (e.g. PartialFunction)? This is what we'll talk about today. Function syntax is sugar for anonymous classes extending FunctionX traits (or for Java8 lambdas)
Adding a new method to the trait/class Making it conform to an interface Changing a method's signature Updating the body of a method Changing the fields of a class
Adding a new method to the trait/class Making it conform to an interface Changing a method's signature Updating the body of a method Changing the fields of a class Extending behavior Changing behavior
Why would you need that? Adding a new method to the trait/class Making it conform to an interface Changing a method's signature Updating the body of a method Changing the fields of a class Extending behavior Changing behavior
Test { | def foo[@miniboxed T](t: T): T = bar(t) | def bar[ T](t: T): T = baz(t) | def baz[@miniboxed T](t: T): T = t | } <console>:10: warning: The method Test.bar would benefit from miniboxing type parameter T, since it is instantiated by miniboxed type parameter T of method foo: def foo[@miniboxed T](t: T): T = bar(t) ^ <console>:11: warning: The following code could benefit from miniboxing specialization if the type parameter T of method bar would be marked as "@miniboxed T": def bar[T](t: T): T = baz(t) ^ defined object Test
(t: T) => t defined method identityFun scala> identityFun(3) <console>:11: warning: The method identityFun would benefit from miniboxing type parameter T, since it is instantiated by a primitive type. identityFun(3) ^ res1: Int = 3
t <console>:12: warning: The type parameter T1 of trait scala.Function1 is specialized but to interoperate efficiently with miniboxing, it would have to be miniboxed. def identityFun[@miniboxed T] = (t: T) => t ^ <console>:12: warning: The type parameter R of trait scala.Function1 is specialized but to interoperate efficiently with miniboxing, it would have to be miniboxed. def identityFun[@miniboxed T] = (t: T) => t ^ defined method identityFun Library Interoperation Library Interoperation
t <console>:12: warning: The type parameter T1 of trait scala.Function1 is specialized but to interoperate efficiently with miniboxing, it would have to be miniboxed. def identityFun[@miniboxed T] = (t: T) => t ^ <console>:12: warning: The type parameter R of trait scala.Function1 is specialized but to interoperate efficiently with miniboxing, it would have to be miniboxed. def identityFun[@miniboxed T] = (t: T) => t ^ defined method identityFun Library Interoperation Library Interoperation Not actionable
t <console>:12: warning: The type parameter T1 of trait scala.Function1 is specialized but to interoperate efficiently with miniboxing, it would have to be miniboxed. def identityFun[@miniboxed T] = (t: T) => t ^ <console>:12: warning: The type parameter R of trait scala.Function1 is specialized but to interoperate efficiently with miniboxing, it would have to be miniboxed. def identityFun[@miniboxed T] = (t: T) => t ^ defined method identityFun Library Interoperation Library Interoperation Not actionable Need to fix it
t <console>:12: warning: The type parameter T1 of trait scala.Function1 is specialized but to interoperate efficiently with miniboxing, it would have to be miniboxed. def identityFun[@miniboxed T] = (t: T) => t ^ <console>:12: warning: The type parameter R of trait scala.Function1 is specialized but to interoperate efficiently with miniboxing, it would have to be miniboxed. def identityFun[@miniboxed T] = (t: T) => t ^ defined method identityFun Library Interoperation Library Interoperation Not actionable Need to fix it
Adding a new method to the trait/class Making it conform to an interface Changing a method's signature Updating the body of a method Changing the fields of a class Extending behavior Changing behavior
Adding a new method to the trait/class Making it conform to an interface Changing a method's signature Updating the body of a method Changing the fields of a class Extending behavior Changing behavior Completely replacing a library class
Other library dependencies Each library is free to use its desired FunctionX version Talk to each in its own "language" Have to track of the transformations
changes to – Methods – Fields – Classes – Traits • Carry transformation info with types – Automatically annotate the code – The pickler phase stores them in signatures – Introduce conversions where necessary
We have an MbFunction1 and – Callee expects Function1? • Conversions – Between the two cases – Functions defined in miniboxed code • Miniboxing-friendly and specialization-friendly – Functions defined in non-miniboxed code • Specialization-friendly • Need conversion Miniboxing friendly →
Other library Other library Other lib 1 Other lib 2 Other lib 3 dependencies reverse dependencies Libraries not compiled with the miniboxing plugin are not aware of the transformation → incorrect bytecode
Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_101). Type in expressions to have them evaluated. Type :help for more information. scala> Test.identityFun(2) <console>:11: error: This method was compiled with the miniboxing plugin and can only be called by code also compiled with the miniboxing plugin (see scala-miniboxing.org/compatibility) [mbox=0.4-M8,scala=2.11.7] Test.identityFun(2) ^
(t: T) => t def identityFun[@miniboxed T]: Function1[T, T] = (t: T) => t typer interop-inject @compileTimeOnly(...) def identityFun[@miniboxed T]: Function1[T, T] @mbFun = (t: T) => t Built into the Scala stdlib and recognized by scalac (checked by refchecks) pickler
code – Under an erased interface (example) – Under a specialized interface • Pro: no dependency on the plugin downstream • Cons: have to write some glue code
immutable vector data structure – With constant-time split and merge (for parallel ops) • Idea by Phil Bagwell and Tiark Rompf • Implementation by Nicolas Stucki – 4 developer-weeks of work – Hand-tuned for maximum performance – Scaling almost linearly with the number of cores – Summing a vector is 2x as slow as summing an array • Presented at ICFP '15
difficult is it to specialize RRBVector with miniboxing? – What are the speedups obtained by miniboxing? • Preparation: – Copied the Scala stdlib suppor necessary for RRBVector (3k LOC) – Eliminated the parallel execution support (3k 2k LOC) → – Prepared benchmarks • Subject: Milos Stojanovic – Master student working in the lab – Experienced with miniboxing – Never saw the RRBVector code base before
minutes to optimize the code base by following the miniboxing warnings → 0.3% of the development time Benchmark Microbenchmarks (5M elements) Macrobenchmark Builder map fold reverse* Least squares linear regression (5M points) Erased (seconds) 43.2 103.0 94.1 31.4 4864.6 Miniboxed (seconds) 22.9 60.4 42.1 35.3 1818.1 Speedup (ratio) 1.88x 1.71x 2.24x 0.89x 2.68x * reversing a vector does not perform any operations that could benefit from miniboxing.
Scala constructs – Preserve the syntactic sugar – No source code changes • Scalac/miniboxing does a lot of the work • Use cases – Miniboxing: performance – <your use case here>