Move fast and fix things

Move fast and fix things

An introduction to Scalafix, presented at Scala World 2017

C2bb0454c4af1a61e7f173d54ce17b0b?s=128

Gabriele Petronella

September 19, 2017
Tweet

Transcript

  1. Move fast and BREAK FIX things

  2. ME, HI!

  3. STUFF I DO (BY DAY)

  4. STUFF I DO (BY NIGHT) https://astexplorer.net/ https://github.com/gabro/vscode-scalafmt https://github.com/scalacenter/scalafix

  5. AGENDA 1. Intro and context 2. ASTs and related workflows

    3. Scalameta 4. Scalafix 5. Live examples
  6. WHAT IS SCALAFIX Scalafix is a rewrite and linting tool

    for Scala — scalacenter.github.io/scalafix
  7. EXAMPLE 1 - NOPROCEDURESYNTAX // before def main(args: Seq[String]) {

    println("Hello world!") } // after def main(args: Seq[String]): Unit = { println("Hello world!") }
  8. EXAMPLE 2 - NOAUTOTUPLING // before def someMethod(t: (Int, String))

    = ??? someMethod(1, "something") // after def someMethod(t: (Int, String)) = ??? someMethod((1, "something"))
  9. EXAMPLE 3 - REMOVECARTESIANBUILDER // before import cats.syntax.cartesian._ val o1:

    Option[Int] = Some(42) val o2: Option[String] = Some("hello") o1 |@| o2 map (_ + _) // after import cats.syntax.apply._ val o1: Option[Int] = Some(42) val o2: Option[String] = Some("hello") (o1, o2).mapN(_ + _)
  10. EXAMPLE 4 - NOINFER val myList = List(Some(42), Right("foo")) //

    ^ // |__ ⚠ Product with Serializable
  11. LET'S TALK ABOUT MAINTAINERS

  12. PURE EVIL BREAK CODE WITHOUT DOCUMENTING WHAT BROKE

  13. MILD EVIL BREAK CODE DOCUMENTING WHAT BROKE (OR LINKING TO

    A SUPER-LONG ISSUE)
  14. GOOD EFFORT BREAK CODE AND DOCUMENT HOW TO FIX IT

  15. YOU ROCK! BREAK CODE AFTER A DEPRECATION CYCLE AND EXPLAIN

    HOW TO FIX IT
  16. SUPERHERO BREAK CODE AFTER A DEPRECATION CYCLE AND PROVIDE AN

    AUTOMATIC REWRITE
  17. SCI-FI?

  18. MEANWHILE IN SWIFT

  19. MEANWHILE IN JAVASCRIPT

  20. MEANWHILE IN JAVASCRIPT 3 paragraphs later

  21. The JS tooling landscape is living in the future —

    Ólafur Páll Geirsson, author of Scalafix
  22. IT'S TIME WE JUMP INTO THE FUTURE

  23. HOW? LET'S TAKE A STEP BACK

  24. A QUICK PRIMER TO THE AST

  25. LET'S START FROM THE ANSWER val answer = 42

  26. TOKENS val answer = 42 // | | | |

    | | | | // \_'val'_/ \_Name_/ \_'='_/ \_Literal_/
  27. GRAMMAR val answer = 42 // | | | |

    | | | | // | | \__Term.Name__/ | \_Lit.Int_/ | // | | | | // | \_____Pat.Var.Term__/ | // | | // \_____________________Defn.Val____________________/
  28. SO... AST?

  29. ABSTRACT SYNTAX TREE

  30. WHY ABSTRACT?

  31. val answer = 42; val answer = 42 val answer

    = 42 val answer = 42
  32. None
  33. ASTS... WHY SHOULD I CARE?

  34. AST WORKFLOW 1: SCALAC

  35. AST WORKFLOW 2: MACROS

  36. AST WORKFLOW 3: SCALAFMT

  37. AST WORKFLOW 4: SCALAFIX

  38. AST WORKFLOW 4: SCALAFIX Woops, copy-paste?

  39. WHAT SCALAFIX COULD DO: // before def someMethod(string: String) {

    // I like trees println(string.trim.split("/").lastOption) } // after def someMethod(string: String): Unit = println( string .trim .split("/") .lastOption )
  40. None
  41. WHAT SCALAFIX DOES INSTEAD: // before def someMethod(string: String) {

    // I like trees println(string.trim.split("/").lastOption) } // after def someMethod(string: String): Unit = { // I like trees println(string.trim.split("/").lastOption) }
  42. "AST" WORKFLOW 4: SCALAFIX

  43. OK, LET'S DO THIS!

  44. None
  45. Introducing SCALAMETA

  46. Scalameta is a modern metaprogramming library for Scala — scalameta.org

  47. METAPROGRAMMING?

  48. METAPROGRAMMING DEVTOOLS! ▸ code formatting ▸ code fixing ▸ code

    browsing ▸ and many more applications!
  49. SCALAMETA VADEMECUM ▸ Trees ▸ Tokens ▸ Parser ▸ Tree

    manipulation primitives ▸ Semantic API ▸ (pretty-printer)
  50. TOKENS The "atoms"

  51. TREES The fundamental data structure

  52. PARSER ! ➡ # several dialects

  53. TREE MANIPULATION PRIMITIVES ▸ transform ▸ traverse ▸ collect

  54. SEMANTIC API: DATABASE ▸ Names ▸ Symbols ▸ Messages ▸

    Synthetics
  55. SEMANTIC API: NAMES package scalaworld.semantic Names: [8..18): scalaworld => _root_.scalaworld.

    [19..27): semantic => _root_.scalaworld.semantic.
  56. SEMANTIC API: SYMBOLS List(1, 2, 3).head Symbols: _root_.scala.collection.immutable.List. => final

    object List _root_.scala.collection.IterableLike#head()Ljava/lang/Object;. => def head: A
  57. SEMANTIC API: MESSAGES object A { 1 + 1 }

    Messages: [140..145): [warning] a pure expression does nothing in statement position; you may be omitting necessary parentheses
  58. SEMANTIC API: SYNTHETICS (SUGARS) List(1, 2, 3) Synthetics: [2..7): apply

    => _root_.scala.collection.immutable.List.apply (Lscala/collection/Seq;) [8..11): Int => _root_.scala.Int# List.apply[Int](1, 2, 3)
  59. RECAP List(1, 2, 3) // Symbol _root_.scala.collection.immutable.List. // Denotation final

    object List // Synthetic [2..7): apply => _root_.scala.collection.immutable.List.apply (Lscala/collection/Seq;)
  60. None
  61. SCALAFIX FINALLY!

  62. Rule Rewrite

  63. Rule A rule can be: ▸ checked ▸ fixed

  64. Patch

  65. Patch A Scalafix Patch is a patch in the diff

    sense of patch. It boils down to a list of -/+ to apply to the source code.
  66. LintMessage LintCategory

  67. LintMessage / LintCategory A LintMessage is a warning/error that gets

    displayed to the user. Each LintMessage belongs to LintCategory (e.g. "MissingExplicitType" )
  68. RuleCtx

  69. RuleCtx The toolbox for writing rules. It provides the API

    for producing patches.
  70. SemanticdbIndex

  71. SemanticdbIndex A index for looking up data in a scalameta's

    Semantic Database. It contains all the available semantic information.
  72. None
  73. LIVE

  74. WHAT'S NEXT?

  75. SHORT-TERM ▸ more linter rules ▸ rule "bundles" ▸ more

    robust expansion of inferred types / implicits
  76. MEDIUM TERM ▸ editor integrations ▸ stable API ▸ docs

  77. None
  78. Questions? @gabro27 @buildoHQ @ScalaItaly