SlideShare uma empresa Scribd logo
1 de 158
Baixar para ler offline
A Taste of Dotty
copyright 2021 Hermann Hueck
https://github.com/hermannhueck/taste-of-dotty
1
Abstract
This presentation is an introduction to Dotty / Scala 3 and an overview of many
features.
It covers those features which I deem most important for Scala application developers.
For detailed information see the Dotty documentation.
The code examples are partly my own. I also took many examples (unchanged or
modified) from the Dotty Documentation.
The presentation also contains many links to specific chapters in the Dotty docs.
2
Agenda (1/3)
» Design Goals
» TASTy
» Project Setup
» Using Scala 2 Libraries
» Top Level def's and val's
» Indentation / Optional Braces
» New Control Syntax
» Main Methods
» Constructor Invocations w/o new
» Traits Parameters
» Enums and ADTs
» Intersection Types
3
Agenda (2/3)
» Union Types
» Contextual Abstractions
» Implicit Conversions
» Extension Methods
» Givens
» Type Lambdas
» Typeclasses
» Opaque Type Aliases
» Polymorphic Function Types
» Dependent Function Types
» Context Functions
» Tuples are HLists
4
Agenda (3/3)
» Explicit Nulls
» Multiversial or Strict Equality
» Export Clauses
» Match Types
» inline
» Typeclass Derivation
» Given By-Name Parameters
» Implicit Resolution
» Overload Resolution
» Other Features
» Resources
5
Design Goals1
1 
https://dotty.epfl.ch/docs/index.html
6
Design Goals
» build on strong foundations (DOT Calculus)
» improve language consistency,
» eliminate surprising behaviours, puzzlers
» better (type) safety and ergonomics, simplify where possible
» improve performance
7
TASTy1a
1a 
https://www.scala-lang.org/blog/2018/04/30/in-a-nutshell.html
8
What is TASTy? - (Typed Abstract Syntax Trees)
» Tasty is the high-level interchange (serialization) format for Scala 3.
» Represents the syntactic structure of programs and also contains complete information
about types and positions.
» The Tasty “snapshot” of a code file is taken after type checking (so that all types are present
and all implicits are elaborated) but before any transformations (so that no information is
lost or changed).
» Heavily optimized for compactness (approximately same size as class files).
» .tasty files are now co-located with .class files.
» .tasty files are included in published JARs.
9
Image taken from "Preparing for Scala 3" - Martin Odersky's keynote of Scala Days 2018, Berlin
10
Project Setup2
2 
https://dotty.epfl.ch/docs/usage/getting-started.html
11
IDE Support3
» IntelliJ IDEA supports Scala 3.
» Metals supports Scala 3.
» Metals works with any editor that supports LSP (Language Server
Protocol): VS Code, vim, emacs, Sublime Text, Eclipse
3 
https://dotty.epfl.ch/docs/usage/ide-support.html
12
sbt support
» sbt 1.5.x++ supports Scala 3 out of the box.
» sbt-dotty plugin is no longer needed since sbt 1.5.0.
13
New sbt Project
» create new project: sbt new scala/scala3.g8
» (or: sbt new scala/scala3-cross.g8 for a cross-build project)
» cd to project directory
» start sbt in the project directory
» open project in VS Code
14
build.sbt
val scala3Version = "3.0.0-RC3"
lazy val root = project
.in(file("."))
.settings(
name := "scala3-simple",
version := "0.1.0",
scalaVersion := scala3Version,
libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test"
)
15
project/build.properties
sbt.version=1.5.1
16
Using Scala 2 Libraries4
4 
https://scalacenter.github.io/scala-3-migration-guide/docs/compatibility/classpath.html
17
Using Scala 2 Libraries in Scala 3
» Dotty can already utilize Scala 2 libraries.
» This works because Dotty is currently retro-compatible with Scala
2.x.
» This allows to migrate your app to Dotty, even before 3rd party
dependencies have been migrated.
» Caveat: Dotty CANNOT invoke macros defined in Scala 2 libraries.
18
Using Scala 2 Libraries in Scala 3
// build.sbt
libraryDependencies += ("my.domain" %% "myScala213Lib" % myScala213LibVersion).cross(CrossVersion.for3Use2_13)
libraryDependencies ++= Seq(
"co.fs2" %% "fs2-core" % fs2Version,
"co.fs2" %% "fs2-io" % fs2Version,
"org.scalatest" %% "scalatest" % scalaTestVersion % Test
).map(module => module.cross(CrossVersion.for3Use2_13))
19
Using Scala 3 Libraries in Scala 2
» Scala 2.13.5 and higher can utilize Scala 3 libraries.
» This works because the Scala 2.13.5+ compiler implements a TASTY reader
(enabled by compiler flag -Ytasty-reader).
// build.sbt
scalaVersion = "2.13.5"
scalacOptions += "-Ytasty-reader" // supported by Scala 2.13.5 and higher
libraryDependencies += ("my.domain" %% "myScala3Lib" % myScala3LibVersion).cross(CrossVersion.for2_13Use3)
20
Migration
Comprehensive information about migration can be found in the ...
Scala 3 Migration Guide
https://scalacenter.github.io/scala-3-migration-guide/
21
Top Level def's and
val's5
5 
https://dotty.epfl.ch/docs/reference/dropped-features/package-objects.html
22
Top Level def's and val's
» Scala 2: def's and val's must be defined in a trait, class or object.
» Scala 3: def's and val's can be defined at the top level.
» Scala 2: To provide def's and val's directly in a package, one has to
use package objects.
» Scala 3: Package objects are still available in 3.0, but will be
deprecated and removed in 3.1 or 3.2.
23
val r = scala.util.Random
def randomInt(): Int =
r.nextInt
def printBoxed(value: Any): Unit =
println(boxed(value))
def boxed(value: Any): String =
val line = "u2500" * 50
s"$linen${value.toString}n$line"
@main def topLevelDefsAndVals() =
printBoxed(randomInt())
24
Indentation / Optional
Braces6
6 
https://dotty.epfl.ch/docs/reference/other-new-features/indentation.html
25
Indentation / Optional Braces
» Braces are optional.
» Without braces identation becomes significant to delimit a block
of code.
» An colon at the end of the line starts a new indentation block.
» end markers are optional.
26
» with braces:
// Scala 2 + 3:
trait MyTrait {
def boxed(value: Any): String = {
val line = "u2500" * 50
s"$linen${value.toString}n$line"
}
}
» without braces:
// Scala 3:
trait MyTrait:
def boxed(value: Any): String =
val line = "u2500" * 50
s"$linen${value.toString}n$line"
end MyTrait // optional end marker
27
New Control Syntax7
7 
https://dotty.epfl.ch/docs/reference/other-new-features/control-syntax.html
28
if ... then ... else
val x = 42
if x < 0 then -x else x
if x < 0 then
"negative"
else if x == 0 then
"zero"
else
"positive"
29
while ... do (while-loop)
var x = 42
def f(x: Int): Int = x - 10
while x >= 0 do x = f(x)
while
x >= 0
do
x = f(x)
30
for ... do (for-loop)
val xs = List(1, 2, 3)
val ys = List(10, 20, 30)
for x <- xs if x > 0
do println(x * x)
for
x <- xs
y <- ys
do
println(x + y)
31
for ... yield (for-comprehension)
val xs = List(1, 2, 3)
val ys = List(10, 20, 30)
for x <- xs if x > 0
yield x * x
for
x <- xs
y <- ys
yield x + y
32
Main Methods8
8 
https://dotty.epfl.ch/docs/reference/changed-features/main-functions.html
33
Main Methods
@main def happyBirthday(age: Int, name: String, others: String*): Unit =
val congrats = s"Happy Birthday at age $age to $name" ++ {
if others.isEmpty then
""
else
" and " ++ others.mkString(" and ")
} ++ "."
println(congrats)
34
Main Methods
» A @main annotation on a method turns this method into an executable program.
» The method must be static, i.e. not defined within a class or trait.
» If annotated the method name is arbitrary.
» Argument types can not only be Array[String].
» Any argument type is allowed if an instance of typeclass scala.util.FromString is in
implicit scope.
» Dotty checks the runtime arguments passed against the signature of the main
function.
35
Constructor Invocations
without new9
9 
https://dotty.epfl.ch/docs/reference/other-new-features/creator-applications.html
36
Constructors without new
» When constructing instances the new keyword is optional.
» Works not only for case classes but also for regular classes.
» Works for Java classes too.
» If no apply method is found, the compiler creates apply methods for each constructor.
» These constructor proxies bear the same signatures as the constructors and invoke them.
val sb =
StringBuilder("The keyword 'new'")
.append(" is ")
.append("optional")
.append("!")
37
Trait Parameters10
10 
https://dotty.epfl.ch/docs/reference/other-new-features/trait-parameters.html
38
Trait Parameters
» Traits can have parameters like classes.
» Arguments are evaluated before the trait is initialized.
» They replace early initalizers in Scala 2 traits, which have been dropped.
trait Greeting(val name: String):
def msg = s"How are you, $name"
class C extends Greeting("Bob"):
println(msg)
class D extends C with Greeting("Bill"): // COMPILE ERROR
// [error] trait Greeting is already implemented by superclass C
// [error] its constructor cannot be called again
39
Enums and ADTs11 12
12 
https://dotty.epfl.ch/docs/reference/enums/adts.html
11 
https://dotty.epfl.ch/docs/reference/enums/enums.html
40
Simple Enums
» enum is a new keyword.
» With enum one can define a type consisting of a set of named values.
enum Color:
case Red, Green, Blue
41
Java compatible Enums
» To make your Scala-defined enums usable as Java enums, you can
do so by extending java.lang.Enum.
enum Color extends java.lang.Enum[Color]:
case Red, Green, Blue
42
Enums with Parameters
» The parameters are defined by using an explicit extends clause.
enum Color(val escape: String):
case Red extends Color(Console.RED)
case Green extends Color(Console.GREEN)
case Blue extends Color(Console.BLUE)
43
Methods defined for Enums
scala> val red = Color.Red
val red: Color = Red
scala> red.ordinal
val res0: Int = 0
Methods defined on the companion object
scala> Color.valueOf("Blue")
val res0: Color = Blue
scala> Color.values
val res1: Array[Color] = Array(Red, Green, Blue)
44
User-defined members of Enums
» It is possible to add your own definitions to an enum.
» You can also define your own methods in the enum's companion object.
enum Color(val escape: String):
case Red extends Color(Console.RED)
case Green extends Color(Console.GREEN)
case Blue extends Color(Console.BLUE)
// user defined method
def colored(text: String) = s"$escape$text${Console.RESET}"
import Color._
val greenHello = Green.colored("Hello World!")
45
ADTs in Scala 2
» In Scala 2 ADTS are expressed as sealed traits with a hierarchy of case classes.
» This syntax is still supported in Scala 3.
sealed trait Tree[+T]
object Tree {
case class Leaf[T](elem: T) extends Tree[T]
case class Node[T](left: Tree[T], right: Tree[T]) extends Tree[T]
}
import Tree._
val tree: Tree[Int] = Node(Leaf(1), Node(Leaf(2), Leaf(3)))
46
ADTs in Scala 3
» In Scala 3 an ADT can be expressed with enum syntax.
enum Tree[+T]:
case Leaf(elem: T) extends Tree[T]
case Node(left: Tree[T], right: Tree[T]) extends Tree[T]
import Tree.*
val tree: Tree[Int] = Node(Leaf(1), Node(Leaf(2), Leaf(3)))
47
ADTs with Syntactic Sugar
» The extends clause can be omitted in many cases.
enum Tree[+T]:
case Leaf(elem: T)
case Node(left: Tree[T], right: Tree[T])
import Tree.*
val tree: Tree[Int] = Node(Leaf(1), Node(Leaf(2), Leaf(3)))
48
ADTs with Methods
» As all other enums, ADTs can define methods.
enum Tree[+T]:
case Leaf(elem: T)
case Node(left: Tree[T], right: Tree[T])
def count: Int = this match
case Leaf(_) => 1
case Node(left, right) => left.count + right.count
import Tree.*
val tree: Tree[Int] = Node(Leaf(1), Node(Leaf(2), Leaf(3)))
val count = tree.count // 3
49
Intersection Types13
13 
https://dotty.epfl.ch/docs/reference/new-types/intersection-types.html
50
Intersection Types
» Used on types, the & operator creates an intersection type.
» The type A & B represents values that are of the type A and B at the same
time.
» A & B has all members/properties of A and all members/properties of B.
» & is commutative: A & B is the same type as B & A.
» with ist not commutative: A with B is not exactly the same type as B with A.
» Intersection types will - in the long run - replace compound types: A with B
51
Intersection Types
trait Resettable:
def reset(): Unit
trait Growable[T]:
def add(x: T): Unit
def f(x: Resettable & Growable[String]) =
x.reset()
x.add("first")
52
class MyClass(var x : String = "") extends Resettable, Growable[String]:
def reset(): Unit =
x = ""
def add(s: String): Unit =
x += s
override def toString =
s"[$x]"
val obj: MyClass = MyClass("foo") // [foo]
obj.reset() // []
obj.add("bar") // [bar]
obj.add("baz") // [barbaz]
f(obj) // [first]
53
Union Types14
14 
https://dotty.epfl.ch/docs/reference/new-types/union-types.html
54
Union Types
» A union type A | B comprises all values of type A and also all values of type B.
» Union types are duals of intersection types.
» A | B contains all members/properties which A and B have in common.
» | is commutative: A | B is the same type as B | A.
» Pattern matching is the natural way to decide if an A | B is an A or a B.
» Union types are not suited to express coproducts (use enums).
» Type inference doesn't give you the least (most specific) supertype.
» If you want the least supertype, specify the type explicitly.
55
type Hash = Int
case class UserName(name: String)
case class Password(hash: Hash)
def check(what: UserName | Password): String = what match
case UserName(name) => name
case Password(hash) => hash.toString
val name: UserName = UserName("Eve")
val password: Password = Password(123)
val nameOrPw1 =
if true then name else password // : Object = UserName(Eve)
val nameOrPw2: UserName | Password =
if true then name else password // : UserName | Password = UserName(Eve)
56
Contextual
Abstractions15
(Implicits in Scala 2)
15 
https://dotty.epfl.ch/docs/reference/contextual/motivation.html
57
Implicits
» Implicits are the fundamental way to abstract over context in Scala 2.
» Hard to understand, error-prone, easily misused or overused, many rough edges.
» Implicits convey mechanism over intent.
» One mechanism used for many different purposes:
» implicit conversions
» extension methods
» providing context
» dependency injection
» typeclasses
58
The new Design in Scala 3 (1/2)
» Focus on intent over mechanism
» Implicit conversions are hard to misuse.
» Concise syntax for extension methods
» New keywords given and using
» given instances focus on types instead of terms.
» using clauses replace implicit parameters.
» given imports are distinct from regular imports.
59
The new Design in Scala 3 (2/2)
» Typeclasses can be expressed in a more concise way.
» Context bounds remain unchanged in syntax and semantics.
» Typeclass derivation is supported.
» Context Functions provide a way to abstract over given clauses.
» Implicit By-Name Parameters are an essential tool to define recursive synthesized values
without looping.
» Multiversal Equality introduces a special typeclass CanEqual to support type safe equality.
» Scala 2 implicits remain available in parallel for a long time (backward compatibility).
60
Implicit Conversions16
16 
https://dotty.epfl.ch/docs/reference/contextual/conversions.html
61
Implicit Conversion in Scala 2
implicit def str2Int(s: String): Int =
Integer.valueOf(s)
val xs = List("foo", "bar", "baz")
xs("1") // bar
xs("one") // java.lang.NumberFormatException: For input string: "one"
62
Implicit Conversion in Scala 3
given Conversion[String, Int] with
def apply(s: String): Int =
Integer.valueOf(s).nn
val xs = List("foo", "bar", "baz")
xs("1") // bar
xs("one") // java.lang.NumberFormatException: For input string: "one"
63
Implicit Conversions
» Scala 2 syntax is still available in Scala 3 (backward compat).
» Scala 2 syntax can easily be mixed up with other implicit constructs.
» In Scala 3 scala.Conversion is a subclass of Function1 defined in package scala.
» Implicit Conversions must extend Conversion.
package scala
abstract class Conversion[-T, +U] extends (T => U)
64
Conversion Example
case class Token(str: String)
given Conversion[String, Token]:
def apply(str: String): Token = Token(str)
or even more concise:
case class Token(str: String)
given Conversion[String, Token] = Token(_)
65
Extension Methods17
17 
https://dotty.epfl.ch/docs/reference/contextual/extension-methods.html
66
Extension Methods
» Extension methods replace implicit classes of Scala 2.
» They are defined using the new key word extension.
» The extension keyword is followed by a single parameter,
» which is the object on which the extension method(s) is/are defined.
» The extension clause is followed by one ore more method definitions.
» They can be invoked two ways: method(param) or param.method
» This syntax also applies to operators.
67
Extension Methods
case class Circle(x: Double, y: Double, radius: Double)
// Scala 2 extension method:
// implicit class CircleExtension(private val c: Circle) extends AnyVal {
// @inline def circumference: Double = c.radius * math.Pi * 2
// }
extension (c: Circle)
def circumference: Double = c.radius * math.Pi * 2
val circle = Circle(0, 0, 1)
val cf1 = circle.circumference
val cf2 = circumference(circle)
assert(cf1 == cf2)
68
Collective Extensions
» Several extension methods that share the same left-hand parameter type
» ... can be bundled with extension
» ... moving the common first parameter to the instance.
extension [T](xs: List[T])
def second: T = xs.tail.head
def third: T = xs.tail.second
extension [T](xs: List[T])(using Ordering[T]) // uses an additional implicit parameter
def largest(n: Int) = xs.sorted.takeRight(n)
69
Givens18
18 
https://dotty.epfl.ch/docs/reference/contextual/motivation.html
70
Givens
» given is a new keyword
» givens in many ways replace implicits
» more concise, less boilerplate
» focus on types instead of terms
71
Givens: Future Example 1
» Future requires a given ExecutionContext in nearly every method.
import scala.concurrent.{Future, ExecutionContext}
// implicit val ec: ExecutionContext = ExecutionContext.global // Scala 2
given ec: ExecutionContext = ExecutionContext.global // Scala 3: variable ec can be omitted
def someComputation(): Int = ???
val future: Future[Int] = Future { someComputation() }
future onComplete {
case Success(value) => println(value)
case Failure(throwable) => println(throwable)
}
72
Givens: Future Example 2
» This example provides the ExecutionContext via import.
import scala.concurrent.{Future, ExecutionContext}
// import ExecutionContext.Implicits.global // Scala 2
import ExecutionContext.Implicits.{given ExecutionContext}
def someComputation(): Int = ???
val future: Future[Int] = Future { someComputation() }
future onComplete {
case Success(value) => println(value)
case Failure(throwable) => println(throwable)
}
73
Given Instances: Ord Example19
// a type class
trait Ord[T]:
def compare(x: T, y: T): Int
extension (x: T)
def < (y: T) = compare(x, y) < 0
def > (y: T) = compare(x, y) > 0
Typeclass instances to be defined as given's ...
19 
https://dotty.epfl.ch/docs/reference/contextual/givens.html
74
given Instances
» They replace implicitval's, def's and object's.
» They can be defined with only a type omitting a name/symbol.
» Symbols - if omitted - are synthesized by the compiler.
» The given clause ends with the key word with
» followed by a set of method defs implementing the trait (Ord in this case).
75
given Instances for Ord
// instances with symbols
given intOrd: Ord[Int] with
def compare(x: Int, y: Int) = ???
given listOrd[T](using ord: Ord[T]): Ord[List[T]] with
def compare(xs: List[T], ys: List[T]): Int = ???
// instances without symbols
given Ord[Int] with
def compare(x: Int, y: Int) = ???
given [T](using Ord[T]): Ord[List[T]] with
def compare(xs: List[T], ys: List[T]): Int = ???
76
using Clauses20
» They replace the implicit parameter list.
» Multiple using clauses are allowed.
» Anonymous using's: Symbols are optional.
» given instances can be summoned with the function summon.
» summon replaces Scala 2's implicitly.
20 
https://dotty.epfl.ch/docs/reference/contextual/using-clauses.html
77
using Clauses with Symbols
def max[T](x: T, y: T)(using ord: Ord[T]): T =
if ord.compare(x, y) < 0 then y else x
def maximum[T](xs: List[T])(using ord: Ord[T]): T =
xs.reduceLeft(max)
def descending[T](using asc: Ord[T]): Ord[T] = new Ord[T] {
def compare(x: T, y: T) = asc.compare(y, x)
}
def minimum[T](xs: List[T])(using ord: Ord[T]) =
maximum(xs)(using descending)
78
Anonymous using Clauses (without Symbols)
def max[T](x: T, y: T)(using Ord[T]): T =
if summon[Ord[T]].compare(x, y) < 0 then y else x
def maximum[T](xs: List[T])(using Ord[T]): T =
xs.reduceLeft(max)
def descending[T](using Ord[T]): Ord[T] = new Ord[T] {
def compare(x: T, y: T) = summon[Ord[T]].compare(y, x)
}
def minimum[T](xs: List[T])(using Ord[T]) =
maximum(xs)(using descending)
79
Usages
» When passing a given explicitly, the keyword using is required in front of the symbol.
val xs = List(1, 2, 3)
max(2, 3) // max of two Ints
max(2, 3)(using intOrd) // max of two Ints - passing the given explicitly
max(xs, Nil) // max of two Lists
minimum(xs) // minimum element of a List
maximum(xs)(using descending) // maximum element of a List (in desc order)
80
Context Bounds21
» These remain nearly unchanged.
» A context bound is syntactic sugar for the last using clause of a method.
// using an anonymous given
def maximum[T](xs: List[T])(using Ord[T]): T =
xs.reduceLeft(max)
// using context bound
def maximum[T: Ord](xs: List[T]): T =
xs.reduceLeft(max)
21 
https://dotty.epfl.ch/docs/reference/contextual/context-bounds.html
81
Given Imports22
object A:
class TC
given tc: TC = ???
def f(using TC) = ???
object B:
import A.* // imports all members of A except the given instances
import A.given // imports only the given instances of A
object C:
import A.{given, *} // import givens and non-givens with a single import
object D:
import A.TC
import A.{given TC} // importing by type
22 
https://dotty.epfl.ch/docs/reference/contextual/given-imports.html
82
Type Lambdas23
23 
https://dotty.epfl.ch/docs/reference/new-types/type-lambdas.html
83
Type Lambdas
» Type Lambdas are new feature in Scala 3.
» Type Lambdas can be expressed in Scala 2 using a weird syntax with type alias and
type projection.
» The kind-projector compiler plugin brought a more convenient type lambda syntax
to Scala 2.
» Type projections are dropped from Scala 3.24
» Type lambdas remove the need for the kind-projector compiler plugin.
24 
https://dotty.epfl.ch/docs/reference/dropped-features/type-projection.html
84
Type Lambdas
» A type lambda lets one express a higher-kinded type directly, without a type definition.
» Type parameters of type lambdas can have variances and bounds.
A parameterized type definition or declaration such as
type T[X] = (X, X)
is a shorthand for a plain type definition with a type-lambda as its right-hand side:
type T = [X] =>> (X, X)
85
Type Lambda Example: Either Monad Instance
// Scala 2 without kind-projector
implicit def eitherMonad[L]: Monad[({type lambda[x] = Either[L, x]})#lambda] = ...
// Scala 2 using kind-projector
implicit def eitherMonad[L]: Monad[lambda[x => Either[L, x]]] = ...
// Scala 2 using kind-projector with * syntax (use ? in older versions of kind-projector)
implicit def eitherMonad[L]: Monad[Either[L, *]] = ...
// Scala 3 using a type lambda
given eitherMonad[L]: Monad[[R] =>> Either[L, R]] with
...
// Scala 3 using compiler option -Ykind-projector
given eitherMonad[L]: Monad[Either[L, *]] with
...
86
Typeclasses26
(Monad Example)
26 
https://dotty.epfl.ch/docs/reference/contextual/type-classes.html
87
Typeclasses: Monad Trait
trait Functor[F[?]]:
extension [A, B](x: F[A])
def map (f: A => B): F[B]
trait Monad[F[?]] extends Functor[F]:
def pure[A](a: A): F[A]
extension [A, B](fa: F[A])
def flatMap (f: A => F[B]): F[B]
extension [A, B](fa: F[A])
override def map (f: A => B): F[B] = flatMap(fa)(f andThen pure)
extension [A](fa: F[F[A]])
def flatten: F[A] = flatMap(fa)(identity)
88
Typeclasses: Monad Trait
- Type class Ord defined an Ordering for some type A.
- Ord was polymorphic and parameterized with type A.
- Functor and Monad are parameterized with the higher-kinded type
F[_]. (Higher-kinded polymorphism)
89
Typeclasses: Monad Instances
given Monad[List] with
override def pure[A](a: A): List[A] = List(a)
extension [A, B](fa: List[A])
override def flatMap(f: A => List[B]): List[B] =
fa flatMap f
given Monad[Option] with
override def pure[A](a: A): Option[A] = Some(a)
extension[A, B](fa: Option[A])
override def flatMap(f: A => Option[B]): Option[B] =
fa flatMap f
given[L]: Monad[Either[L, *]] with // requires -Ykind-projector
override def pure[A](a: A): Either[L, A] = Right(a)
extension [A, B](fa: Either[L, A])
override def flatMap(f: A => Either[L, B]): Either[L, B] =
fa flatMap f
90
Typeclasses: Using the Monad Instances
def compute[F[?]: Monad, A, B](fa: F[A], fb: F[B]): F[(A, B)] =
for
a <- fa
b <- fb
yield (a, b)
val l1 = List(1, 2, 3)
val l2 = List(10, 20, 30)
val lResult = compute(l1, l2) // List((1,10), (1,20), (1,30), (2,10), (2,20), (2,30), (3,10), (3,20), (3,30))
val o1 = Option(1)
val o2 = Option(10)
val oResult = compute(o1, o2) // Some((1,10))
val e1 = Right(1).withLeft[String]
val e2 = Right(10).withLeft[String]
val eResult = compute(e1, e2) // Right((1,10))
91
Opaque Type Aliases27
27 
https://dotty.epfl.ch/docs/reference/other-new-features/opaques.html
92
Opaque Type Aliases
» Opaque types aliases provide type abstractions without any overhead.
» No Boxing !!!
» They are defined like type aliases, but prefixed with the keyword opaque.
» They must be defined within the scope of an object, trait or class.
» The alias definition is visible only within that scope.
» Outside the scope only the defined alias is visible.
» Opaque type aliases are compiled away and have no runtime overhead.
» In Scala 2 one could use Value Classes to avoid boxing. (Many limitations!)
93
object Geometry:
opaque type Length = Double
opaque type Area = Double
object Length:
def apply(d: Double): Length = d
extension (length: Length)
def toDouble: Double = length
object Area:
def apply(d: Double): Area = d
extension (area: Area)
def toDouble: Double = area
94
enum Shape:
case Circle(radius: Length)
case Rectangle(width: Length, height: Length)
def area: Area = this match
case Circle(r) => math.Pi * r * r
case Rectangle(w, h) => w * h
def circumference: Length = this match
case Circle(r) => 2 * math.Pi * r
case Rectangle(w, h) => 2 * w + 2 * h
end Geometry
95
Opaque Type Aliases
» Outside the object Geometry only the types Length and Area are
known.
» These types are not compatible with Double.
» A Double value cannot be assigned to a variable of type Area.
» An Area value cannot be assigned to a variable of type Double.
96
import Geometry._
import Geometry.Shape._
val circle = Circle(Length(1.0))
// val cArea: Double = circle.area // error: found: Area, required: Double
val cArea: Area = circle.area
val cAreaDouble: Double = cArea.toDouble
// val cCircumference: Double = circle.circumference // error: found: Length, required: Double
val cCircumference: Length = circle.circumference
val cCircumferenceDouble: Double = cCircumference.toDouble
97
Polymorphic Function
Types28
28 
https://dotty.epfl.ch/docs/reference/new-types/polymorphic-function-types.html
98
Polymorphic Function Types
» Scala 2 already provides polymorphic methods (but not
polymorphic functions).
» Polymorphic methods could not be turned into functions (there
was no type that could describe them).
» Scala 3 provides polymorphic functions and polymorphic function
types.
99
Polymorphic Function Types
// A polymorphic method:
def foo[A](xs: List[A]): List[A] = xs.reverse
// A polymorphic function value:
val bar: [A] => List[A] => List[A]
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// a polymorphic function type
= [A] => (xs: List[A]) => foo[A](xs)
foo[Int](List(1, 2, 3)) // List(3, 2, 1)
bar[Int](List(1, 2, 3)) // List(3, 2, 1)
100
Dependent Function
Types28a
28a 
https://dotty.epfl.ch/docs/reference/new-types/dependent-function-types.html
101
Dependent Function Types
» In a dependent method the result type refers to a parameter of the
method.
» Scala 2 already provides dependent methods (but not dependent
functions).
» Dependent methods could not be turned into functions (there was
no type that could describe them).
102
trait Entry { type Key; val key: Key }
def extractKey(e: Entry): e.Key = e.key // a dependent method (also in Scala 2)
val extractor: (e: Entry) => e.Key = extractKey // a dependent function value
// ║ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ║
// ║ Dependent ║
// ║ Function Type ║
// ╚════════════════╝
val intEntry = new Entry { type Key = Int; val key = 42 }
val stringEntry = new Entry { type Key = String; val key = "foo" }
val intKey1 = extractKey(intEntry) // 42
val intKey2 = extractor(intEntry) // 42
val stringKey1 = extractKey(stringEntry) // "foo"
val stringKey2 = extractor(stringEntry) // "foo"
assert(intKey1 == intKey2)
assert(stringKey1 == stringKey2)
103
Context Functions29
29 
https://dotty.epfl.ch/docs/reference/contextual/context-functions.html
104
Context Functions
» Context functions are functions with (only) context parameters.
» They resemble methods with only implicit parameters.
» Their types are context function types.
» They are written using ?=> as the "arrow" sign.
Context Function Literals
» Like their types, context function literals are written using ?=>.
» They differ from normal function literals:
» Their types are context function types.
105
Example: Executable
type Executable[T] = ExecutionContext ?=> T
given ec: ExecutionContext = ExecutionContext.global
def f(x: Int): Executable[Int] = {
val result: AtomicInteger = AtomicInteger(0)
def runOnEC(using ec: ExecutionContext): Int =
ec.execute(() => result.set(x * x)) // execute a Runnable
Thread.sleep(100L) // just for demo: wait for the Runnable to be executed
result.get
runOnEC
}
val res1: Int = f(2) //=> 4 // ExecutionContext resolved implicitly
val res2: Int = f(2)(using ec) //=> 4 // ExecutionContext passed explicitly
106
Example: PostConditions
object PostConditions:
opaque type WrappedResult[T] = T
def result[T](using r: WrappedResult[T]): T = r
extension [T](x: T)
def ensuring(condition: WrappedResult[T] ?=> Boolean): T =
assert(condition(using x))
x
import PostConditions.{ensuring, result}
val sum = List(1, 2, 3).sum.ensuring(result == 6)
println(s"sum = $sum") // sum = 6
107
Tuples are HLists
108
Tuples are HLists
» Tuples and HList express the same semantic concept.
» Scala 3 provides Tuple syntax (like Scala 2) and HList syntax to express
this concept.
» Both are completely equivalent.
» In Scala 2 Tuple members are limited to 22, in Scala 3 unlimited.
» shapeless3 must no longer convert between Tuples and HLists.
» new List-like methods for Tuple
109
Tuples are HLists
// Scala 2 + 3: Tuple syntax
val isb1: (Int, String, Boolean) = (42, "foo", true)
// Scala 3: HList syntax
val isb2: Int *: String *: Boolean *: EmptyTuple = 42 *: "foo" *: true *: EmptyTuple
// HList in Scala 2 with 'shapeless'
// val isb3: Int :: String :: Boolean :: HNil = 42 :: "foo" :: true :: HNil
summon[(Int, String, Boolean) =:= Int *: String *: Boolean *: EmptyTuple] // identical types
assert(isb1 == isb2) // identical values
110
New List-like methods on Tuple30
» *: (prepend), ++ (concat), size, take, drop, zip, map
isb1.size // 3
isb1 ++ isb2 // (42,foo,true,42,foo,true)
(isb1 ++ isb2).splitAt(2) // ((42,foo),(true,42,foo,true))
isb1.take(2) // (42,foo)
isb1.drop(1) // (foo,true)
isb1.zip(isb2) // ((42,42),(foo,foo),(true,true))
isb1.map([T] => (x: T) => Option[T](x)) // (Some(42),Some(foo),Some(true))
isb1.map([T] => (x: T) => List[T](x, x)) // (List(42, 42),List(foo, foo),List(true, true))
30 
https://dotty.epfl.ch/api/scala/Tuple.html
111
Explicit Nulls31
31 
https://dotty.epfl.ch/docs/reference/other-new-features/explicit-nulls.html
112
Explicit Nulls
» Explicit nulls are an opt-in feature, enabled via the -Yexplicit-nulls compiler flag.
» This modifies the Scala type system, making reference types (anything that extends AnyRef) non-nullable.
» Explicit nulls change the type hierarchy, so that Null is only a subtype of Any, as opposed to every reference type.
» After erasure, Null remains a subtype of all reference types (as forced by the JVM).
» T | Null expresses nullability. It is the type of a nullable value.
// error: found `Null`, but required `String`
val s1: String = null
// Ok
val s2: String | Null = null
113
Explicit Nulls: Unsoundness
» There are still instances where an expression has a non-nullable type like String, but its value
is null.
» The unsoundness occurs in corner cases, because uninitialized fields in a class start out as
null.
class C:
val f: String = foo(f)
def foo(f2: String|Null): String = if (f2 == null) "field is null" else f2
val c = new C()
// c.f == "field is null"
114
Explicit Nulls: Equality Checks
» Comparison between AnyRef and Null (using ==, !=, eq or ne) is no longer allowed.
» null can only be compared with Null, nullable union (T | Null), or Any type.
val x: String = "foo"
val y: String | Null = "foo"
x == null // error: Values of types String and Null cannot be compared with == or !=
x eq null // error
"hello" == null // error
y == null // ok
y == x // ok
(x: String | Null) == null // ok
(x: Any) == null // ok
115
Working with Nulls
» The extension method .nn can "cast away" nullability.
val strOrNull: String|Null = "foo"
val str: String = strOrNull.nn
116
Java Interop
» Java reference types (loaded from source or from byte code) are always nullable.
» Java member types, method parameter types and method return types are patched to be nullable.
» E.g. a Java value or method returning String is patched to return String|Null.
// Java class
class C {
private String member;
public String getValue() { return member; }
}
is (using -Yexplicit-nulls) equivalent to:
// Scala 3 class
class C:
private member: String | Null
def getValue(): String | Null = member
117
Multiversial or Strict
Equality32 32a
32a 
https://heikoseeberger.rocks/2020/01/07/2020-01-07-dotty-4/
32 
https://dotty.epfl.ch/docs/reference/contextual/multiversal-equality.html
118
Universial Equality
» In Scala 2 and Scala 3 you can compare values of any two different types with == and !=.
» These comparisons are not type safe.
» The operators internally use Any#equals.
» This is the heritage of java.lang.Object#equals
final case class Foo()
Foo() == Foo() // true
Foo() == Option(Foo()) // false - but should not compile
119
Multiversial or Strict Equality (1/6)
» Scala 3 gives you strict equality as an opt-in feature.
» Import scala.language.strictEquality or add -language:strictEquality to scalacOptions.
» Enabling this feature prevents successful compilation for all comparisons ...
» ... with some exceptions (see below).
scala.language.strictEquality
Foo() == Foo() // does not compile
Foo() == Option(Foo()) // does not compile
120
Multiversial or Strict Equality (2/6)
» For the types you want to compare you have to provide an CanEqual instance.
given CanEqual[Foo, Foo] = CanEqual.derived
Foo() == Foo() // compiles; result: true
Foo() == Option(Foo()) // does not compile, as we want
121
Multiversial or Strict Equality (3/6)
» You can also use the derives clause when defining your class.
final case class Bar() derives CanEqual
// this is equivalent to
// given CanEqual[Bar, Bar] = CanEqual.derived
Bar() == Bar() // true
Bar() == Option(Bar()) // does not compile
// you can still not compare _Foo_'s with _Bar_'s.
Foo() == Bar() // does not compile
Bar() == Foo() // does not compile
122
Multiversial or Strict Equality (4/6)
» If you want to compare Foo's with Bar's ...
» provide two CanEqual instances which allow the comparison.
given CanEqual[Foo, Bar] = CanEqual.derived
given CanEqual[Bar, Foo] = CanEqual.derived
Foo() == Bar() // compiles; result is false
Bar() == Foo() // compiles; result is false
123
Multiversial or Strict Equality (5/6)
» The Scala standard library provides bidirectional CanEqual instances for several types:
» Numeric types can be compared with each other and with java.lang.Number.
» Boolean can be compared to Boolean and to java.lang.Boolean.
» Char can be compared to Char and to java.lang.Character.
» Seq[T] can be compared to Seq[T] (or any sub type) if their element types can be
compared.
» Set[T] can be compared to Set[T] (or any sub type) if their element types can be compared.
» A subtype of AnyRef can be compared with Null.
124
Multiversial or Strict Equality (6/6)
// Numeric types can be compared with each other and with java.lang.Number.
42 == 42L // true
42 == 42.0 // true
// Seq[T] can be compared to Seq[T] (or any sub type) if their element types can be compared.
List(1, 2, 3) == Vector(1, 2, 3) // true
// A subtype of AnyRef can be compared with Null.
Foo() == null // false
125
Export Clauses33
33 
https://dotty.epfl.ch/docs/reference/other-new-features/export.html
126
Export Clauses a.k.a. Export Aliases
» An export clause syntactically has the same format as an import clause.
» An export clause defines aliases for selected members of an object.
» Exported members are accessible from inside the object as well as from outside ...
» ... even when the aliased object is private.
» Export aliases encourage a best practice: Prefer composition over inheritance.
» They also fill the gap left by deprecated/removed package objects which inherited from
some class or trait.
» A given instance can also be exported, if the exported member is also tagged with given.
127
Export Clauses
class A:
def a1 = 42
def a2 = a1.toString
class B:
private val a = new A
export a.{a2 => aString} // exports a.a2 aliased to aString
val b = new B
// b.a.a1 and b.a.a2 are not directly accessible as a is private in B.
// The export clause makes a.a2 (aliased to aString) accessible as a member of b.
val bString = b.aString ensuring (_ == 42.toString)
128
Match Types34
34 
https://dotty.epfl.ch/docs/reference/new-types/match-types.html
129
Match Types
» Match types are match expressions on the type level.
» The syntax is analogous to match expressions on the value level.
» A match type reduces to one of a number of right hand sides,
depending on the scrutinee type.
130
Match Types
type Elem[X] = X match
case String => Char
case Array[t] => t
case Iterable[t] => t
// proofs
summon[Elem[String] =:= Char]
summon[Elem[Array[Int]] =:= Int]
summon[Elem[List[Float]] =:= Float]
summon[Elem[Nil.type] =:= Nothing]
131
Recursive Match Types
» Match types may be recursive.
type LeafElem[X] = X match
case String => Char
case Array[t] => LeafElem[t]
case Iterable[t] => LeafElem[t]
case AnyVal => X
» Recursive match types may have an upper bound.
type Concat[Xs <: Tuple, +Ys <: Tuple] <: Tuple = Xs match
case EmptyTuple => Ys
case x *: xs => x *: Concat[xs, Ys]
132
inline35
35 
https://dotty.epfl.ch/docs/reference/metaprogramming/inline.html
133
inline
» Scala 3 introduces a new modifier inline, to be used with ...
» ... methods, val's, parameters, conditionals and match expressions.
» val's and parameters, expressions must be fixed at compile time to be
inlinable.
» The compiler guartantees inlining or fails to compile.
» In Scala 2 the @inline annotation was a hint to the compiler to inline if
possible.
134
inline Example
object Config:
inline val logging = false // RHS must be a constant expression (i.e. known at compile time)
object Logger:
inline def log[T](msg: String)(op: => T): T =
if Config.logging // Config.logging is a constant condition known at compile time.
println(s"START: $msg")
val result = op
println(s"END: $msg; result = $result")
result
else
op
» inline method log will always be inlined at the points of call.
» if-then-else with a constant condition will be rewritten to its then- or else-part.
135
Recursive Inline Methods
inline def power(x: Double, inline n: Int): Double = // for inlining n must be a constant.
if n == 0 then 1.0
else if n == 1 then x
else
val y = power(x, n / 2)
if n % 2 == 0 then y * y else y * y * x
power(expr, 10)
// translates to:
// val x = expr
// val y1 = x * x // ^2
// val y2 = y1 * y1 // ^4
// val y3 = y2 * x // ^5
// y3 * y3 // ^10
136
inline Conditionals
» If the condition of an if-then-else expression is a constant expression then it simplifies to the
selected branch.
» When prefixing an if-then-else expression with inline the condition has to be a constant expression.
» This guarantees that the conditional will always simplify.
inline def update(delta: Int) =
inline if delta >= 0 then increaseBy(delta)
else decreaseBy(-delta)
A call update(22) would rewrite to increaseBy(22) as 22 is a compile-time constant.
If update was not called with a constant, this code snippet doesn't compile.
137
Inline Matches
» A match expression in the body of an inline method def may be prefixed by the inline modifier.
» If there is enough static information to unambiguously take a branch, the expression is
reduced to that branch.
» Otherwise a compile-time error is raised that reports that the match cannot be reduced.
inline def g(x: Any) <: Any = inline x match
case x: String => (x, x) // return type: Tuple2[String, String](x, x)
case x: Double => x // return type: Double
val res1: Double = g(1.0d) // Has type 1.0d which is a subtype of Double
val res2: (String, String) = g("test") // Has type (String, String)
138
Typeclass Derivation36
36 
https://dotty.epfl.ch/docs/reference/contextual/derivation.html
139
Typeclass Derivation
» In Scala 2 type class derivation wasn't baked into the language.
» Type class derivation was provided by 3rd party libraries: shapeless, Magnolia.
» These libraries were based on Scala 2 macros.
» Scala 3 comes with low level mechanics for typeclass derivation,
» which are provided primarily for library authors.
» For details see the Dotty documentation
140
Given By-Name
Parameters37
37 
https://dotty.epfl.ch/docs/reference/contextual/by-name-context-parameters.html
141
Given By-Name Parameters
» Implicit parameters can be declared by-name to avoid a divergent
inferred expansion.
» Like a normal by-name parameter the argument for a given
parameter is evaluated lazily on demand.
» This feature is available since Scala 2.13 (but with implicit by-
name parameters).
142
Given By-Name Parameters
trait Codec[T]:
def write(x: T): Unit
given intCodec: Codec[Int]:
def write(x: Int): Unit = println(s"x = $x")
given optionCodec[T](using ev: => Codec[T]): Codec[Option[T]] with // given param ev is evaluated lazily
def write(xo: Option[T]) = xo match
case Some(x) => ev.write(x) // evaluation of ev occurs only in the Some(x) case.
case None => // no evaluation in the None case
val s = summon[Codec[Option[Int]]]
s.write(Some(33))
s.write(None)
143
Improved Implicit
Resolution38
38 
https://dotty.epfl.ch/docs/reference/changed-features/implicit-resolution.html
144
Improved Implicit Resolution
» New algorithm which caches implicit results more aggressively for
performance.
» Types of implicit values and result types of implicit methods must be explicitly
declared.
» Nesting is now taken into account when selecting an implicit.
» Package prefixes no longer contribute to the implicit scope of a type (which was
the case in Scala 2).
» More details and rules in the Dotty documentation
145
Improved Overload
Resolution39
39 
https://dotty.epfl.ch/docs/reference/changed-features/overload-resolution.html
146
Looking Beyond the First Argument List
» Overloading resolution now do not only take the first argument list into account when choosing among a set of
overloaded alternatives.
def f(x: Int)(y: String): Int = 0
def f(x: Int)(y: Int): Int = 0
f(3)("") // ok, but ambiguous overload error in Scala 2
def g(x: Int)(y: Int)(z: Int): Int = 0
def g(x: Int)(y: Int)(z: String): Int = 0
g(2)(3)(4) // ok // but ambiguous overload error in Scala 2
g(2)(3)("") // ok // but ambiguous overload error in Scala 2
147
Parameter Types of Function Values
» Improved handling of function values with missing parameter types
def f(x: Int)(y: String): Int = 0
def f(x: Int)(y: Int): Int = 0
def h(x: Int, h: Int => Int) = f(x)
def h(x: String, h: String => String) = f(x)
h(40, _ + 2) // ok // but missing parameter type error in Scala 2
h("a", _.toUpperCase) // ok without -explicit-nulls // but missing parameter type error in Scala 2
h("a", _.toUpperCase.nn) // .nn needed with -explicit-nulls
148
Parameter Untupling40
40 
https://dotty.epfl.ch/docs/reference/other-new-features/parameter-untupling.html
149
Parameter Untupling
» In a mapping (or other) function you pattern match the tuples to dissect them into their parts.
» Scala 3 can untuple the tuples into a parameter list of elements.
» So you can omit the keyword case.
val l1 = List(1, 2, 3)
val l2 = List(10, 20, 30)
val tuples: List[(Int, Int)] = l1 zip l2
// Scala 2 style mapping function with pattern matching
val sums1 = tuples map { case (x, y) => x + y }
// Scala 3 style mapping function with untupled parameters
val sums2 = tuples map { (x, y) => x + y }
val sums3 = tuples map { _ + _ }
150
Other Features
151
Dropped Scala 2 Features
» Dropped: Limit 22 for Tuples and Functions
» Dropped: Procedure Syntax
» Dropped: Symbol Literals
» Dropped: DelayedInit
» Dropped: Auto-Application
» Dropped: Early Initializers
» Dropped: Existential Types
» Dropped: General Type Projection
» Dropped: Scala 2 Macros
» and more ...
152
New or Changed Features
» Open Classes
» Improved Lazy Vals Initialization
» Kind Polymorphism
» Tupled Function
» Option-less pattern matching
» Macros: Quotes and Splices
» and more ...
153
Resources
154
Links
» This presentation: code and slides
https://github.com/hermannhueck/taste-of-dotty
» Dotty Documention
https://dotty.epfl.ch/docs/
155
Talks
» Martin Odersky at ScalaSphere Krakow: Revisiting Implicits (published October 2019)
https://www.youtube.com/watch?v=h4dS5WRGJtE
» Nicolas Stucki at ScalaDays Lausanne: Metaprogramming in Dotty (published July 2019)
https://www.youtube.com/watch?v=ZfDS_gJyPTc
» Guillaume Martres at ScalaDays Lausanne: Future proofing Scala through TASTY (published
July 2019)
https://www.youtube.com/watch?v=zQFjC3zLYwo
» Guillaume Martres at ScalaWorld GB: Scala 3, Type Inference and You! (published September
2019)
https://www.youtube.com/watch?v=lMvOykNQ4zs
156
More Talks
» Lukas Rytz at ScalaDays Lausanne: How are we going to migrate to Scala 3.0, aka Dotty? (published July
2019)
https://www.youtube.com/watch?v=KUl1Ilcf0b8
» Sébastien Doeraene at ScalaSphere Krakov: How will TASTy affect the Scala ecosystem, exactly?
(published January 2020)
https://www.youtube.com/watch?v=_N7zNhLdB1Y
» Josh Suereth & James Ward at Devoxx Belgium: What's coming in Scala 3 (published November 2019)
https://www.youtube.com/watch?v=Nv-BzYOMiWY
» Jamie Thompson at f(by) 2020:
Taste the difference with Scala 3: Migrating the ecosystem and more (published February 2020)
https://www.youtube.com/watch?v=YQmVrUdx8TU
157
Thank You !
Questions ?
https://github.com/hermannhueck/taste-of-dotty
158

Mais conteúdo relacionado

Mais procurados

If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongMario Fusco
 
Map(), flatmap() and reduce() are your new best friends: simpler collections,...
Map(), flatmap() and reduce() are your new best friends: simpler collections,...Map(), flatmap() and reduce() are your new best friends: simpler collections,...
Map(), flatmap() and reduce() are your new best friends: simpler collections,...Chris Richardson
 
Java programming lab_manual_by_rohit_jaiswar
Java programming lab_manual_by_rohit_jaiswarJava programming lab_manual_by_rohit_jaiswar
Java programming lab_manual_by_rohit_jaiswarROHIT JAISWAR
 
Advanced Debugging Using Java Bytecodes
Advanced Debugging Using Java BytecodesAdvanced Debugging Using Java Bytecodes
Advanced Debugging Using Java BytecodesGanesh Samarthyam
 
Programming in Scala: Notes
Programming in Scala: NotesProgramming in Scala: Notes
Programming in Scala: NotesRoberto Casadei
 
Metaprogramming in Scala 2.10, Eugene Burmako,
Metaprogramming  in Scala 2.10, Eugene Burmako, Metaprogramming  in Scala 2.10, Eugene Burmako,
Metaprogramming in Scala 2.10, Eugene Burmako, Vasil Remeniuk
 
Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2José Paumard
 
Planet-HTML5-Game-Engine Javascript Performance Enhancement
Planet-HTML5-Game-Engine Javascript Performance EnhancementPlanet-HTML5-Game-Engine Javascript Performance Enhancement
Planet-HTML5-Game-Engine Javascript Performance Enhancementup2soul
 
Functional Algebra: Monoids Applied
Functional Algebra: Monoids AppliedFunctional Algebra: Monoids Applied
Functional Algebra: Monoids AppliedSusan Potter
 
Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Jonas Bonér
 
Java programming lab manual
Java programming lab manualJava programming lab manual
Java programming lab manualsameer farooq
 
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014Susan Potter
 
Implementing the IO Monad in Scala
Implementing the IO Monad in ScalaImplementing the IO Monad in Scala
Implementing the IO Monad in ScalaHermann Hueck
 

Mais procurados (20)

If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are Wrong
 
Java 8: the good parts!
Java 8: the good parts!Java 8: the good parts!
Java 8: the good parts!
 
Map(), flatmap() and reduce() are your new best friends: simpler collections,...
Map(), flatmap() and reduce() are your new best friends: simpler collections,...Map(), flatmap() and reduce() are your new best friends: simpler collections,...
Map(), flatmap() and reduce() are your new best friends: simpler collections,...
 
Java Class Design
Java Class DesignJava Class Design
Java Class Design
 
Java Lab Manual
Java Lab ManualJava Lab Manual
Java Lab Manual
 
Scala coated JVM
Scala coated JVMScala coated JVM
Scala coated JVM
 
Java programming lab_manual_by_rohit_jaiswar
Java programming lab_manual_by_rohit_jaiswarJava programming lab_manual_by_rohit_jaiswar
Java programming lab_manual_by_rohit_jaiswar
 
Advanced Debugging Using Java Bytecodes
Advanced Debugging Using Java BytecodesAdvanced Debugging Using Java Bytecodes
Advanced Debugging Using Java Bytecodes
 
Programming in Scala: Notes
Programming in Scala: NotesProgramming in Scala: Notes
Programming in Scala: Notes
 
Metaprogramming in Scala 2.10, Eugene Burmako,
Metaprogramming  in Scala 2.10, Eugene Burmako, Metaprogramming  in Scala 2.10, Eugene Burmako,
Metaprogramming in Scala 2.10, Eugene Burmako,
 
Java 8 Lambda Expressions
Java 8 Lambda ExpressionsJava 8 Lambda Expressions
Java 8 Lambda Expressions
 
Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2
 
Planet-HTML5-Game-Engine Javascript Performance Enhancement
Planet-HTML5-Game-Engine Javascript Performance EnhancementPlanet-HTML5-Game-Engine Javascript Performance Enhancement
Planet-HTML5-Game-Engine Javascript Performance Enhancement
 
Functional Algebra: Monoids Applied
Functional Algebra: Monoids AppliedFunctional Algebra: Monoids Applied
Functional Algebra: Monoids Applied
 
Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)
 
