Skip to content

Commit a45451a

Browse files
authored
Merge pull request #2592 from dotty-staging/add-reference-3
Add docs on changed features
2 parents d11d20f + f14335b commit a45451a

10 files changed

+308
-10
lines changed

docs/docs/reference/adts.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ The changes are specified below as deltas with respect to the Scala syntax given
108108
EnumDef ::= id ClassConstr [`extends' [ConstrApps]]
109109
[nl] `{’ EnumCaseStat {semi EnumCaseStat} `}’
110110

111-
2. Cases of enums are defined as follows:
111+
2. Cases of enums are defined as follows:
112112

113113
EnumCaseStat ::= {Annotation [nl]} {Modifier} EnumCase
114114
EnumCase ::= `case' (EnumClassDef | ObjectDef | ids)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
layout: doc-page
3+
title: "Restrictions to Implicit Conversions"
4+
---
5+
6+
Previously, an implicit value of type `Function1`, or any of its subtypes
7+
could be used as an implicit conversion. That is, the following code would compile
8+
even though it probably masks a type error:
9+
10+
implicit val m: Map[String, Int] = Map(1 -> "abc")
11+
12+
val x: String = 1 // scalac: assigns "abc" to x
13+
// Dotty: type error
14+
15+
By contrast, Dotty only considers _methods_ as implicit conversions, so the
16+
`Map` value `m` above would not qualify as a conversion from `String` to `Int`.
17+
18+
To be able to express implicit conversions passed as parameters, `Dotty`
19+
introduces a new type
20+
21+
abstract class ImplicitConverter[-T, +U] extends Function1[T, U]
22+
23+
Implicit values of type `ImplicitConverter[A, B]` do qualify as implicit
24+
conversions. It is as if there was a global implicit conversion method
25+
26+
def convert[A, B](x: A)(implicit converter: ImplicitConverter[A, B]): B =
27+
converter(x)
28+
29+
(In reality the Dotty compiler simulates the behavior of this method directly in
30+
its type checking because this turns out to be more efficient).
31+
32+
In summary, previous code using implicit conversion parameters such as
33+
34+
def useConversion(implicit f: A => B) {
35+
val y: A = ...
36+
val x: B = a // error under Dotty
37+
}
38+
39+
is no longer legal and has to be rwritten to
40+
41+
def useConversion(implicit f: ImplicitConverter[A, B]) {
42+
val y: A = ...
43+
val x: B = a // OK
44+
}
45+
46+
47+
48+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
layout: doc-page
3+
title: "Changes in Implicit Resolution"
4+
---
5+
6+
Implicit resolution uses a new algorithm which caches implicit results
7+
more aggressively for perforance. There are also some changes that
8+
affect implicits on the language level.
9+
10+
1. Types of implicit values and result types of implicit methods
11+
must be explicitly declared. Excepted are only values in local blocks
12+
where the type may still be inferred:
13+
14+
class C {
15+
16+
val ctx: Context = ... // ok
17+
18+
/*!*/ implicit val x = ... // error: type must be given explicitly
19+
20+
/*!*/ next(): Context = ... // error: type must be given explicitly
21+
22+
val y = {
23+
implicit val ctx = this.ctx // ok
24+
...
25+
}
26+
27+
2. Implicit parameters may not have singleton types.
28+
29+
/*!*/ def f(implicit x: y.type) // error `y.type` not allowed as type of implicit
30+
31+
3. Nesting is now taken into account for selecting an implicit.
32+
Consider for instance the following scenario
33+
34+
def f(implicit i: C) = {
35+
def g(implicit j: C) = {
36+
implicitly[C]
37+
}
38+
}
39+
40+
This will now resolve the `implicitly` call to `j`, because `j` is nested
41+
more deeply than `i`. Previously, this would have resulted in an
42+
ambiguity error.
43+
44+
[//] # todo: expand with precise rules
45+
46+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
layout: doc-page
3+
title: Changed: Lazy Vals and @volatile
4+
---
5+
6+
Lazy val initialization no longer guarantees safe publishing. This change was done
7+
to avoid the performance overhead of thread synchonization because many lazy vals are only used in a single-threaded context.
8+
9+
To get back safe publishing you need to annotate a lazy val with `@volatile`. In
10+
11+
@volatile lazy val x = expr
12+
13+
it is guaranteed that readers of a lazy val will see the value of `x`
14+
once it is assigned.
15+
16+
The [ScalaFix](https://scalacenter.github.io/scalafix/) rewrite tool
17+
as well as Dotty's own `-language:Scala2 -rewrite` option will rewrite all normal
18+
lazy vals to volatile ones in order to keep their semantics compatible
19+
with current Scala's.
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
---
2+
layout: doc-page
3+
title: "Programmatic Structural Types"
4+
---
5+
6+
Previously, Scala supported structural types by means of
7+
reflection. This is problematic on other platforms, because Scala's
8+
reflection is JVM-based. Consequently, Scala.js and Scala.native don't
9+
support structural types fully. The reflction based implementation is
10+
also needlessly restrictive, since it rules out other implementation
11+
schemes. This makes structural types unsuitable for e.g. modelling
12+
rows in a database, for which they would otherwise seem to be an ideal
13+
match.
14+
15+
Dotty allows to implement structural types programmatically, using
16+
"Selectables". `Selectable` is a trait defined as follows:
17+
18+
trait Selectable extends Any {
19+
def selectDynamic(name: String): Any
20+
def selectDynamicMethod(name: String, paramClasses: ClassTag[_]*): Any =
21+
new UnsupportedOperationException("selectDynamicMethod")
22+
}
23+
24+
The most important method of a `Selectable` is `selectDynamic`: It
25+
takes a field name and returns the value associated with that name in
26+
the selectable.
27+
28+
Assume now `r` is a value with structural type `S`.` In general `S` is
29+
of the form `C { Rs }`, i.e. it consists of a class reference `C` and
30+
refinement declarations `Rs`. We call a field selection `r.f`
31+
_structural_ if `f` is a name defined by a declaration in `Rs` whereas
32+
`C` defines no member of name `f`. Assuming the selection has type
33+
`T`, it is mapped to something equivalent to the following code:
34+
35+
(r: Selectable).selectDynamic("f").asInstanceOf[T]
36+
37+
That is, we make sure `r` conforms to type `Selectable`, potentially
38+
by adding an implicit conversion. We then invoke the `get` operation
39+
of that instance, passing the the name `"f"` as a parameter. We
40+
finally cast the resulting value back to the statically known type
41+
`T`.
42+
43+
`Selectable` also defines another access method called
44+
`selectDynamicMethod`. This operation is used to select methods
45+
instead of fields. It gets passed the class tags of the selected
46+
method's formal parameter types as additional arguments. These can
47+
then be used to disambiguate one of several overloaded variants.
48+
49+
Package `scala.reflect` contains an implicit conversion which can map
50+
any value to a selectable that emulates reflection-based selection, in
51+
a way similar to what was done until now:
52+
53+
package scala.reflect
54+
55+
object Selectable {
56+
implicit def reflectiveSelectable(receiver: Any): scala.Selectable =
57+
receiver match {
58+
case receiver: scala.Selectable => receiver
59+
case _ => new scala.reflect.Selectable(receiver)
60+
}
61+
}
62+
63+
When imported, `reflectiveSelectable` provides a way to access fields
64+
of any structural type using Java reflection. This is similar to the
65+
current implementation of structural types. The main difference is
66+
that to get reflection-based structural access one now has to add an
67+
import:
68+
69+
import scala.relect.Selectable.reflectiveSelectable
70+
71+
On the other hand, the previously required language feature import of
72+
`reflectiveCalls` is now redundant and is therefore dropped.
73+
74+
As you can see from its implementation above, `reflectSelectable`
75+
checks first whether its argument is already a run-time instance of
76+
`Selectable`, in which case it is returned directly. This means that
77+
reflection-based accesses only take place as a last resort, if no
78+
other `Selectable` is defined.
79+
80+
Other selectable instances can be defined in libraries. For instance,
81+
here is a simple class of records that support dynamic selection:
82+
83+
case class Record(elems: (String, Any)*) extends Selectable {
84+
def selectDynamic(name: String): Any = elems.find(_._1 == name).get._2
85+
}
86+
87+
`Record` consists of a list of pairs of element names and values. Its
88+
`selectDynamic` operation finds the pair with given name and returns
89+
its value.
90+
91+
For illustration, let's define a record value and cast it to a
92+
structural type `Person`:
93+
94+
type Person = Record { val name: String; val age: Int }
95+
val person = Record(("name" -> "Emma", "age" -> 42)).asInstanceOf[Person]
96+
97+
Then `person.name` will have static type `String`, and will produce `"Emma"` as result.
98+
99+
The safety of this scheme relies on the correctness of the cast. If
100+
the cast lies about the structure of the record, the corresponding
101+
`selectDynamic` operation would fail. In practice, the cast would
102+
likely be part if a database access layer which would ensure its
103+
correctness.
104+
105+
## Notes:
106+
107+
1. The scheme does not handle polymorphic methods in structural
108+
refinements. Such polymorphic methods are currently flagged as
109+
errors. It's not clear whether the use case is common enough to
110+
warrant the additional complexity of supporting it.
111+
112+
2. There are clearly some connections with `scala.Dynamic` here, since
113+
both select members programmatically. But there are also some
114+
differences.
115+
116+
- Fully dynamic selection is not typesafe, but structural selection
117+
is, as long as the correspondence of the structural type with the
118+
underlying value is as stated.
119+
120+
- `Dynamic` is just a marker trait, which gives more leeway where and
121+
how to define reflective access operations. By contrast
122+
`Selectable` is a trait which declares the access operations.
123+
124+
- One access operation, `selectDynamic` is shared between both
125+
approaches, but the other access operations are
126+
different. `Selectable` defines a `selectDynamicMethod`, which
127+
takes class tags indicating the method's formal parameter types as
128+
additional argument. `Dynamic` comes with `applyDynamic` and
129+
`updateDynamic` methods, which take actual argument values.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
layout: doc-page
3+
title: "Changes in Type Checking"
4+
---
5+
6+
[//] # todo: fill in
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
layout: doc-page
3+
title: "Changes in Type Inference"
4+
---
5+
6+
[//] # todo: fill in
7+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
layout: doc-page
3+
title: "Vararg Patterns"
4+
---
5+
6+
The syntax of vararg patterns has changed. In the new syntax one
7+
writes varargs in patterns exactly like one writes them in
8+
expressions, using a `: _*` type annotation:
9+
10+
xs match {
11+
case List(1, 2, xs: _*) => println(xs) // binds xs
12+
case List(1, _ : _*) => // wildcard pattern
13+
}
14+
15+
The old syntax, which is shorter but less regular, is no longer
16+
supported:
17+
18+
/*!*/ case List(1, 2, xs @ _*) // syntax error
19+
/*!*/ case List(1, 2, _*) => ... // syntax error
20+
21+

docs/sidebar.yml

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ sidebar:
55
subsection:
66
- title: New Types
77
subsection:
8-
- title: Implicit Function Types
9-
url: docs/reference/implicit-function-types.md
108
- title: Intersection types
119
url: docs/reference/intersection-types.html
1210
- title: Union types
1311
url: docs/reference/union-types.html
1412
- title: Type lambdas
1513
url: docs/reference/type-lambdas.html
14+
- title: Implicit Function Types
15+
url: docs/reference/implicit-function-types.md
1616
- title: Enums
1717
subsection:
1818
- title: Enumerations
@@ -21,20 +21,36 @@ sidebar:
2121
url: docs/reference/adts.html
2222
- title: Translation
2323
url: docs/reference/desugarEnums.html
24-
- title: Trait Parameters
25-
url: docs/reference/trait-parameters.html
26-
- title: Multiversal Equality
27-
url: docs/reference/multiversal-equality.html
28-
- title: Inline
29-
url: docs/reference/inline.html
30-
- title: Smaller Changes
24+
- title: Other New Features
3125
subsection:
26+
- title: Multiversal Equality
27+
url: docs/reference/multiversal-equality.html
28+
- title: Inline
29+
url: docs/reference/inline.html
30+
- title: Trait Parameters
31+
url: docs/reference/trait-parameters.html
3232
- title: By-Name Implicits
3333
url: docs/reference/implicit-by-name-parameters.html
3434
- title: Auto Parameter Tupling
3535
url: docs/reference/auto-parameter-tupling.html
3636
- title: Named Type Arguments
3737
url: docs/reference/named-typeargs.html
38+
- title: Changed Features
39+
subsection:
40+
- title: Volatile Lazy Vals
41+
url: docs/reference/changed/lazy-vals.md
42+
- title: Structural Types
43+
url: docs/reference/changed/structural-types.md
44+
- title: Type Checking
45+
url: docs/reference/changed/type-checking.md
46+
- title: Type Inference
47+
url: docs/reference/changed/type-inference.md
48+
- title: Implicit Resolution
49+
url: docs/reference/changed/implicit-resolution.md
50+
- title: Implicit Conversions
51+
url: docs/reference/changed/implicit-conversions.md
52+
- title: Vararg Patterns
53+
url: docs/reference/changed/vararg-patterns.md
3854
- title: Dropped Features
3955
subsection:
4056
- title: DelayedInit
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package varargPatterns
2+
object t1 extends App {
3+
val List(1, 2, xs : _*) = List(1, 2, 3)
4+
println(xs)
5+
val List(1, 2, _ : _*) = List(1, 2, 3)
6+
}

0 commit comments

Comments
 (0)