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.

Scala 3 Is Coming: Martin Odersky Shares What To Know

5,250 views

Published on

Join Dr. Martin Odersky, the creator of Scala and co-founder of Lightbend, on a tour of what is in store and highlight some of his favorite features of Scala 3!

Published in: Software
  • Login to see the comments

Scala 3 Is Coming: Martin Odersky Shares What To Know

  1. 1. Scala 3 Is Coming By Martin Odersky July 11th, 2019
  2. 2. 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
  3. 3. A Tour of Scala 3
  4. 4. What Changes? Docs for all changes and new features at https://dotty.epfl.ch/docs/reference/overview.html
  5. 5. ? 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. ? ?
  6. 6. Nicest Features for Beginners? • At that level, most of the language stays the same • But there are nevertheless a few improvements worth mentioning … ?
  7. 7. #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()
  8. 8. #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)
  9. 9. #1 Enums enum Color { case Red, Green, Blue } Simplest way to define new types with a finite number of values or constructors.
  10. 10. #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) ... }
  11. 11. #1 Enums can have type parameters, making them algebraic data types (ADTs) enum Option[+T] { case Some(x: T) case None }
  12. 12. #1 Enums compile to sealed hierarchies of case classes and singletons. sealed abstract class Option[+T] object Option { case class Some[+T](x: T) extends Option[T] val None = new Option[Nothing] { ... } }
  13. 13. #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] }
  14. 14. The public vote:
  15. 15. Why Enums? • Lots of use cases, and they are becoming more common. • Avoids boring, repetitive boilerplate. • Can grow from very simple to very powerful.
  16. 16. Nicest Features for Everyday Coding? • There are lots of candidates. • Hard to come up with a shortlist. ?
  17. 17. #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) } ... }
  18. 18. #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() }
  19. 19. #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
  20. 20. #1 Givens 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 } given IntOrd as 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)
  21. 21. New Design Principles • Core concept: term inference. • Given a type, produce a canonical term of that type “Trade types for terms” • Instead of adding implicit as a modifier to many different constructs, changing the meaning of each in slightly different ways, have a single construct to introduce a designated term that can be inferred for a type. • We call these terms “given instances” or just “givens”.
  22. 22. Typeclasses Givens 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 } given as 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(_))
  23. 23. Implicit Conversions implicit def intToStr(str: String): Token = new Keyword(str) Givens 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.
  24. 24. Conversion Instances The only way to express implicit conversions is as a given instance of a standard Conversion class: given as Conversion[String, Token] { def apply(str: String): Token = new KeyWord(str) } Or, using an alias: given as Conversion[String, Token] = new KeyWord(_)
  25. 25. The public vote:
  26. 26. Why “Given”? Implicits are Scala’s most distinguished feature. But they are also the most controversial one. Given instances are a simpler and safer alternative. They • emphasize intent over mechanism • make idea of term inference more accessible • discourage abuses
  27. 27. Why “Given”? 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 in my Typelevel Lausanne keynote
  28. 28. Migration • Current implicits are still supported in Scala 3.0 • Will probably be deprecated from Scala 3.1 on. • Special provisions are made for cross compilation: - given arguments also work for old style implicits - given imports also import old style implicits • This allows to migrate user code before libraries are moved over.
  29. 29. 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
  30. 30. 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. ?
  31. 31. #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]] }
  32. 32. #2 Typeclass Derivation enum Tree[T] derives Eql, Ordering, Pickling { case Branch(left: Tree[T], right: Tree[T]) case Leaf(elem: T) } given [T: Eql] as Eql[Tree[T]] = Eql.derived given [T: Ordering] as Ordering[Tree[T]] = Ordering.derived given [T: Pickling] as Pickling[Tree[T]] = Pickling.derived this generates: where typeclasses define “derived” methods.  ScalaDays Talk by Miles Sabin
  33. 33. #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) } }  ScalaDays Talk by Nicolas Stucki
  34. 34. #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
  35. 35. The public vote: (“functions everywhere” was a write-in from Miles)
  36. 36. 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)
  37. 37. Is Scala 3 a New Language?
  38. 38. 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.
  39. 39. 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.
  40. 40. 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.
  41. 41. Replacements Exports + toplevel defs for Package objects Givens for Implicit defs, vals, objects, conversions Extension methods for Implicit classes Inline + staging + for Current macros match types
  42. 42. 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.
  43. 43. Why So Many New Features At Once? Hence, prioritize - Foundations - Simplifications (for developers) - Restrictions over added power and expressiveness
  44. 44. 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
  45. 45. Binary Compatibility today: Dotty can link with Scala-2.12 class files. Scala 2 module Dotty module
  46. 46. 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
  47. 47. 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
  48. 48. 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.
  49. 49. Try it out: dotty.epfl.ch Thank You

×