Java programming lab manual
Java programming lab manualJava programming lab manual
Java programming lab manual
 
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
 
Implementing the IO Monad in Scala
Implementing the IO Monad in ScalaImplementing the IO Monad in Scala
Implementing the IO Monad in Scala
 
Java Concurrency by Example
Java Concurrency by ExampleJava Concurrency by Example
Java Concurrency by Example
 
Java 8 Workshop
Java 8 WorkshopJava 8 Workshop
Java 8 Workshop
 

Semelhante a A Taste of Dotty

Erik Skytthe - Monitoring Mesos, Docker, Containers with Zabbix | ZabConf2016
Erik Skytthe - Monitoring Mesos, Docker, Containers with Zabbix | ZabConf2016Erik Skytthe - Monitoring Mesos, Docker, Containers with Zabbix | ZabConf2016
Erik Skytthe - Monitoring Mesos, Docker, Containers with Zabbix | ZabConf2016Zabbix
 
Getting started with Clojure
Getting started with ClojureGetting started with Clojure
Getting started with ClojureJohn Stevenson
 
Terraform modules restructured
Terraform modules restructuredTerraform modules restructured
Terraform modules restructuredAmi Mahloof
 
Terraform Modules Restructured
Terraform Modules RestructuredTerraform Modules Restructured
Terraform Modules RestructuredDoiT International
 
