|
| 1 | +--- |
| 2 | +layout: blog-page |
| 3 | +title: Announcing Dotty 0.2.0-RC1, with new optimizations, improved stability and IDE support |
| 4 | +author: Dmytro Petrashko |
| 5 | +authorImg: /images/petrashko.jpg |
| 6 | +date: 2017-05-31 |
| 7 | +--- |
| 8 | + |
| 9 | +Today, we are excited to release Dotty version 0.2.0-RC1. This release |
| 10 | +serves as a technology preview that demonstrates new language features |
| 11 | +and the compiler supporting them. |
| 12 | + |
| 13 | +This release is based on [previous milestone](/blog/2017/05/31/first-dotty-milestone-release.html). |
| 14 | +The highlights of this release are: |
| 15 | + - substantial improvement of quality of generated code for pattern matching |
| 16 | + - improvements in VS Code IDE stability |
| 17 | + - improved compatibility with scalac |
| 18 | + - initial support for reproducible builds |
| 19 | + |
| 20 | + |
| 21 | +<!--more--> |
| 22 | + |
| 23 | +This is our second scheduled release according to our [6-week release schedule](http://dotty.epfl.ch/docs/usage/version-numbers.html). |
| 24 | + |
| 25 | +# What’s in the 0.2.0-RC1 technology preview? |
| 26 | +The [previous technology preview](/blog/2017/05/31/first-dotty-milestone-release.html) has shipped new language planned for Scala 3: |
| 27 | +[Intersection Types](http://dotty.epfl.ch/docs/reference/intersection-types.html), |
| 28 | +[Union Types](http://dotty.epfl.ch/docs/reference/union-types.html), |
| 29 | +[Trait Parameters](http://dotty.epfl.ch/docs/reference/trait-parameters.html), |
| 30 | +[Enumerations](http://dotty.epfl.ch/docs/reference/enums/enums.html), |
| 31 | +[Algebraic Data Types](http://dotty.epfl.ch/docs/reference/enums/adts.html), |
| 32 | +[By-Name Implicits](http://dotty.epfl.ch/docs/reference/implicit-by-name-parameters.html). |
| 33 | + |
| 34 | +This technology preview is geared towards improving stability and reliability. It includes: |
| 35 | + |
| 36 | + - [Local optimizations upstreamed from Dotty Linker](https://github.com/lampepfl/dotty/pull/2513), [2647](https://github.com/lampepfl/dotty/pull/2647) by ([@OlivierBlanvillain](https://github.com/OlivierBlanvillain). See more details below. |
| 37 | + - [Optimizing Pattern Matcher](https://github.com/lampepfl/dotty/pull/2829) by ([@odersky](https://github.com/odersky) |
| 38 | + - [Idempotency checks](https://github.com/lampepfl/dotty/pull/2756) are the first step to reproducible builds |
| 39 | + - [Faster Base class sets](https://github.com/lampepfl/dotty/pull/2676) by ([@odersky](https://github.com/odersky) and ([@darkdimius](https://twitter.com/darkdimius) |
| 40 | + - Huge number of fixes to IDE and Dotty Language Server covering: |
| 41 | + |
| 42 | + - [Fix hover-on-type for implicitly converted expressions](https://github.com/lampepfl/dotty/pull/2836) |
| 43 | + - [Fixes to find all references in external projects](https://github.com/lampepfl/dotty/pull/2810), [2773](https://github.com/lampepfl/dotty/pull/2773/files) |
| 44 | + - [Fix conflict with dragos-vscode-scala](https://github.com/lampepfl/dotty/pull/2777) |
| 45 | + - [Fix ide crash on non-parsable file](https://github.com/lampepfl/dotty/pull/2752) |
| 46 | + - [Fix hover functionality for enum classes](https://github.com/lampepfl/dotty/pull/2722) |
| 47 | + - [Report errors on Dotty Language Server initialization](https://github.com/lampepfl/dotty/pull/2708) |
| 48 | + - [Fixes to sbt setting up Dotty IDE](https://github.com/lampepfl/dotty/pull/2690) |
| 49 | + - General stability improvements [2838](https://github.com/lampepfl/dotty/pull/2838), [2787](https://github.com/lampepfl/dotty/pull/2787), [2692](https://github.com/lampepfl/dotty/pull/2692) |
| 50 | + |
| 51 | + - Scalac compatibility improvements: |
| 52 | + |
| 53 | + - [Support Scala 2.12 traits](https://github.com/lampepfl/dotty/pull/2685) |
| 54 | + - [Fixes to handling of Scala 2 classfiles](https://github.com/lampepfl/dotty/pull/2834/files) |
| 55 | + - [Scalac parser crashes on Dotty.jar](https://github.com/lampepfl/dotty/pull/2719) |
| 56 | + |
| 57 | + - Java compatibility improvements: |
| 58 | + |
| 59 | + - [Fixes to handing of Java generic signatures](https://github.com/lampepfl/dotty/pull/2831) |
| 60 | + - [java.lang.System.out is final but that's a lie](https://github.com/lampepfl/dotty/pull/2781) |
| 61 | + |
| 62 | + - Improved error messages: |
| 63 | + |
| 64 | + - [Nicer error message for "implicit function type needs non-empty parameter list"](https://github.com/lampepfl/dotty/pull/2821) |
| 65 | + - [Nicer error message for nonsensical modifier combination](https://github.com/lampepfl/dotty/pull/2807/files), [2747](https://github.com/lampepfl/dotty/pull/2747) |
| 66 | + - [Nicer error message for supercall inside @inline method](https://github.com/lampepfl/dotty/pull/2740) |
| 67 | + - [Check that case classes don't inherit case classes](https://github.com/lampepfl/dotty/pull/2790) |
| 68 | + - [Check that named parameters don't conflict with positional ones](https://github.com/lampepfl/dotty/pull/2785) |
| 69 | + |
| 70 | + - Improved command line handling: |
| 71 | + |
| 72 | + - [Support params in a file like @file.txt](https://github.com/lampepfl/dotty/pull/2765) |
| 73 | + |
| 74 | + - Type system stability: |
| 75 | + |
| 76 | + - [Handle wildcard types in unions and intersections](https://github.com/lampepfl/dotty/pull/2742) |
| 77 | + |
| 78 | + - Fixes to implicit search: |
| 79 | + |
| 80 | + - [Fix shadowing of higher order implicits](https://github.com/lampepfl/dotty/pull/2739) |
| 81 | + |
| 82 | + |
| 83 | +## Better generated code: |
| 84 | + |
| 85 | +As was [spotted](https://twitter.com/gkossakowski/status/870243464528744449) by [@gkossakowski](https://twitter.com/gkossakowski) |
| 86 | +In the previous release Dotty was on par with Scala 2.11 in speed. But why is that? |
| 87 | +The reason is that Dotty compiled by dotty had really horrible code generated or pattern matching. |
| 88 | + |
| 89 | +Let's illustrate on a simple example: |
| 90 | + |
| 91 | +``` |
| 92 | +case class CC(a: Int, b: Object) |
| 93 | +
|
| 94 | + def foo(x: Any): Int = { |
| 95 | + val (a, b) = x match { |
| 96 | + case CC(s @ 1, CC(t, _)) => |
| 97 | + (s , 2) |
| 98 | + case _ => (42, 43) |
| 99 | + } |
| 100 | + a + b |
| 101 | + } |
| 102 | + |
| 103 | + def booleans(a: Object) = { |
| 104 | + val (b1, b2) = (a.isInstanceOf[CC], a.isInstanceOf[List[Int]]) |
| 105 | + (b1, b2) match { |
| 106 | + case (true, true) => true |
| 107 | + case (false, false) => true |
| 108 | + case _ => false |
| 109 | + } |
| 110 | + } |
| 111 | +``` |
| 112 | + |
| 113 | + |
| 114 | +Dotty that was released in the previous milestone didn't contain any optimizations and generated horrible code for it. |
| 115 | +The java-with-goto code below is equivalent to what dotty hs generated. |
| 116 | + |
| 117 | +``` |
| 118 | +// output of dotc 0.1.2-RC1 |
| 119 | + public int foo(Object x) { |
| 120 | + var3_2 = x; |
| 121 | + if (!(var3_2 instanceof CC)) ** GOTO lbl-1000 |
| 122 | + var4_3 = (CC)var3_2; |
| 123 | + if (CC$.MODULE$.unapply((CC)var3_2) == null) ** GOTO lbl-1000 |
| 124 | + var5_4 = CC$.MODULE$.unapply((CC)var3_2); |
| 125 | + s = var5_4._1(); |
| 126 | + var7_6 = var5_4._2(); |
| 127 | + if (1 != s) ** GOTO lbl-1000 |
| 128 | + var8_7 = s; |
| 129 | + if (!(var7_6 instanceof CC)) ** GOTO lbl-1000 |
| 130 | + var9_8 = (CC)var7_6; |
| 131 | + if (CC$.MODULE$.unapply((CC)var7_6) != null) { |
| 132 | + var10_9 = CC$.MODULE$.unapply((CC)var7_6); |
| 133 | + var11_10 = var10_9._2(); |
| 134 | + v0 = Tuple2..MODULE$.apply((Object)BoxesRunTime.boxToInteger((int)1), (Object)BoxesRunTime.boxToInteger((int)2)); |
| 135 | + } else lbl-1000: // 5 sources: |
| 136 | + { |
| 137 | + v0 = Tuple2..MODULE$.apply((Object)BoxesRunTime.boxToInteger((int)42), (Object)BoxesRunTime.boxToInteger((int)43)); |
| 138 | + } |
| 139 | + var2_11 = v0; |
| 140 | + a = BoxesRunTime.unboxToInt((Object)var2_11._1()); |
| 141 | + b = BoxesRunTime.unboxToInt((Object)var2_11._2()); |
| 142 | + return a + b; |
| 143 | + } |
| 144 | +
|
| 145 | + public boolean booleans(Object a) { |
| 146 | + Tuple2 tuple2 = Tuple2..MODULE$.apply((Object)BoxesRunTime.boxToBoolean((boolean)(a instanceof CC)), (Object)BoxesRunTime.boxToBoolean((boolean)(a instanceof List))); |
| 147 | + boolean b1 = BoxesRunTime.unboxToBoolean((Object)tuple2._1()); |
| 148 | + boolean b2 = BoxesRunTime.unboxToBoolean((Object)tuple2._2()); |
| 149 | + Tuple2 tuple22 = Tuple2..MODULE$.apply((Object)BoxesRunTime.boxToBoolean((boolean)b1), (Object)BoxesRunTime.boxToBoolean((boolean)b2)); |
| 150 | + Option option = Tuple2..MODULE$.unapply(tuple22); |
| 151 | + if (!option.isEmpty()) { |
| 152 | + Tuple2 tuple23 = (Tuple2)option.get(); |
| 153 | + boolean bl = BoxesRunTime.unboxToBoolean((Object)tuple23._1()); |
| 154 | + boolean bl2 = BoxesRunTime.unboxToBoolean((Object)tuple23._2()); |
| 155 | + if (bl) { |
| 156 | + boolean bl3 = bl; |
| 157 | + if (bl2) { |
| 158 | + boolean bl4 = bl2; |
| 159 | + return true; |
| 160 | + } |
| 161 | + } |
| 162 | + } |
| 163 | + Option option2 = Tuple2..MODULE$.unapply(tuple22); |
| 164 | + if (option2.isEmpty()) return false; |
| 165 | + Tuple2 tuple24 = (Tuple2)option2.get(); |
| 166 | + boolean bl = BoxesRunTime.unboxToBoolean((Object)tuple24._1()); |
| 167 | + boolean bl5 = BoxesRunTime.unboxToBoolean((Object)tuple24._2()); |
| 168 | + if (bl) return false; |
| 169 | + boolean bl6 = bl; |
| 170 | + if (bl5) return false; |
| 171 | + boolean bl7 = bl5; |
| 172 | + return true; |
| 173 | + } |
| 174 | +``` |
| 175 | + |
| 176 | +Due to new optimizing pattern matcher, dotty now is able to generate the code below without `-optimise` |
| 177 | + |
| 178 | +``` |
| 179 | +// output of 0.2.0-RC1 without -optimise |
| 180 | + public int foo(Object x) { |
| 181 | + var3_2 = x; |
| 182 | + if (!(var3_2 instanceof CC)) ** GOTO lbl-1000 |
| 183 | + var4_3 = CC$.MODULE$.unapply((CC)var3_2); |
| 184 | + s = var5_4 = var4_3._1(); |
| 185 | + if (1 == var5_4 && (var7_6 = var4_3._2()) instanceof CC) { |
| 186 | + t = CC$.MODULE$.unapply((CC)var7_6)._1(); |
| 187 | + v0 = Tuple2..MODULE$.apply((Object)BoxesRunTime.boxToInteger((int)1), (Object)BoxesRunTime.boxToInteger((int)2)); |
| 188 | + } else lbl-1000: // 2 sources: |
| 189 | + { |
| 190 | + v0 = Tuple2..MODULE$.apply((Object)BoxesRunTime.boxToInteger((int)42), (Object)BoxesRunTime.boxToInteger((int)43)); |
| 191 | + } |
| 192 | + var2_8 = v0; |
| 193 | + a = BoxesRunTime.unboxToInt((Object)var2_8._1()); |
| 194 | + b = BoxesRunTime.unboxToInt((Object)var2_8._2()); |
| 195 | + return a + b; |
| 196 | + } |
| 197 | +
|
| 198 | + public boolean booleans(Object a) { |
| 199 | + Tuple2 tuple2 = Tuple2..MODULE$.apply((Object)BoxesRunTime.boxToBoolean((boolean)(a instanceof CC)), (Object)BoxesRunTime.boxToBoolean((boolean)(a instanceof List))); |
| 200 | + boolean b1 = BoxesRunTime.unboxToBoolean((Object)tuple2._1()); |
| 201 | + boolean b2 = BoxesRunTime.unboxToBoolean((Object)tuple2._2()); |
| 202 | + Tuple2 tuple22 = Tuple2..MODULE$.apply((Object)BoxesRunTime.boxToBoolean((boolean)b1), (Object)BoxesRunTime.boxToBoolean((boolean)b2)); |
| 203 | + if (tuple22 != null) { |
| 204 | + boolean bl; |
| 205 | + boolean bl2 = BoxesRunTime.unboxToBoolean((Object)tuple22._1()); |
| 206 | + if (!bl2) { |
| 207 | + bl = bl2; |
| 208 | + } else { |
| 209 | + if (BoxesRunTime.unboxToBoolean((Object)tuple22._2())) { |
| 210 | + return true; |
| 211 | + } |
| 212 | + bl = bl2; |
| 213 | + } |
| 214 | + if (!bl) { |
| 215 | + if (false != BoxesRunTime.unboxToBoolean((Object)tuple22._2())) return false; |
| 216 | + return true; |
| 217 | + } |
| 218 | + } |
| 219 | + return false; |
| 220 | + } |
| 221 | +``` |
| 222 | + |
| 223 | +You can clearly see that it's shorter ;-) and it actually does less work. |
| 224 | +If you additionally enable local optimizations, you get a pretty good code: |
| 225 | + |
| 226 | +``` |
| 227 | +// output of 0.2.0-RC1 with -optimise |
| 228 | +
|
| 229 | + public int foo(Object x) { |
| 230 | + int n; |
| 231 | + Tuple2 tuple2; |
| 232 | + CC cC; |
| 233 | + Object object; |
| 234 | + if (x instanceof CC && 1 == (n = (cC = (CC)x)._1()) && (object = cC._2()) instanceof CC) { |
| 235 | + ((CC)object)._1(); |
| 236 | + tuple2 = new Tuple2((Object)BoxesRunTime.boxToInteger((int)1), (Object)BoxesRunTime.boxToInteger((int)2)); |
| 237 | + } else { |
| 238 | + tuple2 = new Tuple2((Object)BoxesRunTime.boxToInteger((int)42), (Object)BoxesRunTime.boxToInteger((int)43)); |
| 239 | + } |
| 240 | + Tuple2 tuple22 = tuple2; |
| 241 | + return BoxesRunTime.unboxToInt((Object)tuple22._1()) + BoxesRunTime.unboxToInt((Object)tuple22._2()); |
| 242 | + } |
| 243 | +
|
| 244 | + public boolean booleans(Object a) { |
| 245 | + boolean bl = a instanceof CC; |
| 246 | + boolean bl2 = a instanceof List; |
| 247 | + new Tuple2((Object)BoxesRunTime.boxToBoolean((boolean)bl), (Object)BoxesRunTime.boxToBoolean((boolean)bl2)); |
| 248 | + new Tuple2((Object)BoxesRunTime.boxToBoolean((boolean)bl), (Object)BoxesRunTime.boxToBoolean((boolean)bl2)); |
| 249 | + if (bl && bl2) { |
| 250 | + return true; |
| 251 | + } |
| 252 | + boolean bl3 = bl; |
| 253 | + if (bl3) return false; |
| 254 | + if (bl2) return false; |
| 255 | + return true; |
| 256 | + } |
| 257 | +``` |
| 258 | + |
| 259 | +This code still has a major inefficiency: it allocates tuples. |
| 260 | +We plan to continue migration of local optimizations from Dotty linker that should allow us to generate code that is as |
| 261 | +good the one generated by Dotty linker with global analysis disabled: |
| 262 | + |
| 263 | + ``` |
| 264 | + // output of Dotty linker https://github.com/dotty-linker/dotty/tree/opto |
| 265 | + public int foo(Object x) { |
| 266 | + CC cC; |
| 267 | + int n = 0; |
| 268 | + int n2 = 0; |
| 269 | + if (x instanceof CC && 1 == (cC = (CC)x)._1() && cC._2() instanceof CC) { |
| 270 | + n = 1; |
| 271 | + n2 = 2; |
| 272 | + } else { |
| 273 | + n = 42; |
| 274 | + n2 = 43; |
| 275 | + } |
| 276 | + return n + n2; |
| 277 | + } |
| 278 | + |
| 279 | + public boolean booleans(Object a) { |
| 280 | + boolean bl = a instanceof CC; |
| 281 | + boolean bl2 = a instanceof List; |
| 282 | + if (bl && bl2 || !bl && !bl2) { |
| 283 | + return true; |
| 284 | + } |
| 285 | + return false; |
| 286 | + } |
| 287 | +
|
| 288 | +``` |
| 289 | + |
| 290 | +## How can you try it out? |
| 291 | +We ship with tools that help you try out the Dotty platform: |
| 292 | + |
| 293 | + - [IDE features for Visual Studio Code](http://dotty.epfl.ch/docs/usage/ide-support.html) |
| 294 | + - [sbt support, including retro-compatibility with Scala 2](https://github.com/lampepfl/dotty-example-project) |
| 295 | + |
| 296 | + |
| 297 | +You have several alternatives: use the `sbt-dotty` plugin, get a standalone |
| 298 | +installation, or try it online on [Scastie]. |
| 299 | + |
| 300 | +### sbt |
| 301 | +Using sbt 0.13.13 or newer, do: |
| 302 | + |
| 303 | +``` |
| 304 | +sbt new lampepfl/dotty.g8 |
| 305 | +``` |
| 306 | + |
| 307 | +This will setup a new sbt project with Dotty as compiler. For more details on |
| 308 | +using Dotty with sbt, see the |
| 309 | +[example project](https://github.com/lampepfl/dotty-example-project). |
| 310 | + |
| 311 | +### Standalone installation |
| 312 | + |
| 313 | +Releases are available for download on the _Releases_ |
| 314 | +section of the Dotty repository: |
| 315 | +https://github.com/lampepfl/dotty/releases |
| 316 | + |
| 317 | +We also provide a [homebrew](https://brew.sh/) package that can be installed by running |
| 318 | + |
| 319 | +``` |
| 320 | +brew install lampepfl/brew/dotty |
| 321 | +``` |
| 322 | + |
| 323 | +### Scastie |
| 324 | + |
| 325 | +[Scastie], the online Scala playground, |
| 326 | +supports Dotty. |
| 327 | +You can try it out there without installing anything. |
| 328 | + |
| 329 | + |
| 330 | +## What are the next steps? |
| 331 | + |
| 332 | +Over the coming weeks and months, we plan to work on the following topics: |
| 333 | + |
| 334 | + - [Add support for using Dotty generated classes with Scala 2.12](https://github.com/lampepfl/dotty/pull/2827) |
| 335 | + - [Add Language-level support for HMaps and HLists](https://github.com/lampepfl/dotty/pull/2199); |
| 336 | + - Upstream more optimizations from Dotty Linker |
| 337 | + |
| 338 | +If you want to get your hands dirty with any of this, now is a good |
| 339 | +moment to get involved! Join the team of contributors, including |
| 340 | +Martin Odersky ([@odersky](https://twitter.com/odersky)) |
| 341 | +Dmitry Petrashko ([@DarkDimius](https://twitter.com/DarkDimius)), |
| 342 | +Guillaume Martres ([@smarter](https://github.com/smarter)), |
| 343 | +Felix Mulder ([@felixmulder](https://twitter.com/felixmulder)), |
| 344 | +Nicolas Stucki ([@nicolasstucki](https://github.com/nicolasstucki)), |
| 345 | +Liu Fengyun ([@liufengyun](https://github.com/liufengyun)), |
| 346 | +Olivier Blanvillain ([@OlivierBlanvillain](https://github.com/OlivierBlanvillain)), |
| 347 | +and others! |
| 348 | + |
| 349 | +## Library authors: Join our community build |
| 350 | + |
| 351 | +Dotty now has a set of libraries that are built against every nightly snapshot. |
| 352 | +Currently this includes scalatest, squants and algebra. |
| 353 | +Join our [community build](https://github.com/lampepfl/dotty-community-build) |
| 354 | + to make sure that our regression suite includes your library. |
| 355 | + |
| 356 | + |
| 357 | +To get started, see <https://github.com/lampepfl/dotty>. |
| 358 | + |
| 359 | + |
| 360 | +[Scastie]: https://scastie.scala-lang.org/?target=dotty |
0 commit comments