Top Banner
From DOT to Dotty Martin Odersky ScalaX, London, 8 December 2016
56

From DOT to Dotty

Apr 16, 2017

Download

Technology

Martin Odersky
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: From DOT to Dotty

From DOT to Dotty

Martin Odersky

ScalaX, London, 8 December 2016

Page 2: From DOT to Dotty

DOT: Foundations

dotty: Prototype

… for future Scala

Page 3: From DOT to Dotty

Why Do Foundations Matter?

• They help ensure properties such as type soundness.

• They serve as a feedback loop for language design.

• They help detect hidden connections between language features.

Page 4: From DOT to Dotty

Why Not Pick Existing Foundations?

• Because they would lead to variants of existing languages.

• Foundations are formative!

Page 5: From DOT to Dotty

Our AimWe are looking for a minimal theory that can model

1. type parameterization,2. modules,3. objects and classes.

minimal: We do not deal with inheritance here.

Page 6: From DOT to Dotty

Our AimWe are looking for a minimal theory that can model

1. type parameterization,2. modules,3. objects and classes.

There were several attempts before, including νObj,which was proposed as a basis for Scala (ECOOP 2003).

But none of them felt completely canonical or minimal.

Related: 1ML, which can model (1) and (2) by mapping to System F.

Page 7: From DOT to Dotty

Dependent Types• We will model modules as objects with type members.

• This requires a notion of dependent type - the type referred to by a type member depends on the owning value.

• In Scala we restrict dependencies to paths.

• In the calculus presented here we restrict it further to variables.

Variable xPath p = x | p.a

Page 8: From DOT to Dotty

Dependent Types in CodeWe can model heterogeneous maps like this:

Page 9: From DOT to Dotty

Dependent Types in Code

Page 10: From DOT to Dotty

Dependent Types in Code

Page 11: From DOT to Dotty

Foundations: DOT

The DOT calculus is intended to be a minimal foundation of Scala.

Its type structure is a blueprint for the types used internally in the compiler.

Page 12: From DOT to Dotty

DOT Terms• Translated to Scala notation, the language covered by

DOT is:Value v = (x: T) => t Function

new { x: T => d } Object

Definition d = def a = t Method definitiontype A = T Type

Term t = v Valuex Variablet1(t2) Applicationt.a Selection{ val x = t1; t2 } Local definition.

Page 13: From DOT to Dotty

DOT TypesThe Types covered by DOT are:

Type T = Any Top typeNothing Bottom typex.A Selection(x: T1) => T2 Function{ def a: T } Method declaration{ type T >: T1 <: T2 } Type declarationT1 & T2 Intersection{ x => T } Recursion

Page 14: From DOT to Dotty

DOT TypesThe Types covered by DOT are:

Type T = Any Top typeNothing Bottom typex.A Selection(x: T1) => T2 Function{ def a: T } Method declaration{ type T >: T1 <: T2 } Type declarationT1 & T2 Intersection{ x => T } Recursion

Should Scala have these?

Page 15: From DOT to Dotty

DOT TypesThe Types covered by DOT are:

Type T = Any Top typeNothing Bottom typex.A Selection(x: T1) => T2 Function{ def a: T } Method declaration{ type T >: T1 <: T2 } Type declarationT1 & T2 Intersection{ x => T } Recursion

Will replace the

T1 with T2

syntax

Page 16: From DOT to Dotty

DOT TypesThe Types covered by DOT are:

Type T = Any Top typeNothing Bottom typex.A Selection(x: T1) => T2 Function{ def a: T } Method declaration{ type T >: T1 <: T2 } Type declarationT1 & T2 Intersection{ x => T } RecursionScala has only refinements

T { d1 … dn}

with this as self reference.

Page 17: From DOT to Dotty

DOT Syntax in Greek

Note: terms are in ANF form.This simplifies some things, but is not essential.

Page 18: From DOT to Dotty

Type Assignment

Page 19: From DOT to Dotty

