Last updated on 22.11.2020
Notable talks from the FPConf conference.
Macros in Scala
A good introduction to scala macros from JetBrains scala plugin developer.
Macros is basically an AST transformation.
Simple macros are implementes as a method invocations:
1 2 3 |
def macro_name(a: Any) = macro macro_impl def macro_impl(c: Context)(a: c.Tree) = ??? |
More complex things are achieved with implicit macros.
Macros can help with:
- Typeclass generation (including generic implicit macros as a fallback)
- DSLs
- Typechecked strings (e.g. format-string)
- Compiler plugins
IDE support is far from ideal, mostly because of todays scala macro implementation limitations. Coming Scala.meta to the rescue.
Speaker had a custom IDEA build on his laptop, with a super-awesome “expand macros” feature. Just press a magic shortcut and examine expanded macro code.
Brilliant thing by JetBrains, can’t wait to use it.
Embedding a language in string interpolator
Great example of custom string interpolator use case.
Mikhail Limansky showed an example of creating MongoDB query language interpreter with a string interpolator.
Most of the times you don’t need such things, for example if you use a good ORM. But speaker’s case is valid. He works with two projects each using different and verbose ORM’s to access a single mongo database. So he made a decision to implement a single expressive (and importantly— well-known) language interpreter, that would generate ORM code of choice.
Even though it’s a plain string interpolator, it’s almost compeletely typesafe, thanks to extensive macros usage. Talk covers every step to implement such a thing.
Here’s the library.
https://github.com/limansky/mongoquery
Frontend with joy (DataScript database)
Introduction into DataScript database: https://github.com/tonsky/datascript
In a few words — it’s an immutable in-memory database for browser js applications.
Along with mentioned immutability it has several other advantages:
- Powerful query language with pattern matching.
- Well-defined and simple database changes description format. With an ability to query with such diffs it has event sourcing out of the box.
- It builds indexes.
Scala performance for those who doubt
My personal favourite of all the fpconf talks.
- Deadcode elimination
- Constant folding
- Loop unrolling
- …
Micro-benchmark runner. Has sbt plugin (sbt-jmh)
Tools here: JMH perfasm profiler, javap
Measurements
1) Pattern matching
Simple ADT match equals in speed to if-clause sequence.
Null-check is much faster then
Option-matching. In general, because of type-erasure, parametrized types pattern matching is slower (but it’s a fair price such feature).
2) Tail recursion
Basically is as fast as loops
3) Collections
Fold and map combinators have significant overhead for big arrays, and especially for primitives as elements.
That’s partly because of HotSpot optimization heuristics are shaped for java.
The problem for primitives is boxing. Scala collections are generics, so specialization doesn’t work for them.
There is an alternative collection library, called Debox, which have specialized Buffer, Set and Map .
Conclusion
- Scala is slow:
- it’s easy to write beautiful, but laggy code
- collections are super-slow with primitives
- scalac can generate strange code
- Scala is fast:
- with good internals knowledge, beautiful code can work as fast as java code
- with a few hacks you can make collections be friends with primitives
- JVM can optimize strange scalac generated code