Move fast and
refactor with
scalafix

- Ólafur Páll Geirsson, Scala Center
@olafurpg

About me

  • Devtools for ~2 years
  • 65% employed at Scala Center
  • 35% experimenting with stuff

Scala Center

"For open source. For education."

scalafmt

scalafix

Agenda

  1. Motivation
  2. Tool demo
  3. How it works
  4. Rewrite demo

1. Why?

"define a migration path
from Scala 2.x to Dotty"

-- May 9th, 2016 - Scala Center Advisory Board

Move fast and
break
things

Move fast and
break refactor
things

Scala => Scala

Explicit type annotations

any2stringadd

Function arity adaptation

language.postfixOps

Library => Library

Xor => Either

fs2.Task => IO

Cross-build cats/scalaz

-deprecated

2. Tool demo

Step 1:


$ git clone https://github.com/arktekk/linx
// project/plugins.sbt
addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.1.0-RC4")
// build.sbt
scalaVersion := dottyLatestNightlyBuild
$ sbt compile
-- Error: linx/shared/src/main/scala/linx/Linx.scala:42:15 ----
42 |  implicit def VarOps[A, X]() = new VarOps[A, X](l)
   |  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |  implicit definition needs explicit type

Step 2:


// project/plugins.sbt
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.3.2")
$ sbt "scalafix Dotty"

Step 3:


$ git diff
-  VarOps[A, X]() = new VarOps[A, X](l)
+  VarOps[A, X](): Linx.VarOps[A, X] = new VarOps[A, X](l)

Profit

Coming soon!

> scalafix org/repo/v1.0

Compared with
perl/bash?

Compared with
intellij-scala?

  • Types/Symbols from scalac
  • CLI-first (batch)
  • I'm excited to see IntelliJ Migrators API

Compared with
scala-refactoring?

  • Built with scalameta
  • CLI-first (batch)
Syntax Semantic
perl/bash n/a n/a
scala-refactoring scalac scalac
scalameta custom scalac
intellij-scala custom custom

3. How does
scalafix work?

scalafix ♥️ scalameta

Scalameta Semantic DB

Semantic DB Example


    val lst = List[Int](1, x, 3).filter(y => y > 2).headOption

[32..36): List => _root_.scala.collection.immutable.List.apply(Lscala/collection/Seq;)Lscala/collection/immutable/List;.
[37..40): Int => _root_.scala.Int#
[48..54): filter => _root_.scala.collection.TraversableLike#filter(Lscala/Function1;)Ljava/lang/Object;.
[57..58): > => _root_.scala.Int#`>`(I)Z.
[62..72): headOption => _root_.scala.collection.TraversableLike#headOption()Lscala/Option;.

Rewrite: Semantic DB => Patch

Rewrite

  • Rewrite.apply("object code")
  • Rewrite.diff("object code")

Patch

  • RenameSymbol
  • AddImport
  • RemoveToken
  • ...

4. Library demo


- List(1, 2).filter(_ > 2).headOption
+ List(1, 2).find(_ > 2)

Summary

  • Move fast and refactor things
  • Scalafix rewrites are easy to
    • write
    • publish
    • consume

THANK YOU

- Visit documentation: scalacenter.github.io/scalafix
- Contribute with ideas, reporting issues and PRs.
- Follow @olafurpg on Twitter.
- Chat on Gitter.