Announcing Dotty 0.16.0-RC3 – the Scala Days 2019 Release

Hello again! Today, we are excited to announce the 16th release of Dotty. The development of Dotty continues according to our schedule but today, Tuesday June the 11th, we are electrified as it is the first day of Scala Days 2019 which marks the 10th anniversary of Scala Days. With this release we are getting closer to the envelope of the new features that Dotty plans to offer.

This release serves as a technology preview that demonstrates new language features and the compiler supporting them.

Dotty is the project name for technologies that are being considered for inclusion in Scala 3. Scala has pioneered the fusion of object-oriented and functional programming in a typed setting. Scala 3 will be a big step towards realising the full potential of these ideas. Its main objectives are to

  • become more opinionated by promoting programming idioms we found to work well,
  • simplify where possible,
  • eliminate inconsistencies and surprising behaviours,
  • build on strong foundations to ensure the design hangs together well,
  • consolidate language constructs to improve the language’s consistency, safety, ergonomics, and performance.

You can learn more about Dotty on our website.

This is our 16th scheduled release according to our 6-week release schedule.

What’s new in the 0.16.0-RC3 technology preview?

Syntax Change: Type Lambdas

We reconsider the syntax of type lambdas in an effort to provide an improved visual cue for two categories of types: types that relate to normal function types and types that operate on a higher level. The fat arrow => definitely relates to the first, while we reserve now -> to mean pure function in the future. As a result, we disengage => from type lambdas, which are now represented by =>>. As a result a function from types to types is written as [X] =>> F[X].

For those who are interested in the discussions, #6558 introduced the new syntax.

Syntax Change: Wildcard Arguments in Types

The syntax of wildcard arguments in types has changed from _ to ?. Example:

List[?]
Map[? <: AnyRef, ? >: Null]

Again, in an effort to fine-tune our syntax we put two features, from the world of terms and types, side-by-side and drew parallels at the syntactic level. Consequently, as f(_) is a shorthand for the lambda x => f(x) and as we plan ahead for making C[_] to be a shorthand for the type lambda [X] =>> C[X] in the future we pick ? as a replacement syntax for wildcard types, since it aligns with Java's syntax.

For more information please read our documentation on Wildcards.

Syntax Change: Contextual Abstractions

We reconsider the syntax for contextual abstractions introducing delegates (formerly known as implied). delegate, in the context of contextual abstraction means that we declare a representative of a type. We use delegate as a noun. Note that this change is solely syntactical/grammatical and its motivation is to give a clearer meaning to those canonical values of certain types (like Ord[Int]), that serve for synthesizing arguments to given clauses.

delegate IntOrd for Ord[Int] {
  def compare(x: Int, y: Int) =
    if (x < y) -1 else if (x > y) +1 else 0
}
delegate ListOrd[T] for Ord[List[T]] given (ord: Ord[T]) {

For more information, the documentation has been updated as part of the relevant PR #6649

Polymorphic function types

We add preliminary support for polymorphic function types. Nowadays, when we want to write a universally quantified function over elements of lists of type T we write e.g., List[T] => List[(T, T)] where T is bound at an enclosing definition. With polymorphic function types (PFT hereafter) we can quantify the parametric type locally. For example:

[T <: AnyVal] => List[T] => List[(T, T)]

As you notice, this gives us the ability to impose restrictions on the type variable T locally. Assume, you have an identity function with type id = T => T. By writing it as type id = [T] => T => T we abstract further the concept of a polymorphic function and make it a true family of functions.

The code below (correctly) fails to type check because T needs to be bounded in the enclosing class:

val id: T => T = t => t
  println(s"${id(1)} , ${id(7.0d)}")

With PFTs we can now achieve what we want:

val id = [T] => (t: T) => t
  println(s"${id(1)} , ${id(7.0d)}")

For those who are interested in the discussions and more test cases, #4672 introduced PFTs.

lazy vals are now thread-safe by default

Previously thread-safety was required using @volatile but that would not be consistent with Scala 2. The old behavior of non-volatile lazy vals can be recovered by using the newly-introduced @threadUnsafe.

For more information please read our documentation on the threadUnsafe annotation.

Add support for Java-compatible enums

We add support for Java-compatible enumerations. The users can just extend java.lang.Enum[T].

enum A extends java.lang.Enum[A] {
  case MONDAY, TUESDAY, SATURDAY
}

enum B(val gravity: Double) extends java.lang.Enum[B] {
  case EARTH extends B(9.8)
  case JUPITER extends B(100)
  case MOON extends B(4.3)
  case Foo extends B(10)
}

For more information please check the test case and also the relevant PRs #6602 and #6629.

In the test, the enums are defined in the MainScala.scala file and used from a Java source, Test.java.

Introducing for clauses for importing delegate imports by type

Since delegate instances can be anonymous it is not always practical to import them by their name, and wildcard imports are typically used instead. By-type imports provide a more specific alternative to wildcard imports, which makes it clearer what is imported. Example:

import delegate A.{for TC}

This imports any delegate instance in A that has a type which conforms tp TC. There can be several bounding types following a for and bounding types can contain wildcards. For instance, assuming the object

object Delegates {
  delegate intOrd for Ordering[Int]
  delegate [T: Ordering] listOrd for Ordering[List[T]]
  delegate ec for ExecutionContext = ...
  delegate im for Monoid[Int]
}

the import

import delegate Delegates.{for Ordering[_], ExecutionContext}

would import the intOrd, listOrd, and ec instances but leave out the im instance, since it fits none of the specified bounds.

New type class derivation scheme

Summary of measured differences with the old scheme:

  • About 100 lines more compiler code - the rest of the lines changed diff is tests.
  • About 13-15% more code generated for type class instances
  • About 3-4% slower to compile type class instances

Advantages of new scheme:

  • Fewer allocations, since mirrors (Generic has been renamed to Mirror) are usually shared instead of being allocated at runtime.
  • It works well even if there are no derives clauses. The old scheme would generate more code in that case.
  • Complete decoupling between derives clauses and mirror generation.

For the technical details of these changes please consule the corresponding PR #6531.

Let us know what you think!

If you have questions or any sort of feedback, feel free to send us a message on our Gitter channel. If you encounter a bug, please open an issue on GitHub.

Contributing

Thank you to all the contributors who made this release possible!

According to git shortlog -sn --no-merges 0.15.0-RC1..0.16.0-RC3 these are:

88  Martin Odersky
51  Anatolii
48  Nicolas Stucki
26  Guillaume Martres
21  Miles Sabin
19  Liu Fengyun
12  Aleksander Boruch-Gruszecki
11  Sébastien Doeraene
 8  Aggelos Biboudis
 4  Olivier Blanvillain
 3  Eugene Yokota
 1  Dale Wijnand
 1  Allan Renucci
 1  Olivier ROLAND

If you want to get your hands dirty and contribute to Dotty, now is a good time to get involved! Head to our Getting Started page for new contributors, and have a look at some of the good first issues. They make perfect entry points into hacking on the compiler.

We are looking forward to having you join the team of contributors.

Library authors: Join our community build

Dotty now has a set of widely-used community libraries that are built against every nightly Dotty snapshot. Currently this includes ScalaPB, algebra, scalatest, scopt and squants. Join our community build to make sure that our regression suite includes your library.