Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

A Tour of Scala 3


Published on

Keynote, Scala Days Lausanne, June 11 2019

Published in: Technology
  • Login to see the comments

A Tour of Scala 3

  1. 1. A Tour of Scala 3 Martin Odersky Scala Days Lausanne June 2019
  2. 2. 10th Anniversary Edition of ScalaDays It all started here in 2010
  3. 3. 10th Anniversary Edition of ScalaDays It all started here in 2010
  4. 4. Some curious parallels between now and then What was new in 2010? Collections in Scala 2.8 Scala 2.13, with even better collections! First redesign since 2010 100% CanBuildFrom free! And today?
  5. 5. Scala 2.13 • Redesigned collections (à talk by Stefan Zeiger, Wed 17.45) • Updated futures implementation (à talk by Viktor Klang, Wed 14.30) • Language changes: § literal types § partial unification (SI-2712) on by default § by-name implicits § macro annotations § many polishings in details Merged over 1500 pull requests from 162 contributors
  6. 6. More curious parallels between now and then • Scala 2.8 had some breaking language changes. • Should have been named 3.0. • But we already talked about it as 2.8, felt that it was too late to change. • Now in 2019, Scala 3.0 has (almost) arrived!
  7. 7. Roadmap June 2019 All features fleshed out, with implementations in Dotty 0.16+ Fall 2019 Feature freeze, Scala 3.0 M1 stabilization complete SIP process write spec, user docs migrate open-source ecosystem flesh out tests, community build compatibility and migration tools Fall 2020 Scala 3.0 final Scala 2.13 Scala 2.14
  8. 8. A Tour of Scala 3
  9. 9. ? Best of Scala 3 What are Scala-3’s Nicest Features? • For beginners • For everyday coding • For experts I’ll give my personal ranking of the top 3 of each category. I also did a Twitter survey and will report on that. ? ?
  10. 10. Nicest Features for Beginners? • At that level, most of the language stays the same • But there are nevertheless a few improvements worth mentioning … ?
  11. 11. #3: Drop New • new can be omitted from almost all instance creations. • Only needed to disambiguate in an apply method. • No need to define a case class anymore just to get nice constructor calls. class StringBuilder(s: String) { def this() = this("") } StringBuilder("abc") // same as new StringBuilder("abc") StringBuilder() // same as new StringBuilder()
  12. 12. #2: Toplevel Definitions All kinds of definitions can be written on the toplevel. Package objects are no longer needed, will be phased out. package p type Labelled[T] = (String, T) val a: Labelled[Int] = ("count", 1) def b = a._2 def hello(name: String) = println(i"hello, $name)
  13. 13. #1 Enums enum Color { case Red, Green, Blue } Simplest way to define new types with a finite number of values or constructors.
  14. 14. #1 Enums can have parameters can define fields and methods can interop with Java enum Planet(mass: Double, radius: Double) extends java.lang.Enum { private final val G = 6.67300E-11 def surfaceGravity = G * mass / (radius * radius) case MERCURY extends Planet(3.303e+23, 2.4397e6) case VENUS extends Planet(4.869e+24, 6.0518e6) case EARTH extends Planet(5.976e+24, 6.37814e6) case MARS extends Planet(6.421e+23, 3.3972e6) ... }
  15. 15. #1 Enums can have type parameters, making them algebraic data types (ADTs) enum Option[+T] { case Some(x: T) case None }
  16. 16. #1 Enums compile to sealed hierarchies of case classes and objects. sealed abstract class Option[+T] object Option { case class Some[+T](x: T) extends Option[T] object Some { def apply[T](x: T): Option[T] = Some(x) } val None = new Option[Nothing] { ... } }
  17. 17. #1 Enums can be GADTs (generalized ADTs). à cases can extend the base type with different type arguments. enum Tree[T] { case True extends Tree[Boolean] case False extends Tree[Boolean] case IsZero(n: Tree[Int]) extends Tree[Boolean] case Zero extends Tree[Int] case Succ(n: Tree[Int]) extends Tree[Int] case If(cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T]) extends Tree[T] }
  18. 18. The public vote:
  19. 19. Why Enums? • Lots of use cases, and they are becoming more common. • Avoids boring, repetitive boilerplate. • Can grow from very simple to very powerful.
  20. 20. Nicest Features for Everyday Coding? • There are lots of candidates. • Hard to come up with a shortlist. ?
  21. 21. #3 Union Types Provide ad-hoc combinations of types Subsetting = Subtyping No boxing overhead case class UserName(name: String) case class Password(hash: Hash) def help(id: UserName | Password) = { val user = id match { case UserName(name) => lookupName(name) case Password(hash) => lookupPassword(hash) } ... }
  22. 22. #3 Union Types Work also with singleton types Great for JS interop type Command = ”Click" | ”Drag" | ”KeyPressed" def handleEvent(kind: Command) = kind match { case “Click" => MouseClick() case ”Drag" => MoveTo() case ”KeyPressed" => KeyPressed() }
  23. 23. #2 Extension Methods Replace implicit classes Make it easier to add methods to existing classes. object StringOps { def (s: String) * (x: Int): String = if (x <= 0) “” else s * (x - 1) ++ s } import StringOps._ "hello" * 3
  24. 24. #1 Delegates Replace “implicit” as a modifier Express intent instead of mechanism trait Ord[T] { def (x: T) compareTo (y: T): Int def (x: T) < (y: T) = x.compareTo(y) < 0 } delegate IntOrd for Ord[Int] { def (x: Int) compareTo (y: Int) = if (x < y) -1 else if (x > y) +1 else 0 } def maximum[T](xs: List[T]) given Ord[T] = xs.reduce((x, y) => if (x < y) y else x)
  25. 25. #1 Delegates Work out of the box with extension methods Provide a nice syntax for typeclasses trait SemiGroup[T] { def (x: T) combine (y: T): T } trait Monoid[T] extends SemiGroup[T] { def unit: T } delegate for Monoid[String] { def (x: String) combine (y: String) = x.concat(y) def unit = "" } def sum[T: Monoid](xs: List[T]): T = xs.foldLeft( the[Monoid[T]].unit )(_.combine(_))
  26. 26. #1 Delegates implicit def intToStr(str: String): Token = new Keyword(str) tame implicit conversions What’s wrong with this? It’s too easy to write compared to how dangerous it is. Implicit as a modifier will go away, and with it this kind of conversion.
  27. 27. #1 Delegates The only way to express implicit conversions is as a delegate for a standard Conversion class: delegate for Conversion[String, Token] { def apply(str: String): Token = new KeyWord(str) } Or, using an alias delegate: delegate for Conversion[String, Token] = new KeyWord(_)
  28. 28. The public vote:
  29. 29. Why Delegates? Implicits are Scala’s most distinguished feature. But they are also the most controversial one. Delegates are a simpler and safer alternative. They • emphasize intent over mechanism • make idea of term inference more accessible • discourage abuses
  30. 30. Why Delegates? Many improvements over current implicits, including: • names don’t matter • nesting is significant à local coherence is easy • no shadowing problems • restricted implicit scope avoids surprises • more robust prioritization • no accidental conversions • better error messages à More details Fri 9am at the Typelevel summit
  31. 31. The Hardest Thing… … was naming them! The design of delegates has been solid for 6 months, but how do we call these terms that get inferred for types? We went through a long list of names: In the end, it will not matter, just need a noun that’s easy to remember. witness evidence instance impl repr assume representative delegate implied implicit
  32. 32. Nicest Features for Experts? • Since Scala 3 puts Meta Programming on a new basis, there is lots to choose from. • Difficult to pick a winner. ?
  33. 33. #3 Match Types • Match types can be recursive. • More straightforward than using implicits (c.f. HLists). • Work in type checking is still in progress enum Tuple { case Empty case Pair[Hd, Tl] } import Tuple._ type Concat[+Xs <: Tuple, +Ys <: Tuple] <: Tuple = Xs match { case Empty => Ys case Pair[x, xs] => Pair[x, Concat[xs, Ys]] }
  34. 34. #2 Typeclass Derivation enum Tree[T] derives Eql, Ordering, Pickling { case Branch(left: Tree[T], right: Tree[T]) case Leaf(elem: T) } delegate [T: Eql] for Eql[Tree[T]] = Eql.derived delegate [T: Ordering] for Ordering[Tree[T]] = Ordering.derived delegate [T: Pickling] for Pickling[Tree[T]] = Pickling.derived this generates: where typeclasses define “derived” methods. à Talk by Miles Sabin, Wed 15.30
  35. 35. #2 Typeclass Derivation “derived” methods use match types, inline and macros to do their work object Eq { inline def derived[T] given (mirror: Mirror.Of[T]): Eq[T] = new Eq[T] { def eql(x: T, y: T): Boolean = inline mirror match { case m: Mirror.SumOf[T] => val ord = m.ordinal(x) ord == m.ordinal(y) && eqlCases[m.ElemTypes](0)(x, y, ord) case m: Mirror.ProductOf[T] => eqlElems[m.ElemTypes](0)(x, y) } } à Talk by Nicolas Stucki, Thu 11.15
  36. 36. #1 Functions Everywhere Scala distinguishes methods from functions. Scala 3 lifts three fundamental capabilities from one to the other. Function types can be: • dependent: • polymorphic: • implicit: trait Graph { type Node; type Edge } type NodeExtractor = (g: Graph) => g.Node type PolyIdentity = [T] => T => T type Executable[T] = given ExecutionContext => T
  37. 37. The public vote: (“functions everywhere” was a write-in from Miles)
  38. 38. Synergies object PostConditions { opaque type Wrap[T] = T def result[T] given (r: Wrap[T]): T = r def (x: T) ensuring [T] (cond: given Wrap[T] => Boolean): T = assert(cond given x) } import PostConditions.{ensuring, result} List(1, 2, 3) .sum .ensuring(result == 6)
  39. 39. Is Scala 3 a New Language?
  40. 40. Is Scala 3 a New Language? Yes! • Many language changes, including feature removals. • New constructs improve user experience and on-boarding. • Books will have to be rewritten.
  41. 41. Is Scala 3 a New Language? No! • It’s still Scala. • All core constructs remain in place. • Large & practical common subset between Scala 2 and Scala 3. • Programs can cross-build à Dotty compiler, ScalaTest.
  42. 42. Is Scala 3 a New Language? It’s a Process • Scala 3.0 keeps most constructs of 2.13, alongside the new ones. • Some constructs will be deprecated and phased out in the 3.x release train. • This requires some temporary duplication. • End result: a more compact and regular language.
  43. 43. Replacements Exports + toplevel defs for Package objects Delegates for Implicit defs, vals, objects, conversions Extension methods for Implicit classes Inline + staging + for Current macros match types
  44. 44. Why So Many New Features At Once? Scala 3 is when the books will be rewritten. Need to get it in now if • it affects foundations, • it simplifies life, especially for learners, • it replaces existing features.
  45. 45. Why So Many New Features At Once? Hence, prioritize - Foundations - Simplifications (for developers) - Restrictions over added power and expressiveness
  46. 46. How to Get There? • Source compatibility for a large common subset. • Rewrite tools can handle much of the rest • Situation better than for Python 2 vs 3 because of static typing & binary compatibility. à Talk by Lukas Rytz, Wed 16.45
  47. 47. Binary Compatibility today: Dotty can link with Scala-2.12 class files. Scala 2 module Dotty module
  48. 48. Binary Compatibility today: Dotty can link with Scala-2.12 class files. Scala 2 module Dotty module in the works: Two way compatibility using Tasty as common intermediate format. Scala 2 module Scala 3 module
  49. 49. Tasty At The Core Tasty .scala (2.x) .scala (3.x) .class (Java 8) .js .class (Java 11) .out macros analyzers optimizers IDE LSP à Talk by Gullaume Martres, Wed 10.15
  50. 50. Binary Compatibility For Scala 3 • The plan is to keep the Tasty format binary compatible over the whole 3.x series. • Compile-from Tasty then allows code to migrate without the current problems of binary compatibility.
  51. 51. Try it out: Thank You