Tooling for scala 3
Dotty support in Metals
Tomasz Godzik
Some fun new concepts
Besides:
- simplified pattern matching
- better macros
- enums
- focus on ease of migration
- implicit suggestions
- a lot of even more modern features
THE FUTURE OR SCALA 3
trait A:
def f: Int
class C(x: Int) extends A:
def f = x
object O:
def f = 3
Optional braces
val x: String = ???
val y: String | Null = ???
x == null // error
x eq null // error
"hello" == null // error
y == null // ok
y == x // ok
explicit nulls
@main def helloWorld(
age: Int,
name: String,
others: String*
) = {
println(s"Hello $name!")
println(s"You are $age years old")
}
outer methods
case class Circle(
x: Double,
y: Double,
radius: Double
)
def (c: Circle).circumference: Double =
c.radius * math.Pi * 2
Extension methods
scalameta parser
- basis for a number of developer's tools
- works without the compiler
- fast
- has an easily understandable AST
- a lot projects depending on it
extension (c: Circle)
def shapeName = "Circle"
Source(
stats = List(
Defn.ExtensionGroup(
eparam = Term.Param(
mods = List(),
name = Term.Name(value = "c"),
decltpe = Some(value = Type.Name(value = "Circle")),
default = None
),
tparams = List(),
uparams = List(),
body = Defn.Def(
mods = List(),
name = Term.Name(value = "shapeName"),
tparams = List(),
paramss = List(),
decltpe = None,
body = Lit.String(value = "Circle")
)
)
)
)
scalameta parser
enum ListEnum {
enum ListEnum[+A] {
case Cons(h: A, t: ListEnum[A])
case Empty
}
}
Document outline
Worksheets
scalameta parser
Parser Scala when used with the scala3 dialect
optional braces support
all the new features supported
scalameta parser
scala.meta.parser.dotty.CommunityDottySuite:
From https://github.com/lampepfl/dotty
a0707985bf..1f503e7868 master -> origin/master
e8cfbb381f..45b8dc0f9e release-3.0.0 -> origin/release-3.0.0
HEAD is now at 13de192d04 Merge pull request #11958 from lampepfl/derived-names-mac
--------------------------
dotty
Files parsed correctly 828
Files errored: 0
Time taken: 14989ms
Lines parsed: ~190k
Parsing speed per 1k lines ===> 78 ms/1klines
--------------------------
+ community-build-dotty 17.179s
scalafmt
- important to keep consistent style for a team
- runs on CI
- can be considered a blocker to Scala 3 migration
object Main:
def main(args: Array[String]) =
val name: Option[String] = Some("AVeryLongString")
name
match
case None => println("Hello <unknown>")
case Some(x) => println(s"Hello $x")
object Main:
def main(args: Array[String]) =
val name: Option[String] =
Some("AVeryLongString")
name
match
case None => println("Hello <unknown>")
case Some(x) => println(s"Hello $x")
scalafmt
version = 3.0.0-RC1
runner.dialect = scala3
indent.main = 3
scalafmt
version = 3.0.0-RC1
fileOverride {
"glob:**/scala-3*/**" {
runner.dialect = scala3
indent.main = 3
}
}
scalafmt
def hello(name: String): Unit = {
val greeting = s"Hello $name"
println(greeting)
}
Rewrite - drop braces
def hello(name: String): Unit =
val greeting = s"Hello $name"
println(greeting)
scalafmt
import scala.meta.{Main => Metals}
import scala.meta._
object Main{}
Rewrite - New syntax
import scala.meta.Main as Metals
import scala.meta.*
object Main{}
mdoc
```scala mdoc
val x = 1
val y = 2
x + y
```
```scala
val x = 1
// x: Int = 1
val y = 2
// y: Int = 2
x + y
// res0: Int = 3
```
after
Before
mdoc
```scala mdoc:crash
val y = ???
```
```scala
val y = ???
// scala.NotImplementedError: an implementation is missing
// at scala.Predef$.$qmark$qmark$qmark(Predef.scala:288)
// at repl.MdocSession$App$$anonfun$1.apply$mcV$sp(modifiers.md:9)
// at repl.MdocSession$App$$anonfun$1.apply(modifiers.md:8)
// at repl.MdocSession$App$$anonfun$1.apply(modifiers.md:8)
```
after
Before
mdoc
```scala mdoc:scalafmt
indent.callSite = 2
---
function(
argument1, // indented by 2
""
)
```
```scala formatted
function(
argument1, // indented by 2
""
)
```
```scala original
function(
argument1, // indented by 2
""
)
```
<details class='config' open><summary>Config for this example:</summary><p>
```scala config
continuationIndent.callSite = 2
```
</p></details>
after
Before
mdoc
scaladoc
Typechecked scaladoc snippets
```scala sc:failing
val iAmWrong: Int = 2.3
for(i ← 1.to(10))
yield i*2
```
Borrows ideas and code from mdoc
But inside the compile
scalafix
import scala.List
import scala.collection.{immutable, mutable}
object Foo { immutable.Seq.empty[Int] }
import scala.collection.immutable
object Foo { immutable.Seq.empty[Int] }
before
after
scalafix
scalafix
import scala.meta._
import scala.collection.{mutable => mut}
object Main {}
import scala.meta.*
import scala.collection.mutable as mut
object Main {}
before
after
Your favourite language in you favourite Editor
Metals
Scala 3 support
Metals
Scala 3 Inline
Metals
inline def power(x: Double, n: Int): Double =
if n == 0 then 1.0
else if n == 1 then x
else
val y = power(x, n / 2)
if n % 2 == 0 then y * y else y * y * x
Scala 3 auto importing implicits
Metals
Tasty!
Metals
+-------------+ +-------------+ +-------------+
$ scalac | Hello.scala | -> | Hello.tasty | -> | Hello.class |
+-------------+ +-------------+ +-------------+
^ ^ ^
| | |
Your source TASTy file Class file
code for scalac for the JVM
(contains (incomplete
complete information)
information)
MAcros
Metals
import scala.quoted.*
inline def assert(inline expr: Boolean): Unit =
${ assertImpl('expr) }
def assertImpl(expr: Expr[Boolean])(using Quotes) = '{
if !$expr then
throw AssertionError(s"failed assertion: ${${ showExpr(expr) }}")
}
def showExpr(expr: Expr[Boolean])(using Quotes): Expr[String] =
'{ "<some source code>" } // Better implementation later in this document
ScalaJS
ScalaJS
currently Implemented inside Scala 3 compiler
reuses most of existing code
Implemented in 3 months!
not outstanding issues
Scala native
Scala native
Windows support
multithreading
scala 3
Scala 3 will be amazing!
Question to Martin
What new tooling feature would you love to see implemented when it comes to Scala 3, but that did not exist in Scala 2?
Release party
By Tomek Godzik
Release party
- 191