Definition Type Assignment

Page 20: From DOT to Dotty

Subtyping

Page 21: From DOT to Dotty

ExpressivenessSimple as the model is, it is actually quite expressive.

Directly representable:

▶ type parameters▶ variance▶ nominal typing▶ generative modules ▶ self types ▶ ADTs and simple classes

Requires smallish extension:

▶ Classes with inheritance

Page 22: From DOT to Dotty

Meta TheorySimple as the model is, the soundness proof of DOT was surprisingly hard.

▶ Attempts were made since about 2008.

▶ Previous publications (FOOL 12, OOPSLA 14) reportabout (some) advances and (lots of) difficulties.

▶ Essential challenge: Subtyping theories areprogrammer-definable.

Page 23: From DOT to Dotty

Programmer-Definable TheoremsIn Scala and DOT, the subtyping relation is given in part by user-definable definitions:

type T >: S <: U { T: S .. U }

This makes T a supertype of S and a subtype of U. By transitivity, S <: U.

So the type definition above proves a subtype relationship which was potentially not provable before.

Page 24: From DOT to Dotty

Bad BoundsWhat if the bounds are non-sensical?

Example:type T >: Any <: Nothing

By the same argument as before, this implies that Any <: Nothing

Once we have that, again by transitivity we get S <: T for arbitrary S and T.

That is, the subtyping relations collapses to a single point!

This means that most proof techniques for soundness fail.

Page 25: From DOT to Dotty

Dealing with itObservation: To prove preservation, we need to reason at the top-level only about environments that arise from an actual computationSuch environments correspond to run-time stores which binds variables to values. And values have guaranteed good bounds because all type members in definitions are aliases.By an elaborate argument one can make use of this observation to show soundness.

Page 26: From DOT to Dotty

For Details

Page 27: From DOT to Dotty

Consequences for Language Design• So far: Some soundness issues were known, but it was

not clear how to fix them.

• Can one impose restrictions to guarantee good bounds?

• Has been tried for a while but was not complete.

• The meta theory taught us a principle to ensure soundness:

Every prefix p of a type selection p.A must be a computed value.

Page 28: From DOT to Dotty

Things To Avoidtrait BadBounds { type A >: Any <: Nothing }

lazy val x: BadBounds = ???

BadBounds # A

val x: BadBounds = null

Need to drastically restrict types we can write in a lazy val: Only concrete types with good bounds are allowed.Need to drastically restrict types we can write in a projection: Only concrete types with good bounds are allowed.

Page 29: From DOT to Dotty
Page 30: From DOT to Dotty
Page 31: From DOT to Dotty

Things To Avoidtrait BadBounds { type A >: Any <: Nothing }

lazy val x: BadBounds = ???

BadBounds # A

val x: BadBounds = nullNeed to track null in the type system (straightforward)

Need to track initialization status(hard)

Page 32: From DOT to Dotty

dottydotty is the working name for our new Scala compiler.

• Builds on DOT in its internal data structures.

• Generics get expressed as type members.

• Supports the next iteration(s) of the Scala programming language.

Page 33: From DOT to Dotty

A Whirlwind Tour Of Dotty Constructs

Page 34: From DOT to Dotty

Dropped Features

DelayedInit

Macros

Existential Types

Procedure Syntax

Early Initializers

General Type Projection

def run() { ... }

Will be rewritten automatically to

def run(): Unit = { ... }

class Foo extends DelayedInit

class C extends {val x = e

} with D

Use trait parameters instead

T # X

- Was shown to be unsound for general types T.- Projection C#X from class types C still available.

(the reflection based kind)

def m(...) = macro impl(...)

C[U] forSome { type U }

Wildcards C[_]still supported.

Page 35: From DOT to Dotty

Implemented New Features

Multiversal Equality

Intersection TypesUnion types

Trait parameters

Function arityadaptation

pairs.map((x, y) => x + y)

instead of

pairs.map {case (x, y) => x + y

}

