!SLIDE intro
!SLIDE left
- Thank you, contributors!
- Some numbers
- Mailing list members:
>
4K - Issue tracker
>
3K registered users (2K not on mailing list)>
7K reported issues- top-11: 25%, top-55: 50%, top-1100: 95%
- 5 issues/day
- GitHub
- Close 6 PR/day
- Mailing list members:
!SLIDE
!SLIDE
!SLIDE
!SLIDE
- Functions (small abstractions)
- Objects and traits (big abstractions)
!SLIDE
- Experimentation
- Large-scala
^H
e development
!SLIDE left
- Simple core: objects and methods
- Simple reduction into core
(x: Int) => x
~>new {def apply(x: Int) = x}
- for comprehensions
- pattern matching
- string interpolation
- context bounds
!SLIDE left
println("")
!SLIDE top
import unfiltered.netty.websockets._
val sockets = ListBuffer.empty[WebSocket]
WebSocketServer("/socket/repl", 8080) {
case Open(s) => sockets += s
case Message(s, Text(str)) =>
val resp = interpret(str)
sockets foreach (_.send(resp))
} run ()
!SLIDE top
val interpreter = new IMain(settings)
val completion = new JLineCompletion(interpreter)
def interpret(data: String): String = {
data.split(":", 2) match {
case Array("run", source) =>
util.stringFromStream { ostream =>
Console.withOut(ostream) {
interpreter.interpret(source) } }
case Array(r"""complete@(\d*)${I(pos)}""", source) =>
// handle completion at position $pos
}
}
!SLIDE
!SLIDE left
- Rewritten Pattern Matcher
- String Interpolation (SIP-11)
- Value Classes (SIP-15)
- Implicit Classes (SIP-13)
!SLIDE left
- Feature Imports (SIP-18)
- Futures and Promises (SIP-14)
- Dependent method types
- Cake factory methods
- ASM-based back-end
!SLIDE left
!SLIDE left
- Rewritten from scratch
- Dozen long-standing bugs fixed
- Favorite: exponential-space bytecode
- Total: close to 100
- Modular, grokkable implementation
!SLIDE left
- Extractors can be extension methods
- Nicer error messages via SAT solving
- Improving CNF encoding: #2724
- "Virtualized": e.g., match in the probability monad
!SLIDE
def check(x: Option[String]) = x match {
case Some("magic") =>
}
!NOTES case Some(_) => case None =>
check(None)
!SLIDE left
- Extractors reconcile
- Pattern matching
- OO Encapsulation
- Requires
Option
boxing- @paulp's tackling this in 2.11
- Value classes meet patmat
!SLIDE
object I {
def unapply(x: String) = util.Try { x.toInt } toOption
}
"10" match { case I(10) => }
I.unapply("10") match { case Some(10) => }
(New in 2.10: Try
, based on Twitter's com.twitter.util.)
!NOTES import language.postfixOps
!SLIDE
def bottles(n: String) = s"$n bottles of beer"
def safeBottles(n: Int) = f"$n%d bottles of beer"
def brokenBottles(n: Double) = f"$n%d bottles of beer"
!NOTES this is the unifier of the talk implicit classes value classes string interpolators patmat & objects macros (printf-style validation)
!SLIDE left
- drop $-prefixed holes
- pack parts in a
StringContext
- call the interpolator (named in the prefix)
- pass the holes as arguments
!SLIDE
// def bottles(n: String) = s"$n bottles of beer"
def bottles(n: String) = StringContext("", " bottles of beer").s(n)
Somewhere, in the standard library:
case class StringContext(parts: String*) {
def s(args: Any*): String = standardInterpolator(treatEscapes, args)
}
!SLIDE
// def safeBottles(n: Int) = f"$n%d bottles of beer"
def safeBottles(n: Int) = "%d bottles of beer" format n
There's a macro for that.
case class StringContext(parts: String*) {
// check that types, number of `args` correspond to formatter in `parts`
def f(args: Any*): String = macro macro_StringInterpolation_f
}
!SLIDE
"10 bottles" match {
case r"""\d* bottles""" => "ok!"
}
!SLIDE
val Pattern = r"""\d* bottles"""
"10 bottles" match {
case Pattern() => "ok!"
}
- Interpolated strings are first-class.
- No need to first put it in a
val
.- Uniformity ~> simplicity
- If we can make this work, so will the original
!SLIDE
val Pattern = r"""\d* bottles"""
Pattern.unapplySeq("10 bottles") match {
case Some(_) => "ok!"
}
unapplySeq
generalizesunapply
to variable number of subpatterns
!SLIDE
val Pattern = StringContext("""\d* bottles""").r
Pattern.unapplySeq("10 bottles") match {
case Some(_) => "ok!"
}
!NOTES
"10 bottles" match {
case r"""(\d*)${I(x)} bottles""" => x
}
- add method
def r: X
toStringContext
X
must have anunapplySeq
method
!SLIDE
implicit class RContext(sc: StringContext) {
def r = new util.matching.Regex(
sc.parts.mkString(""),
sc.parts.tail.map(_ => "x"): _*
)
}
implicit class
encapsulates
best practice implicit conversions- before, only
implicit
val
ordef
y no implicit class!?
!SLIDE left
- Type inference
- Value inference (
implicit val
) - Here be (cool) dragons
- specs, shapeless, scalaz,...
- [paper] fighting bitrot with types
- [paper] type classes as objects and implicits
!SLIDE
implicit class RContext(sc: StringContext) {
def r = new util.matching.Regex(
sc.parts.mkString(""),
sc.parts.tail.map(_ => "x"): _*
)
}
val n = "10 bottles" match {
case r"""(\d*)$n bottles""" => n
}
!SLIDE
val r"""(\d*)${I(n)} bottles""" = "10 bottles"
Note: n
is an Int
!
!SLIDE
Cool applications/articles:
!SLIDE left
- Balance
- Java interop
- Legacy
- Desire for new toys
- With
- Make programming fun
- Sanity
- Simplicity
!SLIDE
- Immutable / pure encouraged.
- Mutation / impure where you need it.
!SLIDE
import concurrent._; import ExecutionContext.Implicits.global
var y = 0
Future { y = 1 } ; Future { y = 2 }
!SLIDE
def slowCalcFuture: Future[Int] = ...
val future1 = slowCalcFuture
val future2 = slowCalcFuture
def combined: Future[Int] = for {
r1 <- future1
r2 <- future2
} yield r1 + r2
!SLIDE
def combined: Future[Int] = async {
val future1 = slowCalcFuture
val future2 = slowCalcFuture
await(future1) + await(future2)
}
!SLIDE
Future[T]
vsT
- important difference
Future[T]
keeps latency,
error handling on your mind
!SLIDE left
- Help you identify Good Parts for
- your project, and
- your team,
- at this time.
- Desirable subset of Scala evolves.
!SLIDE
- postfixOps
- reflectiveCalls
- implicitConversions
- existentials
- higherKinds
- dynamics
- experimental.macros
!SLIDE
class AnythingGoes extends Dynamic {
def applyDynamic(selection: String)(args: Any*): Any =
println(s"You called $selection${args.mkString("(", ",", ")")}. Thanks!")
}
!NOTES import language.dynamics (new AnythingGoes).notInspired("sorry")
!SLIDE
scala> val dict = Dict.dict dict: Dict = Dict(88629 words, 103040 definitions) // safe, unsafe, it's all the same if we know what we're doing scala> dict.unsafeOracle.flibbertigibbet res1: Definitions = flibbertigibbet Flib"ber*ti*gib`bet, n.Defn: An imp. Shak. scala> dict.safeOracle.flibbertigibbet res2: Definitions = flibbertigibbet Flib"ber*ti*gib`bet, n.Defn: An imp. Shak.
!SLIDE
// it is when we make up supposed "crazy, made-up" words that we // enjoy the difference scala> dict.unsafeOracle.bippy res3: Definitions = Runtime Vocabulary Failure: No Such Word scala> dict.safeOracle.bippy :9: error: not found: "bippy" dict.safeOracle.bippy ^
typesafe proxy https://gist.github.com/paulp/5265030
!SLIDE left
- Modularizing std lib & compiler
- Roll your own scala.xml!
!SLIDE left
- Incremental compiler
(@gkossakowski) - Better optimizer/codegen
(@magarciaEPFL, @jamesiry)
!SLIDE left
- Mature 2.10's experimental features
- Macros & Reflection
- stay experimental, no type macros
- best practices: blackbox macros
!SLIDE