@@ -6,36 +6,42 @@ title: "Refactor with scalafix v0.3"
6
6
---
7
7
8
8
I am happy to announce the release of [ scalafix v0.3] [ scalafix ] .
9
- This release leverages the new scala.meta semantic API to provide a re-designed ` Rewrite ` and ` Patch ` API for refactorings.
9
+ This release uses the new scala.meta semantic API to provide a re-designed ` Rewrite ` and ` Patch ` API for refactorings.
10
10
Let me explain what that means word by word.
11
11
12
- ## scala.meta semantic API
12
+ > Note. This is the second post on scalafix and scala.meta. You might be
13
+ > interested in reading the first post
14
+ > [ here] ( http://scala-lang.org/blog/2016/10/24/scalafix.html ) .
15
+
16
+ ## Scala.meta semantic API
13
17
14
18
Scala.meta recently announced the [ first release of its semantic API] [ meta-1.6 ] .
15
19
This release is the product of close collaboration for the past several months between
16
- [ @xeno-by ] ( https://twitter.com/ xeno_by) at Twitter and myself at the Scala Center.
17
- The semantic API provides operations to query information from the compiler.
20
+ [ @xeno_by] [ ] at Twitter and [ myself] [ @olafurpg ] at the Scala Center.
21
+ The objective of the semantic API is to provide operations to query information from the compiler.
18
22
19
- The first version of the scala.meta semantic API makes it possible to query for the "symbol" of a name that appears in a Scala source file.
20
- A symbol is a unique identifier of a definition such as a class, val, def or trait.
21
- For example, the symbol of ` println ` from the standard library is ` _root_.scala.Predef.println(Ljava/lang/Object;)V ` .
23
+ The first version of the scala.meta semantic API makes it possible to query for the resolved "symbol" of a name that appears in a Scala source file.
24
+ A name is a reference to some definition, for example ` println ` or ` scala.Predef.println ` .
25
+ A symbol is a unique identifier of a single definition.
26
+ For example, ` println ` from the standard library has the symbol ` _root_.scala.Predef.println(Ljava/lang/Object;)V. ` .
27
+ The compiler is responsible for resolving names to symbols.
22
28
23
- Symbols are created by "scalahost", a compiler plugin .
24
- Scalahost emits symbols of a source file in the form of a "semantic database".
29
+ Scalahost is a compiler plugin in the scala.meta project that extracts symbols from the compiler and maps them to scala.meta syntax trees .
30
+ Scalahost emits the extracted symbols into a "semantic database".
25
31
The semantic database can be persisted to files on disk and loaded for later analysis.
26
32
Semantic databases from different compilation units, potentially produced by different
27
33
versions of the Scala compiler, can be merged.
28
34
This opens possibilities for large-scale code analysis.
29
35
30
36
The introduction of the scala.meta semantic API is a game changer for scalafix.
31
- The ability to query for symbols open possibilities for many scalafix rewrites.
37
+ The ability to resolve names to symbols opens possibilities for many scalafix rewrites.
32
38
33
39
## Rewrite: meta.Tree => Seq[ Patch]
34
40
35
41
A scalafix ` Patch ` is a small operation that can produce a diff on a Scala source file.
36
42
A patch can either be a "token patch" or a "tree patch".
37
43
38
- Token patches are low-level but give full control of how small details are handled in a source files , for example formatting and comments
44
+ Token patches are low-level but give full control over how every detail in a source file is handled , for example formatting and comments.
39
45
Example token patches are ` Remove(token) ` and ` AddLeft(token, toAdd: String) ` , which removes or prepends a string to ` token ` , respectively.
40
46
41
47
Tree patches are high-level and allow rewrite author to declaratively explain what operation to perform.
@@ -46,8 +52,8 @@ Tree and token patches build a small algebra of operations that can be composed
46
52
A challenge with composing patches is to figure out what to do on conflicts.
47
53
For example, what happens when one patch renames a token while the other patch removes the same token?
48
54
The current strategy in scalafix is to try and resolve as many conflicts as possible on the tree patch level.
49
- Once we we only have token patches, it is harder to resolve conflicts .
50
- Unsolvable conflicts on the token level abort the refactoring.
55
+ It can be harder to resolve conflicts on the token level since the original intent of the patch is lost .
56
+ Unsolvable conflicts abort the refactoring.
51
57
In the future, we hope to support more advanced conflict resolution strategies.
52
58
53
59
In a nutshell, a scalafix ` Rewrite ` is a ` scala.meta.Tree => Seq[Patch] ` function.
@@ -56,9 +62,9 @@ To demonstrate how rewrites are implemented with scalafix v0.3, let's step throu
56
62
57
63
## Example: Xor to Either
58
64
59
- The functional programming library [ cats] [ cats ] migrated recently from its ` Xor ` data type to ` Either ` from the standard library.
65
+ The functional programming library [ cats] [ ] migrated recently from its ` Xor ` data type to ` Either ` from the standard library.
60
66
It requires a few mechanical steps to migrate code to use ` Either ` instead of ` Xor ` .
61
- For example, below is a diff that's taken from [ circe] [ xor-circe ] 's migration to ` Either ` .
67
+ For example, below is a diff that's taken from [ circe] [ ] 's migration to ` Either ` .
62
68
63
69
``` diff
64
70
- final def either: Xor[HCursor, HCursor] = if (succeeded) Xor.right(any) else Xor.left(any)
@@ -108,30 +114,37 @@ The recommended way to use scalafix as tool is the [`sbt-scalafix`][sbt-scalafix
108
114
It's possible define custom tree patches in the [ ` .scalafix.conf ` configuration file] [ config-patches ] .
109
115
110
116
The long-term mission of scalafix is to help automate the migration of deprecated Scala 2.x features to Dotty.
111
- However, as I have hopefully demonstrated in this post, scalafix can be used for more than just migrating between Scala versions.
117
+ However, as I have demonstrated in this post, scalafix can be used for more than just migrating between Scala versions.
112
118
Scalafix can also be used for ad-hoc library and application migrations.
113
119
114
120
I am excited to see what applications the community can build with scala.meta and scalafix.
115
121
Some promising ideas that have floated around include
116
122
117
- - parse and run rewrites from ` @deprecated ` warning messages. This would enable library authors
118
- to provide exectuable migration guides.
119
- - use scalafix to cross-build against multiple similar APIs. For example, a
120
- library author could write against scalaz and rewrite to cats.
123
+ - parse and run rewrites from ` @deprecated ` warning messages. This would enable
124
+ library authors to provide executable migration guides.
125
+ - shim/cross-build libraries with similar APIs. For example,
126
+ a library could be developed with the scalaz API, and use scalafix to
127
+ code-generate a version of the library that uses cats instead.
121
128
- build a code search web-interface with "jump to definition" functionality
122
129
powered by the scala.meta's semantic database.
123
- - replace usage of the infamous ` any2StringAdd ` in favor of string interpolators or explicit ` .toString ` .
124
- - replace usages of ` scala.Seq ` , which can be mutable, in favor of ` scala.collection.immutable.Seq ` .
130
+ - replace usage of ` scala.Seq ` , which can be mutable, in favor of ` scala.collection.immutable.Seq ` .
125
131
126
132
If this sounds exciting to you, join us!
127
133
I am happy to answer any question in the [ scalafix gitter] [ gitter ] channel.
128
134
135
+ PS. I want to thank [ @ShaneDelmore ] [ ] who has provided invaluable feedback from
136
+ the early days of scalafix development and come up with several brilliant ideas
137
+ for scalafix use-cases.
138
+
139
+
140
+ [ @ShaneDelmore ] : https://twitter.com/ShaneDelmore
141
+ [ @olafurpg ] : https://twitter.com/olafurpg
142
+ [ @xeno_by ] : https://twitter.com/xeno_by
129
143
[ xor2either-test ] : https://github.com/scalacenter/scalafix/blob/f61136fad79afcdbb03528ce78c7928afc6eafd6/scalafix-nsc/src/test/resources/syntactic/Xor2Either.source
130
144
[ xor2either ] : https://github.com/scalacenter/scalafix/blob/f61136fad79afcdbb03528ce78c7928afc6eafd6/core/src/main/scala/scalafix/rewrite/Xor2Either.scala
131
- [ xor- circe] : https://github.com/circe/circe/pull/343/files
145
+ [ circe ] : https://github.com/circe/circe/pull/343/files
132
146
[ cats ] : http://github.com/typelevel/cats
133
147
[ ghpages ] : http://github.com/scalacenter/scalafix
134
- [ prevpost ] : http://scala-lang.org/blog/2016/10/24/scalafix.html
135
148
[ scalafix ] : https://scalacenter.github.io/scalafix/#0.3.0
136
149
[ sbt-scalafix ] : https://scalacenter.github.io/scalafix/#sbt-scalafix
137
150
[ sbt-scalahost ] : https://scalacenter.github.io/scalafix/#sbt-scalahost
0 commit comments