Database Performance Tuning
Database Performance Tuning Database Performance Tuning
Database Performance Tuning Arno Huetter
 
Scala Talk at FOSDEM 2009
Scala Talk at FOSDEM 2009Scala Talk at FOSDEM 2009
Scala Talk at FOSDEM 2009Martin Odersky
 
scala.reflect, Eugene Burmako
scala.reflect, Eugene Burmakoscala.reflect, Eugene Burmako
scala.reflect, Eugene BurmakoVasil Remeniuk
 
Евгений Бурмако «scala.reflect»
Евгений Бурмако «scala.reflect»Евгений Бурмако «scala.reflect»
Евгений Бурмако «scala.reflect»e-Legion
 
Dax Declarative Api For Xml
Dax   Declarative Api For XmlDax   Declarative Api For Xml
Dax Declarative Api For XmlLars Trieloff
 
Discover Tasty Query: The library for Scala program analysis
Discover Tasty Query: The library for Scala program analysisDiscover Tasty Query: The library for Scala program analysis
Discover Tasty Query: The library for Scala program analysisJames Thompson
 
Introduction To Apache Mesos
Introduction To Apache MesosIntroduction To Apache Mesos
Introduction To Apache MesosJoe Stein
 
Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...
Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...
Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...HostedbyConfluent
 