T & U

- replaces T with U- is commutative

T | U

avoids huge lubs

@static methods and fieldsnon-blocking lazy vals

trait T(x: Int) { ... }object O {@static val x = ...@static def f() = ...

}

lazy val x = ... // thread-local

@volatilelazy val x - ... // thread-safe,

// avoids dead-locks

type-safe ==, !=

Page 36: From DOT to Dotty

And Further Down the Road ?

Implicit Function Types

scala.metascrap all 22’s

effects

Page 37: From DOT to Dotty

Implicit Function Types

Page 38: From DOT to Dotty

What Are Implicit Function Types?

and what is “Contextual Abstraction”?

Page 39: From DOT to Dotty

“Abstraction”

The ability to name a concept

and use just the name afterward

Page 40: From DOT to Dotty

“Contextual”The context comprises all the inputs that let a program do its work, including:

• configuration data

• capabilities

• dependency injection

• type class instances

Page 41: From DOT to Dotty

Implicit Parameters• Technique of choice to pass inputs to program parts that

need them.

• Advantage over normal parameters:

No boilerplate code to pass them along the edges of a call graph.

• But we still need to declare them as parameters everywhere they are passed!

Page 42: From DOT to Dotty

Example: Transaction Handling

Page 43: From DOT to Dotty

Example (2)

Page 44: From DOT to Dotty

Example (3)

Page 45: From DOT to Dotty

Example Run

Page 46: From DOT to Dotty

Can We Do Better?• Problem: Boilerplate code for declaring implicit

parameters

• Repeating this 3x does not look so terrible.

• But in the dotty compiler there are 2641(!) occurrences of

• We’d like to get rid of them.

Page 47: From DOT to Dotty

Towards A SolutionLet’s massage the definition of f1 a bit:

f1’s right hand side is now an implicit function value.What is its type?

So far: Transaction => Int

From now on: implicit Transaction => Int

or, desugared: ImplicitFunction1[Transaction, Int]

Page 48: From DOT to Dotty

Inside ImplicitFunction1ImplicitFunction1 can be thought of being defined as follows:

Analogously for all other arities.

Page 49: From DOT to Dotty

Two Rules for Typing1. Implicit functions get implicit arguments just like implicit

methods. Given:

f expands to f(a)

2. Implicit functions get created on demand. If the expected type of b is implicit A => B, then

b expands to implicit _: A => b

Page 50: From DOT to Dotty

Revised Example:

But where does current come from?

Page 51: From DOT to Dotty

Revised Example (2)

Page 52: From DOT to Dotty

Summary• Implicit function types are a neat way to abstract over

contexts.

• It’s a very powerful feature, because it allows one to inject implicit values in a scope simply by defining type.

• This opens up a lot of possibilities.

• I expect it will fundamentally affect the kind of Scala code in the future.

Page 53: From DOT to Dotty

When Can I Expect This?

Scala 2.12

Scala 2.13

Scala 3.0TASTY, middle end?

stdlibcollections

dotty MVP

dotty 0.x releases

2016backend, classpath handling

Scala 2.14

2017

2018

This is open source work, depends on community’s contributions.à Roadmap is tentative, no promises:

“MVP” = minimal viable prototype

Page 54: From DOT to Dotty

ContributorsTheory (DOT): Nada Amin, Tiark Rompf, Sandro Stucki, Samuel Grütter. based on previous work by Adriaan Moors, Donna Malayeri, Geoffrey Washburn, and others.

Implementation (dotty): Many contributors, including

Dmitry Petrashko Nicolas StuckiGuillaume Martres Sebastien DouraeneFelix Mulder Ondrej LhotakLiu Fengyun Vera Salvisberg

Close collaboration with scalac team

Adriaan Moors Seth TisueJason Zaugg Stefan ZeigerLukas Rytz

Page 55: From DOT to Dotty

Find out more on scala-lang.org/blog

Page 56: From DOT to Dotty

Thank You