Presentation of Python, Django, DockerStack
Presentation of Python, Django, DockerStackPresentation of Python, Django, DockerStack
Presentation of Python, Django, DockerStackDavid Sanchez
 
Fusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with ViewsFusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with ViewsPhilip Schwarz
 
Advanced Swift Generics
Advanced Swift GenericsAdvanced Swift Generics
Advanced Swift GenericsMax Sokolov
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring ClojurescriptLuke Donnet
 

Semelhante a A Taste of Dotty (20)

Erik Skytthe - Monitoring Mesos, Docker, Containers with Zabbix | ZabConf2016
Erik Skytthe - Monitoring Mesos, Docker, Containers with Zabbix | ZabConf2016Erik Skytthe - Monitoring Mesos, Docker, Containers with Zabbix | ZabConf2016
Erik Skytthe - Monitoring Mesos, Docker, Containers with Zabbix | ZabConf2016
 
Lobos Introduction
Lobos IntroductionLobos Introduction
Lobos Introduction
 
Getting started with Clojure
Getting started with ClojureGetting started with Clojure
Getting started with Clojure
 
Terraform modules restructured
Terraform modules restructuredTerraform modules restructured
Terraform modules restructured
 
Terraform Modules Restructured
Terraform Modules RestructuredTerraform Modules Restructured
Terraform Modules Restructured
 
Scala active record
Scala active recordScala active record
Scala active record
 
Database Performance Tuning
Database Performance Tuning Database Performance Tuning
Database Performance Tuning
 
Scala Talk at FOSDEM 2009
Scala Talk at FOSDEM 2009Scala Talk at FOSDEM 2009
Scala Talk at FOSDEM 2009
 
SCALA - Functional domain
SCALA -  Functional domainSCALA -  Functional domain
SCALA - Functional domain
 
Ruby On Rails
Ruby On RailsRuby On Rails
Ruby On Rails
 
scala.reflect, Eugene Burmako
scala.reflect, Eugene Burmakoscala.reflect, Eugene Burmako
scala.reflect, Eugene Burmako
 
Евгений Бурмако «scala.reflect»
Евгений Бурмако «scala.reflect»Евгений Бурмако «scala.reflect»
Евгений Бурмако «scala.reflect»
 
Dax Declarative Api For Xml
Dax   Declarative Api For XmlDax   Declarative Api For Xml
Dax Declarative Api For Xml
 
Discover Tasty Query: The library for Scala program analysis
Discover Tasty Query: The library for Scala program analysisDiscover Tasty Query: The library for Scala program analysis
Discover Tasty Query: The library for Scala program analysis
 
Introduction To Apache Mesos
Introduction To Apache MesosIntroduction To Apache Mesos
Introduction To Apache Mesos
 
Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...
Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...
Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...
 
Presentation of Python, Django, DockerStack
Presentation of Python, Django, DockerStackPresentation of Python, Django, DockerStack
Presentation of Python, Django, DockerStack
 
Fusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with ViewsFusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with Views
 
Advanced Swift Generics
Advanced Swift GenericsAdvanced Swift Generics
Advanced Swift Generics
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring Clojurescript
 

Mais de Hermann Hueck

Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!Hermann Hueck
 
From Function1#apply to Kleisli
From Function1#apply to KleisliFrom Function1#apply to Kleisli
From Function1#apply to KleisliHermann Hueck
 
From Functor Composition to Monad Transformers
From Functor Composition to Monad TransformersFrom Functor Composition to Monad Transformers
From Functor Composition to Monad TransformersHermann Hueck
 
Reactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaReactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaHermann Hueck
 
Reactive Access to MongoDB from Java 8
Reactive Access to MongoDB from Java 8Reactive Access to MongoDB from Java 8
Reactive Access to MongoDB from Java 8Hermann Hueck
 
Implementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickImplementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickHermann Hueck
 

Mais de Hermann Hueck (6)

Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!
 
From Function1#apply to Kleisli
From Function1#apply to KleisliFrom Function1#apply to Kleisli
From Function1#apply to Kleisli
 
From Functor Composition to Monad Transformers
From Functor Composition to Monad TransformersFrom Functor Composition to Monad Transformers
From Functor Composition to Monad Transformers
 
Reactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaReactive Access to MongoDB from Scala
Reactive Access to MongoDB from Scala
 
Reactive Access to MongoDB from Java 8
Reactive Access to MongoDB from Java 8Reactive Access to MongoDB from Java 8
Reactive Access to MongoDB from Java 8
 
Implementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickImplementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with Slick
 

Último

Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech studentsHimanshiGarg82
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfproinshot.com
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesVictorSzoltysek
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfonteinmasabamasaba
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptxBUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptxalwaysnagaraju26
 
ManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide DeckManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide DeckManageIQ
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 

Último (20)

Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptxBUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
 
ManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide DeckManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide Deck
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 

A Taste of Dotty

  • 1. A Taste of Dotty copyright 2021 Hermann Hueck https://github.com/hermannhueck/taste-of-dotty 1
  • 2. Abstract This presentation is an introduction to Dotty / Scala 3 and an overview of many features. It covers those features which I deem most important for Scala application developers. For detailed information see the Dotty documentation. The code examples are partly my own. I also took many examples (unchanged or modified) from the Dotty Documentation. The presentation also contains many links to specific chapters in the Dotty docs. 2
  • 3. Agenda (1/3) » Design Goals » TASTy » Project Setup » Using Scala 2 Libraries » Top Level def's and val's » Indentation / Optional Braces » New Control Syntax » Main Methods » Constructor Invocations w/o new » Traits Parameters » Enums and ADTs » Intersection Types 3
  • 4. Agenda (2/3) » Union Types » Contextual Abstractions » Implicit Conversions » Extension Methods » Givens » Type Lambdas » Typeclasses » Opaque Type Aliases » Polymorphic Function Types » Dependent Function Types » Context Functions » Tuples are HLists 4
  • 5. Agenda (3/3) » Explicit Nulls » Multiversial or Strict Equality » Export Clauses » Match Types » inline » Typeclass Derivation » Given By-Name Parameters » Implicit Resolution » Overload Resolution » Other Features » Resources 5
  • 7. Design Goals » build on strong foundations (DOT Calculus) » improve language consistency, » eliminate surprising behaviours, puzzlers » better (type) safety and ergonomics, simplify where possible » improve performance 7
  • 9. What is TASTy? - (Typed Abstract Syntax Trees) » Tasty is the high-level interchange (serialization) format for Scala 3. » Represents the syntactic structure of programs and also contains complete information about types and positions. » The Tasty “snapshot” of a code file is taken after type checking (so that all types are present and all implicits are elaborated) but before any transformations (so that no information is lost or changed). » Heavily optimized for compactness (approximately same size as class files). » .tasty files are now co-located with .class files. » .tasty files are included in published JARs. 9
  • 10. Image taken from "Preparing for Scala 3" - Martin Odersky's keynote of Scala Days 2018, Berlin 10
  • 12. IDE Support3 » IntelliJ IDEA supports Scala 3. » Metals supports Scala 3. » Metals works with any editor that supports LSP (Language Server Protocol): VS Code, vim, emacs, Sublime Text, Eclipse 3  https://dotty.epfl.ch/docs/usage/ide-support.html 12
  • 13. sbt support » sbt 1.5.x++ supports Scala 3 out of the box. » sbt-dotty plugin is no longer needed since sbt 1.5.0. 13
  • 14. New sbt Project » create new project: sbt new scala/scala3.g8 » (or: sbt new scala/scala3-cross.g8 for a cross-build project) » cd to project directory » start sbt in the project directory » open project in VS Code 14
  • 15. build.sbt val scala3Version = "3.0.0-RC3" lazy val root = project .in(file(".")) .settings( name := "scala3-simple", version := "0.1.0", scalaVersion := scala3Version, libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test" ) 15
  • 17. Using Scala 2 Libraries4 4  https://scalacenter.github.io/scala-3-migration-guide/docs/compatibility/classpath.html 17
  • 18. Using Scala 2 Libraries in Scala 3 » Dotty can already utilize Scala 2 libraries. » This works because Dotty is currently retro-compatible with Scala 2.x. » This allows to migrate your app to Dotty, even before 3rd party dependencies have been migrated. » Caveat: Dotty CANNOT invoke macros defined in Scala 2 libraries. 18
  • 19. Using Scala 2 Libraries in Scala 3 // build.sbt libraryDependencies += ("my.domain" %% "myScala213Lib" % myScala213LibVersion).cross(CrossVersion.for3Use2_13) libraryDependencies ++= Seq( "co.fs2" %% "fs2-core" % fs2Version, "co.fs2" %% "fs2-io" % fs2Version, "org.scalatest" %% "scalatest" % scalaTestVersion % Test ).map(module => module.cross(CrossVersion.for3Use2_13)) 19
  • 20. Using Scala 3 Libraries in Scala 2 » Scala 2.13.5 and higher can utilize Scala 3 libraries. » This works because the Scala 2.13.5+ compiler implements a TASTY reader (enabled by compiler flag -Ytasty-reader). // build.sbt scalaVersion = "2.13.5" scalacOptions += "-Ytasty-reader" // supported by Scala 2.13.5 and higher libraryDependencies += ("my.domain" %% "myScala3Lib" % myScala3LibVersion).cross(CrossVersion.for2_13Use3) 20
  • 21. Migration Comprehensive information about migration can be found in the ... Scala 3 Migration Guide https://scalacenter.github.io/scala-3-migration-guide/ 21
  • 22. Top Level def's and val's5 5  https://dotty.epfl.ch/docs/reference/dropped-features/package-objects.html 22
  • 23. Top Level def's and val's » Scala 2: def's and val's must be defined in a trait, class or object. » Scala 3: def's and val's can be defined at the top level. » Scala 2: To provide def's and val's directly in a package, one has to use package objects. » Scala 3: Package objects are still available in 3.0, but will be deprecated and removed in 3.1 or 3.2. 23
  • 24. val r = scala.util.Random def randomInt(): Int = r.nextInt def printBoxed(value: Any): Unit = println(boxed(value)) def boxed(value: Any): String = val line = "u2500" * 50 s"$linen${value.toString}n$line" @main def topLevelDefsAndVals() = printBoxed(randomInt()) 24
  • 26. Indentation / Optional Braces » Braces are optional. » Without braces identation becomes significant to delimit a block of code. » An colon at the end of the line starts a new indentation block. » end markers are optional. 26
  • 27. » with braces: // Scala 2 + 3: trait MyTrait { def boxed(value: Any): String = { val line = "u2500" * 50 s"$linen${value.toString}n$line" } } » without braces: // Scala 3: trait MyTrait: def boxed(value: Any): String = val line = "u2500" * 50 s"$linen${value.toString}n$line" end MyTrait // optional end marker 27
  • 29. if ... then ... else val x = 42 if x < 0 then -x else x if x < 0 then "negative" else if x == 0 then "zero" else "positive" 29
  • 30. while ... do (while-loop) var x = 42 def f(x: Int): Int = x - 10 while x >= 0 do x = f(x) while x >= 0 do x = f(x) 30
  • 31. for ... do (for-loop) val xs = List(1, 2, 3) val ys = List(10, 20, 30) for x <- xs if x > 0 do println(x * x) for x <- xs y <- ys do println(x + y) 31
  • 32. for ... yield (for-comprehension) val xs = List(1, 2, 3) val ys = List(10, 20, 30) for x <- xs if x > 0 yield x * x for x <- xs y <- ys yield x + y 32
  • 34. Main Methods @main def happyBirthday(age: Int, name: String, others: String*): Unit = val congrats = s"Happy Birthday at age $age to $name" ++ { if others.isEmpty then "" else " and " ++ others.mkString(" and ") } ++ "." println(congrats) 34
  • 35. Main Methods » A @main annotation on a method turns this method into an executable program. » The method must be static, i.e. not defined within a class or trait. » If annotated the method name is arbitrary. » Argument types can not only be Array[String]. » Any argument type is allowed if an instance of typeclass scala.util.FromString is in implicit scope. » Dotty checks the runtime arguments passed against the signature of the main function. 35
  • 37. Constructors without new » When constructing instances the new keyword is optional. » Works not only for case classes but also for regular classes. » Works for Java classes too. » If no apply method is found, the compiler creates apply methods for each constructor. » These constructor proxies bear the same signatures as the constructors and invoke them. val sb = StringBuilder("The keyword 'new'") .append(" is ") .append("optional") .append("!") 37
  • 39. Trait Parameters » Traits can have parameters like classes. » Arguments are evaluated before the trait is initialized. » They replace early initalizers in Scala 2 traits, which have been dropped. trait Greeting(val name: String): def msg = s"How are you, $name" class C extends Greeting("Bob"): println(msg) class D extends C with Greeting("Bill"): // COMPILE ERROR // [error] trait Greeting is already implemented by superclass C // [error] its constructor cannot be called again 39
  • 40. Enums and ADTs11 12 12  https://dotty.epfl.ch/docs/reference/enums/adts.html 11  https://dotty.epfl.ch/docs/reference/enums/enums.html 40
  • 41. Simple Enums » enum is a new keyword. » With enum one can define a type consisting of a set of named values. enum Color: case Red, Green, Blue 41
  • 42. Java compatible Enums » To make your Scala-defined enums usable as Java enums, you can do so by extending java.lang.Enum. enum Color extends java.lang.Enum[Color]: case Red, Green, Blue 42
  • 43. Enums with Parameters » The parameters are defined by using an explicit extends clause. enum Color(val escape: String): case Red extends Color(Console.RED) case Green extends Color(Console.GREEN) case Blue extends Color(Console.BLUE) 43
  • 44. Methods defined for Enums scala> val red = Color.Red val red: Color = Red scala> red.ordinal val res0: Int = 0 Methods defined on the companion object scala> Color.valueOf("Blue") val res0: Color = Blue scala> Color.values val res1: Array[Color] = Array(Red, Green, Blue) 44
  • 45. User-defined members of Enums » It is possible to add your own definitions to an enum. » You can also define your own methods in the enum's companion object. enum Color(val escape: String): case Red extends Color(Console.RED) case Green extends Color(Console.GREEN) case Blue extends Color(Console.BLUE) // user defined method def colored(text: String) = s"$escape$text${Console.RESET}" import Color._ val greenHello = Green.colored("Hello World!") 45
  • 46. ADTs in Scala 2 » In Scala 2 ADTS are expressed as sealed traits with a hierarchy of case classes. » This syntax is still supported in Scala 3. sealed trait Tree[+T] object Tree { case class Leaf[T](elem: T) extends Tree[T] case class Node[T](left: Tree[T], right: Tree[T]) extends Tree[T] } import Tree._ val tree: Tree[Int] = Node(Leaf(1), Node(Leaf(2), Leaf(3))) 46
  • 47. ADTs in Scala 3 » In Scala 3 an ADT can be expressed with enum syntax. enum Tree[+T]: case Leaf(elem: T) extends Tree[T] case Node(left: Tree[T], right: Tree[T]) extends Tree[T] import Tree.* val tree: Tree[Int] = Node(Leaf(1), Node(Leaf(2), Leaf(3))) 47
  • 48. ADTs with Syntactic Sugar » The extends clause can be omitted in many cases. enum Tree[+T]: case Leaf(elem: T) case Node(left: Tree[T], right: Tree[T]) import Tree.* val tree: Tree[Int] = Node(Leaf(1), Node(Leaf(2), Leaf(3))) 48
  • 49. ADTs with Methods » As all other enums, ADTs can define methods. enum Tree[+T]: case Leaf(elem: T) case Node(left: Tree[T], right: Tree[T]) def count: Int = this match case Leaf(_) => 1 case Node(left, right) => left.count + right.count import Tree.* val tree: Tree[Int] = Node(Leaf(1), Node(Leaf(2), Leaf(3))) val count = tree.count // 3 49
  • 51. Intersection Types » Used on types, the & operator creates an intersection type. » The type A & B represents values that are of the type A and B at the same time. » A & B has all members/properties of A and all members/properties of B. » & is commutative: A & B is the same type as B & A. » with ist not commutative: A with B is not exactly the same type as B with A. » Intersection types will - in the long run - replace compound types: A with B 51
  • 52. Intersection Types trait Resettable: def reset(): Unit trait Growable[T]: def add(x: T): Unit def f(x: Resettable & Growable[String]) = x.reset() x.add("first") 52
  • 53. class MyClass(var x : String = "") extends Resettable, Growable[String]: def reset(): Unit = x = "" def add(s: String): Unit = x += s override def toString = s"[$x]" val obj: MyClass = MyClass("foo") // [foo] obj.reset() // [] obj.add("bar") // [bar] obj.add("baz") // [barbaz] f(obj) // [first] 53
  • 55. Union Types » A union type A | B comprises all values of type A and also all values of type B. » Union types are duals of intersection types. » A | B contains all members/properties which A and B have in common. » | is commutative: A | B is the same type as B | A. » Pattern matching is the natural way to decide if an A | B is an A or a B. » Union types are not suited to express coproducts (use enums). » Type inference doesn't give you the least (most specific) supertype. » If you want the least supertype, specify the type explicitly. 55
  • 56. type Hash = Int case class UserName(name: String) case class Password(hash: Hash) def check(what: UserName | Password): String = what match case UserName(name) => name case Password(hash) => hash.toString val name: UserName = UserName("Eve") val password: Password = Password(123) val nameOrPw1 = if true then name else password // : Object = UserName(Eve) val nameOrPw2: UserName | Password = if true then name else password // : UserName | Password = UserName(Eve) 56
  • 57. Contextual Abstractions15 (Implicits in Scala 2) 15  https://dotty.epfl.ch/docs/reference/contextual/motivation.html 57
  • 58. Implicits » Implicits are the fundamental way to abstract over context in Scala 2. » Hard to understand, error-prone, easily misused or overused, many rough edges. » Implicits convey mechanism over intent. » One mechanism used for many different purposes: » implicit conversions » extension methods » providing context » dependency injection » typeclasses 58
  • 59. The new Design in Scala 3 (1/2) » Focus on intent over mechanism » Implicit conversions are hard to misuse. » Concise syntax for extension methods » New keywords given and using » given instances focus on types instead of terms. » using clauses replace implicit parameters. » given imports are distinct from regular imports. 59
  • 60. The new Design in Scala 3 (2/2) » Typeclasses can be expressed in a more concise way. » Context bounds remain unchanged in syntax and semantics. » Typeclass derivation is supported. » Context Functions provide a way to abstract over given clauses. » Implicit By-Name Parameters are an essential tool to define recursive synthesized values without looping. » Multiversal Equality introduces a special typeclass CanEqual to support type safe equality. » Scala 2 implicits remain available in parallel for a long time (backward compatibility). 60
  • 62. Implicit Conversion in Scala 2 implicit def str2Int(s: String): Int = Integer.valueOf(s) val xs = List("foo", "bar", "baz") xs("1") // bar xs("one") // java.lang.NumberFormatException: For input string: "one" 62
  • 63. Implicit Conversion in Scala 3 given Conversion[String, Int] with def apply(s: String): Int = Integer.valueOf(s).nn val xs = List("foo", "bar", "baz") xs("1") // bar xs("one") // java.lang.NumberFormatException: For input string: "one" 63
  • 64. Implicit Conversions » Scala 2 syntax is still available in Scala 3 (backward compat). » Scala 2 syntax can easily be mixed up with other implicit constructs. » In Scala 3 scala.Conversion is a subclass of Function1 defined in package scala. » Implicit Conversions must extend Conversion. package scala abstract class Conversion[-T, +U] extends (T => U) 64
  • 65. Conversion Example case class Token(str: String) given Conversion[String, Token]: def apply(str: String): Token = Token(str) or even more concise: case class Token(str: String) given Conversion[String, Token] = Token(_) 65
  • 67. Extension Methods » Extension methods replace implicit classes of Scala 2. » They are defined using the new key word extension. » The extension keyword is followed by a single parameter, » which is the object on which the extension method(s) is/are defined. » The extension clause is followed by one ore more method definitions. » They can be invoked two ways: method(param) or param.method » This syntax also applies to operators. 67
  • 68. Extension Methods case class Circle(x: Double, y: Double, radius: Double) // Scala 2 extension method: // implicit class CircleExtension(private val c: Circle) extends AnyVal { // @inline def circumference: Double = c.radius * math.Pi * 2 // } extension (c: Circle) def circumference: Double = c.radius * math.Pi * 2 val circle = Circle(0, 0, 1) val cf1 = circle.circumference val cf2 = circumference(circle) assert(cf1 == cf2) 68
  • 69. Collective Extensions » Several extension methods that share the same left-hand parameter type » ... can be bundled with extension » ... moving the common first parameter to the instance. extension [T](xs: List[T]) def second: T = xs.tail.head def third: T = xs.tail.second extension [T](xs: List[T])(using Ordering[T]) // uses an additional implicit parameter def largest(n: Int) = xs.sorted.takeRight(n) 69
  • 71. Givens » given is a new keyword » givens in many ways replace implicits » more concise, less boilerplate » focus on types instead of terms 71
  • 72. Givens: Future Example 1 » Future requires a given ExecutionContext in nearly every method. import scala.concurrent.{Future, ExecutionContext} // implicit val ec: ExecutionContext = ExecutionContext.global // Scala 2 given ec: ExecutionContext = ExecutionContext.global // Scala 3: variable ec can be omitted def someComputation(): Int = ??? val future: Future[Int] = Future { someComputation() } future onComplete { case Success(value) => println(value) case Failure(throwable) => println(throwable) } 72
  • 73. Givens: Future Example 2 » This example provides the ExecutionContext via import. import scala.concurrent.{Future, ExecutionContext} // import ExecutionContext.Implicits.global // Scala 2 import ExecutionContext.Implicits.{given ExecutionContext} def someComputation(): Int = ??? val future: Future[Int] = Future { someComputation() } future onComplete { case Success(value) => println(value) case Failure(throwable) => println(throwable) } 73
  • 74. Given Instances: Ord Example19 // a type class trait Ord[T]: def compare(x: T, y: T): Int extension (x: T) def < (y: T) = compare(x, y) < 0 def > (y: T) = compare(x, y) > 0 Typeclass instances to be defined as given's ... 19  https://dotty.epfl.ch/docs/reference/contextual/givens.html 74
  • 75. given Instances » They replace implicitval's, def's and object's. » They can be defined with only a type omitting a name/symbol. » Symbols - if omitted - are synthesized by the compiler. » The given clause ends with the key word with » followed by a set of method defs implementing the trait (Ord in this case). 75
  • 76. given Instances for Ord // instances with symbols given intOrd: Ord[Int] with def compare(x: Int, y: Int) = ??? given listOrd[T](using ord: Ord[T]): Ord[List[T]] with def compare(xs: List[T], ys: List[T]): Int = ??? // instances without symbols given Ord[Int] with def compare(x: Int, y: Int) = ??? given [T](using Ord[T]): Ord[List[T]] with def compare(xs: List[T], ys: List[T]): Int = ??? 76
  • 77. using Clauses20 » They replace the implicit parameter list. » Multiple using clauses are allowed. » Anonymous using's: Symbols are optional. » given instances can be summoned with the function summon. » summon replaces Scala 2's implicitly. 20  https://dotty.epfl.ch/docs/reference/contextual/using-clauses.html 77
  • 78. using Clauses with Symbols def max[T](x: T, y: T)(using ord: Ord[T]): T = if ord.compare(x, y) < 0 then y else x def maximum[T](xs: List[T])(using ord: Ord[T]): T = xs.reduceLeft(max) def descending[T](using asc: Ord[T]): Ord[T] = new Ord[T] { def compare(x: T, y: T) = asc.compare(y, x) } def minimum[T](xs: List[T])(using ord: Ord[T]) = maximum(xs)(using descending) 78
  • 79. Anonymous using Clauses (without Symbols) def max[T](x: T, y: T)(using Ord[T]): T = if summon[Ord[T]].compare(x, y) < 0 then y else x def maximum[T](xs: List[T])(using Ord[T]): T = xs.reduceLeft(max) def descending[T](using Ord[T]): Ord[T] = new Ord[T] { def compare(x: T, y: T) = summon[Ord[T]].compare(y, x) } def minimum[T](xs: List[T])(using Ord[T]) = maximum(xs)(using descending) 79
  • 80. Usages » When passing a given explicitly, the keyword using is required in front of the symbol. val xs = List(1, 2, 3) max(2, 3) // max of two Ints max(2, 3)(using intOrd) // max of two Ints - passing the given explicitly max(xs, Nil) // max of two Lists minimum(xs) // minimum element of a List maximum(xs)(using descending) // maximum element of a List (in desc order) 80
  • 81. Context Bounds21 » These remain nearly unchanged. » A context bound is syntactic sugar for the last using clause of a method. // using an anonymous given def maximum[T](xs: List[T])(using Ord[T]): T = xs.reduceLeft(max) // using context bound def maximum[T: Ord](xs: List[T]): T = xs.reduceLeft(max) 21  https://dotty.epfl.ch/docs/reference/contextual/context-bounds.html 81
  • 82. Given Imports22 object A: class TC given tc: TC = ??? def f(using TC) = ??? object B: import A.* // imports all members of A except the given instances import A.given // imports only the given instances of A object C: import A.{given, *} // import givens and non-givens with a single import object D: import A.TC import A.{given TC} // importing by type 22  https://dotty.epfl.ch/docs/reference/contextual/given-imports.html 82
  • 84. Type Lambdas » Type Lambdas are new feature in Scala 3. » Type Lambdas can be expressed in Scala 2 using a weird syntax with type alias and type projection. » The kind-projector compiler plugin brought a more convenient type lambda syntax to Scala 2. » Type projections are dropped from Scala 3.24 » Type lambdas remove the need for the kind-projector compiler plugin. 24  https://dotty.epfl.ch/docs/reference/dropped-features/type-projection.html 84
  • 85. Type Lambdas » A type lambda lets one express a higher-kinded type directly, without a type definition. » Type parameters of type lambdas can have variances and bounds. A parameterized type definition or declaration such as type T[X] = (X, X) is a shorthand for a plain type definition with a type-lambda as its right-hand side: type T = [X] =>> (X, X) 85
  • 86. Type Lambda Example: Either Monad Instance // Scala 2 without kind-projector implicit def eitherMonad[L]: Monad[({type lambda[x] = Either[L, x]})#lambda] = ... // Scala 2 using kind-projector implicit def eitherMonad[L]: Monad[lambda[x => Either[L, x]]] = ... // Scala 2 using kind-projector with * syntax (use ? in older versions of kind-projector) implicit def eitherMonad[L]: Monad[Either[L, *]] = ... // Scala 3 using a type lambda given eitherMonad[L]: Monad[[R] =>> Either[L, R]] with ... // Scala 3 using compiler option -Ykind-projector given eitherMonad[L]: Monad[Either[L, *]] with ... 86
  • 88. Typeclasses: Monad Trait trait Functor[F[?]]: extension [A, B](x: F[A]) def map (f: A => B): F[B] trait Monad[F[?]] extends Functor[F]: def pure[A](a: A): F[A] extension [A, B](fa: F[A]) def flatMap (f: A => F[B]): F[B] extension [A, B](fa: F[A]) override def map (f: A => B): F[B] = flatMap(fa)(f andThen pure) extension [A](fa: F[F[A]]) def flatten: F[A] = flatMap(fa)(identity) 88
  • 89. Typeclasses: Monad Trait - Type class Ord defined an Ordering for some type A. - Ord was polymorphic and parameterized with type A. - Functor and Monad are parameterized with the higher-kinded type F[_]. (Higher-kinded polymorphism) 89
  • 90. Typeclasses: Monad Instances given Monad[List] with override def pure[A](a: A): List[A] = List(a) extension [A, B](fa: List[A]) override def flatMap(f: A => List[B]): List[B] = fa flatMap f given Monad[Option] with override def pure[A](a: A): Option[A] = Some(a) extension[A, B](fa: Option[A]) override def flatMap(f: A => Option[B]): Option[B] = fa flatMap f given[L]: Monad[Either[L, *]] with // requires -Ykind-projector override def pure[A](a: A): Either[L, A] = Right(a) extension [A, B](fa: Either[L, A]) override def flatMap(f: A => Either[L, B]): Either[L, B] = fa flatMap f 90
  • 91. Typeclasses: Using the Monad Instances def compute[F[?]: Monad, A, B](fa: F[A], fb: F[B]): F[(A, B)] = for a <- fa b <- fb yield (a, b) val l1 = List(1, 2, 3) val l2 = List(10, 20, 30) val lResult = compute(l1, l2) // List((1,10), (1,20), (1,30), (2,10), (2,20), (2,30), (3,10), (3,20), (3,30)) val o1 = Option(1) val o2 = Option(10) val oResult = compute(o1, o2) // Some((1,10)) val e1 = Right(1).withLeft[String] val e2 = Right(10).withLeft[String] val eResult = compute(e1, e2) // Right((1,10)) 91
  • 93. Opaque Type Aliases » Opaque types aliases provide type abstractions without any overhead. » No Boxing !!! » They are defined like type aliases, but prefixed with the keyword opaque. » They must be defined within the scope of an object, trait or class. » The alias definition is visible only within that scope. » Outside the scope only the defined alias is visible. » Opaque type aliases are compiled away and have no runtime overhead. » In Scala 2 one could use Value Classes to avoid boxing. (Many limitations!) 93
  • 94. object Geometry: opaque type Length = Double opaque type Area = Double object Length: def apply(d: Double): Length = d extension (length: Length) def toDouble: Double = length object Area: def apply(d: Double): Area = d extension (area: Area) def toDouble: Double = area 94
  • 95. enum Shape: case Circle(radius: Length) case Rectangle(width: Length, height: Length) def area: Area = this match case Circle(r) => math.Pi * r * r case Rectangle(w, h) => w * h def circumference: Length = this match case Circle(r) => 2 * math.Pi * r case Rectangle(w, h) => 2 * w + 2 * h end Geometry 95
  • 96. Opaque Type Aliases » Outside the object Geometry only the types Length and Area are known. » These types are not compatible with Double. » A Double value cannot be assigned to a variable of type Area. » An Area value cannot be assigned to a variable of type Double. 96
  • 97. import Geometry._ import Geometry.Shape._ val circle = Circle(Length(1.0)) // val cArea: Double = circle.area // error: found: Area, required: Double val cArea: Area = circle.area val cAreaDouble: Double = cArea.toDouble // val cCircumference: Double = circle.circumference // error: found: Length, required: Double val cCircumference: Length = circle.circumference val cCircumferenceDouble: Double = cCircumference.toDouble 97
  • 99. Polymorphic Function Types » Scala 2 already provides polymorphic methods (but not polymorphic functions). » Polymorphic methods could not be turned into functions (there was no type that could describe them). » Scala 3 provides polymorphic functions and polymorphic function types. 99
  • 100. Polymorphic Function Types // A polymorphic method: def foo[A](xs: List[A]): List[A] = xs.reverse // A polymorphic function value: val bar: [A] => List[A] => List[A] // ^^^^^^^^^^^^^^^^^^^^^^^^^ // a polymorphic function type = [A] => (xs: List[A]) => foo[A](xs) foo[Int](List(1, 2, 3)) // List(3, 2, 1) bar[Int](List(1, 2, 3)) // List(3, 2, 1) 100
  • 102. Dependent Function Types » In a dependent method the result type refers to a parameter of the method. » Scala 2 already provides dependent methods (but not dependent functions). » Dependent methods could not be turned into functions (there was no type that could describe them). 102
  • 103. trait Entry { type Key; val key: Key } def extractKey(e: Entry): e.Key = e.key // a dependent method (also in Scala 2) val extractor: (e: Entry) => e.Key = extractKey // a dependent function value // ║ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ║ // ║ Dependent ║ // ║ Function Type ║ // ╚════════════════╝ val intEntry = new Entry { type Key = Int; val key = 42 } val stringEntry = new Entry { type Key = String; val key = "foo" } val intKey1 = extractKey(intEntry) // 42 val intKey2 = extractor(intEntry) // 42 val stringKey1 = extractKey(stringEntry) // "foo" val stringKey2 = extractor(stringEntry) // "foo" assert(intKey1 == intKey2) assert(stringKey1 == stringKey2) 103
  • 105. Context Functions » Context functions are functions with (only) context parameters. » They resemble methods with only implicit parameters. » Their types are context function types. » They are written using ?=> as the "arrow" sign. Context Function Literals » Like their types, context function literals are written using ?=>. » They differ from normal function literals: » Their types are context function types. 105
  • 106. Example: Executable type Executable[T] = ExecutionContext ?=> T given ec: ExecutionContext = ExecutionContext.global def f(x: Int): Executable[Int] = { val result: AtomicInteger = AtomicInteger(0) def runOnEC(using ec: ExecutionContext): Int = ec.execute(() => result.set(x * x)) // execute a Runnable Thread.sleep(100L) // just for demo: wait for the Runnable to be executed result.get runOnEC } val res1: Int = f(2) //=> 4 // ExecutionContext resolved implicitly val res2: Int = f(2)(using ec) //=> 4 // ExecutionContext passed explicitly 106
  • 107. Example: PostConditions object PostConditions: opaque type WrappedResult[T] = T def result[T](using r: WrappedResult[T]): T = r extension [T](x: T) def ensuring(condition: WrappedResult[T] ?=> Boolean): T = assert(condition(using x)) x import PostConditions.{ensuring, result} val sum = List(1, 2, 3).sum.ensuring(result == 6) println(s"sum = $sum") // sum = 6 107
  • 109. Tuples are HLists » Tuples and HList express the same semantic concept. » Scala 3 provides Tuple syntax (like Scala 2) and HList syntax to express this concept. » Both are completely equivalent. » In Scala 2 Tuple members are limited to 22, in Scala 3 unlimited. » shapeless3 must no longer convert between Tuples and HLists. » new List-like methods for Tuple 109
  • 110. Tuples are HLists // Scala 2 + 3: Tuple syntax val isb1: (Int, String, Boolean) = (42, "foo", true) // Scala 3: HList syntax val isb2: Int *: String *: Boolean *: EmptyTuple = 42 *: "foo" *: true *: EmptyTuple // HList in Scala 2 with 'shapeless' // val isb3: Int :: String :: Boolean :: HNil = 42 :: "foo" :: true :: HNil summon[(Int, String, Boolean) =:= Int *: String *: Boolean *: EmptyTuple] // identical types assert(isb1 == isb2) // identical values 110
  • 111. New List-like methods on Tuple30 » *: (prepend), ++ (concat), size, take, drop, zip, map isb1.size // 3 isb1 ++ isb2 // (42,foo,true,42,foo,true) (isb1 ++ isb2).splitAt(2) // ((42,foo),(true,42,foo,true)) isb1.take(2) // (42,foo) isb1.drop(1) // (foo,true) isb1.zip(isb2) // ((42,42),(foo,foo),(true,true)) isb1.map([T] => (x: T) => Option[T](x)) // (Some(42),Some(foo),Some(true)) isb1.map([T] => (x: T) => List[T](x, x)) // (List(42, 42),List(foo, foo),List(true, true)) 30  https://dotty.epfl.ch/api/scala/Tuple.html 111
  • 113. Explicit Nulls » Explicit nulls are an opt-in feature, enabled via the -Yexplicit-nulls compiler flag. » This modifies the Scala type system, making reference types (anything that extends AnyRef) non-nullable. » Explicit nulls change the type hierarchy, so that Null is only a subtype of Any, as opposed to every reference type. » After erasure, Null remains a subtype of all reference types (as forced by the JVM). » T | Null expresses nullability. It is the type of a nullable value. // error: found `Null`, but required `String` val s1: String = null // Ok val s2: String | Null = null 113
  • 114. Explicit Nulls: Unsoundness » There are still instances where an expression has a non-nullable type like String, but its value is null. » The unsoundness occurs in corner cases, because uninitialized fields in a class start out as null. class C: val f: String = foo(f) def foo(f2: String|Null): String = if (f2 == null) "field is null" else f2 val c = new C() // c.f == "field is null" 114
  • 115. Explicit Nulls: Equality Checks » Comparison between AnyRef and Null (using ==, !=, eq or ne) is no longer allowed. » null can only be compared with Null, nullable union (T | Null), or Any type. val x: String = "foo" val y: String | Null = "foo" x == null // error: Values of types String and Null cannot be compared with == or != x eq null // error "hello" == null // error y == null // ok y == x // ok (x: String | Null) == null // ok (x: Any) == null // ok 115
  • 116. Working with Nulls » The extension method .nn can "cast away" nullability. val strOrNull: String|Null = "foo" val str: String = strOrNull.nn 116
  • 117. Java Interop » Java reference types (loaded from source or from byte code) are always nullable. » Java member types, method parameter types and method return types are patched to be nullable. » E.g. a Java value or method returning String is patched to return String|Null. // Java class class C { private String member; public String getValue() { return member; } } is (using -Yexplicit-nulls) equivalent to: // Scala 3 class class C: private member: String | Null def getValue(): String | Null = member 117
  • 118. Multiversial or Strict Equality32 32a 32a  https://heikoseeberger.rocks/2020/01/07/2020-01-07-dotty-4/ 32  https://dotty.epfl.ch/docs/reference/contextual/multiversal-equality.html 118
  • 119. Universial Equality » In Scala 2 and Scala 3 you can compare values of any two different types with == and !=. » These comparisons are not type safe. » The operators internally use Any#equals. » This is the heritage of java.lang.Object#equals final case class Foo() Foo() == Foo() // true Foo() == Option(Foo()) // false - but should not compile 119
  • 120. Multiversial or Strict Equality (1/6) » Scala 3 gives you strict equality as an opt-in feature. » Import scala.language.strictEquality or add -language:strictEquality to scalacOptions. » Enabling this feature prevents successful compilation for all comparisons ... » ... with some exceptions (see below). scala.language.strictEquality Foo() == Foo() // does not compile Foo() == Option(Foo()) // does not compile 120
  • 121. Multiversial or Strict Equality (2/6) » For the types you want to compare you have to provide an CanEqual instance. given CanEqual[Foo, Foo] = CanEqual.derived Foo() == Foo() // compiles; result: true Foo() == Option(Foo()) // does not compile, as we want 121
  • 122. Multiversial or Strict Equality (3/6) » You can also use the derives clause when defining your class. final case class Bar() derives CanEqual // this is equivalent to // given CanEqual[Bar, Bar] = CanEqual.derived Bar() == Bar() // true Bar() == Option(Bar()) // does not compile // you can still not compare _Foo_'s with _Bar_'s. Foo() == Bar() // does not compile Bar() == Foo() // does not compile 122
  • 123. Multiversial or Strict Equality (4/6) » If you want to compare Foo's with Bar's ... » provide two CanEqual instances which allow the comparison. given CanEqual[Foo, Bar] = CanEqual.derived given CanEqual[Bar, Foo] = CanEqual.derived Foo() == Bar() // compiles; result is false Bar() == Foo() // compiles; result is false 123
  • 124. Multiversial or Strict Equality (5/6) » The Scala standard library provides bidirectional CanEqual instances for several types: » Numeric types can be compared with each other and with java.lang.Number. » Boolean can be compared to Boolean and to java.lang.Boolean. » Char can be compared to Char and to java.lang.Character. » Seq[T] can be compared to Seq[T] (or any sub type) if their element types can be compared. » Set[T] can be compared to Set[T] (or any sub type) if their element types can be compared. » A subtype of AnyRef can be compared with Null. 124
  • 125. Multiversial or Strict Equality (6/6) // Numeric types can be compared with each other and with java.lang.Number. 42 == 42L // true 42 == 42.0 // true // Seq[T] can be compared to Seq[T] (or any sub type) if their element types can be compared. List(1, 2, 3) == Vector(1, 2, 3) // true // A subtype of AnyRef can be compared with Null. Foo() == null // false 125
  • 127. Export Clauses a.k.a. Export Aliases » An export clause syntactically has the same format as an import clause. » An export clause defines aliases for selected members of an object. » Exported members are accessible from inside the object as well as from outside ... » ... even when the aliased object is private. » Export aliases encourage a best practice: Prefer composition over inheritance. » They also fill the gap left by deprecated/removed package objects which inherited from some class or trait. » A given instance can also be exported, if the exported member is also tagged with given. 127
  • 128. Export Clauses class A: def a1 = 42 def a2 = a1.toString class B: private val a = new A export a.{a2 => aString} // exports a.a2 aliased to aString val b = new B // b.a.a1 and b.a.a2 are not directly accessible as a is private in B. // The export clause makes a.a2 (aliased to aString) accessible as a member of b. val bString = b.aString ensuring (_ == 42.toString) 128
  • 130. Match Types » Match types are match expressions on the type level. » The syntax is analogous to match expressions on the value level. » A match type reduces to one of a number of right hand sides, depending on the scrutinee type. 130
  • 131. Match Types type Elem[X] = X match case String => Char case Array[t] => t case Iterable[t] => t // proofs summon[Elem[String] =:= Char] summon[Elem[Array[Int]] =:= Int] summon[Elem[List[Float]] =:= Float] summon[Elem[Nil.type] =:= Nothing] 131
  • 132. Recursive Match Types » Match types may be recursive. type LeafElem[X] = X match case String => Char case Array[t] => LeafElem[t] case Iterable[t] => LeafElem[t] case AnyVal => X » Recursive match types may have an upper bound. type Concat[Xs <: Tuple, +Ys <: Tuple] <: Tuple = Xs match case EmptyTuple => Ys case x *: xs => x *: Concat[xs, Ys] 132
  • 134. inline » Scala 3 introduces a new modifier inline, to be used with ... » ... methods, val's, parameters, conditionals and match expressions. » val's and parameters, expressions must be fixed at compile time to be inlinable. » The compiler guartantees inlining or fails to compile. » In Scala 2 the @inline annotation was a hint to the compiler to inline if possible. 134
  • 135. inline Example object Config: inline val logging = false // RHS must be a constant expression (i.e. known at compile time) object Logger: inline def log[T](msg: String)(op: => T): T = if Config.logging // Config.logging is a constant condition known at compile time. println(s"START: $msg") val result = op println(s"END: $msg; result = $result") result else op » inline method log will always be inlined at the points of call. » if-then-else with a constant condition will be rewritten to its then- or else-part. 135
  • 136. Recursive Inline Methods inline def power(x: Double, inline n: Int): Double = // for inlining n must be a constant. if n == 0 then 1.0 else if n == 1 then x else val y = power(x, n / 2) if n % 2 == 0 then y * y else y * y * x power(expr, 10) // translates to: // val x = expr // val y1 = x * x // ^2 // val y2 = y1 * y1 // ^4 // val y3 = y2 * x // ^5 // y3 * y3 // ^10 136
  • 137. inline Conditionals » If the condition of an if-then-else expression is a constant expression then it simplifies to the selected branch. » When prefixing an if-then-else expression with inline the condition has to be a constant expression. » This guarantees that the conditional will always simplify. inline def update(delta: Int) = inline if delta >= 0 then increaseBy(delta) else decreaseBy(-delta) A call update(22) would rewrite to increaseBy(22) as 22 is a compile-time constant. If update was not called with a constant, this code snippet doesn't compile. 137
  • 138. Inline Matches » A match expression in the body of an inline method def may be prefixed by the inline modifier. » If there is enough static information to unambiguously take a branch, the expression is reduced to that branch. » Otherwise a compile-time error is raised that reports that the match cannot be reduced. inline def g(x: Any) <: Any = inline x match case x: String => (x, x) // return type: Tuple2[String, String](x, x) case x: Double => x // return type: Double val res1: Double = g(1.0d) // Has type 1.0d which is a subtype of Double val res2: (String, String) = g("test") // Has type (String, String) 138
  • 140. Typeclass Derivation » In Scala 2 type class derivation wasn't baked into the language. » Type class derivation was provided by 3rd party libraries: shapeless, Magnolia. » These libraries were based on Scala 2 macros. » Scala 3 comes with low level mechanics for typeclass derivation, » which are provided primarily for library authors. » For details see the Dotty documentation 140
  • 142. Given By-Name Parameters » Implicit parameters can be declared by-name to avoid a divergent inferred expansion. » Like a normal by-name parameter the argument for a given parameter is evaluated lazily on demand. » This feature is available since Scala 2.13 (but with implicit by- name parameters). 142
  • 143. Given By-Name Parameters trait Codec[T]: def write(x: T): Unit given intCodec: Codec[Int]: def write(x: Int): Unit = println(s"x = $x") given optionCodec[T](using ev: => Codec[T]): Codec[Option[T]] with // given param ev is evaluated lazily def write(xo: Option[T]) = xo match case Some(x) => ev.write(x) // evaluation of ev occurs only in the Some(x) case. case None => // no evaluation in the None case val s = summon[Codec[Option[Int]]] s.write(Some(33)) s.write(None) 143
  • 145. Improved Implicit Resolution » New algorithm which caches implicit results more aggressively for performance. » Types of implicit values and result types of implicit methods must be explicitly declared. » Nesting is now taken into account when selecting an implicit. » Package prefixes no longer contribute to the implicit scope of a type (which was the case in Scala 2). » More details and rules in the Dotty documentation 145
  • 147. Looking Beyond the First Argument List » Overloading resolution now do not only take the first argument list into account when choosing among a set of overloaded alternatives. def f(x: Int)(y: String): Int = 0 def f(x: Int)(y: Int): Int = 0 f(3)("") // ok, but ambiguous overload error in Scala 2 def g(x: Int)(y: Int)(z: Int): Int = 0 def g(x: Int)(y: Int)(z: String): Int = 0 g(2)(3)(4) // ok // but ambiguous overload error in Scala 2 g(2)(3)("") // ok // but ambiguous overload error in Scala 2 147
  • 148. Parameter Types of Function Values » Improved handling of function values with missing parameter types def f(x: Int)(y: String): Int = 0 def f(x: Int)(y: Int): Int = 0 def h(x: Int, h: Int => Int) = f(x) def h(x: String, h: String => String) = f(x) h(40, _ + 2) // ok // but missing parameter type error in Scala 2 h("a", _.toUpperCase) // ok without -explicit-nulls // but missing parameter type error in Scala 2 h("a", _.toUpperCase.nn) // .nn needed with -explicit-nulls 148
  • 150. Parameter Untupling » In a mapping (or other) function you pattern match the tuples to dissect them into their parts. » Scala 3 can untuple the tuples into a parameter list of elements. » So you can omit the keyword case. val l1 = List(1, 2, 3) val l2 = List(10, 20, 30) val tuples: List[(Int, Int)] = l1 zip l2 // Scala 2 style mapping function with pattern matching val sums1 = tuples map { case (x, y) => x + y } // Scala 3 style mapping function with untupled parameters val sums2 = tuples map { (x, y) => x + y } val sums3 = tuples map { _ + _ } 150
  • 152. Dropped Scala 2 Features » Dropped: Limit 22 for Tuples and Functions » Dropped: Procedure Syntax » Dropped: Symbol Literals » Dropped: DelayedInit » Dropped: Auto-Application » Dropped: Early Initializers » Dropped: Existential Types » Dropped: General Type Projection » Dropped: Scala 2 Macros » and more ... 152
  • 153. New or Changed Features » Open Classes » Improved Lazy Vals Initialization » Kind Polymorphism » Tupled Function » Option-less pattern matching » Macros: Quotes and Splices » and more ... 153
  • 155. Links » This presentation: code and slides https://github.com/hermannhueck/taste-of-dotty » Dotty Documention https://dotty.epfl.ch/docs/ 155
  • 156. Talks » Martin Odersky at ScalaSphere Krakow: Revisiting Implicits (published October 2019) https://www.youtube.com/watch?v=h4dS5WRGJtE » Nicolas Stucki at ScalaDays Lausanne: Metaprogramming in Dotty (published July 2019) https://www.youtube.com/watch?v=ZfDS_gJyPTc » Guillaume Martres at ScalaDays Lausanne: Future proofing Scala through TASTY (published July 2019) https://www.youtube.com/watch?v=zQFjC3zLYwo » Guillaume Martres at ScalaWorld GB: Scala 3, Type Inference and You! (published September 2019) https://www.youtube.com/watch?v=lMvOykNQ4zs 156
  • 157. More Talks » Lukas Rytz at ScalaDays Lausanne: How are we going to migrate to Scala 3.0, aka Dotty? (published July 2019) https://www.youtube.com/watch?v=KUl1Ilcf0b8 » Sébastien Doeraene at ScalaSphere Krakov: How will TASTy affect the Scala ecosystem, exactly? (published January 2020) https://www.youtube.com/watch?v=_N7zNhLdB1Y » Josh Suereth & James Ward at Devoxx Belgium: What's coming in Scala 3 (published November 2019) https://www.youtube.com/watch?v=Nv-BzYOMiWY » Jamie Thompson at f(by) 2020: Taste the difference with Scala 3: Migrating the ecosystem and more (published February 2020) https://www.youtube.com/watch?v=YQmVrUdx8TU 157
  • 158. Thank You ! Questions ? https://github.com/hermannhueck/taste-of-dotty 158