From d1c98fd1ed14319bfb9c0f9b488b47e2715c9a23 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 29 May 2017 21:56:13 +0200 Subject: [PATCH 1/7] Add changes section --- docs/docs/reference/adts.md | 2 +- docs/docs/reference/changed/lazy-vals.md | 19 +++++++++++++++++++ docs/sidebar.yml | 6 ++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 docs/docs/reference/changed/lazy-vals.md diff --git a/docs/docs/reference/adts.md b/docs/docs/reference/adts.md index 9c4f83a6db93..486774e9997a 100644 --- a/docs/docs/reference/adts.md +++ b/docs/docs/reference/adts.md @@ -108,7 +108,7 @@ The changes are specified below as deltas with respect to the Scala syntax given EnumDef ::= id ClassConstr [`extends' [ConstrApps]] [nl] `{’ EnumCaseStat {semi EnumCaseStat} `}’ -2. Cases of enums are defined as follows: + 2. Cases of enums are defined as follows: EnumCaseStat ::= {Annotation [nl]} {Modifier} EnumCase EnumCase ::= `case' (EnumClassDef | ObjectDef | ids) diff --git a/docs/docs/reference/changed/lazy-vals.md b/docs/docs/reference/changed/lazy-vals.md new file mode 100644 index 000000000000..699dfff5cd0c --- /dev/null +++ b/docs/docs/reference/changed/lazy-vals.md @@ -0,0 +1,19 @@ +--- +layout: doc-page +title: Changed: Lazy Vals and @volatile +--- + +Lazy val initialization no longer guarantees safe publishing. This change was done +to avid the performance overhead of thread synchonization because many lazy vals are only used in a single-threaded context. + +To get back safe publishing you need to annotate a lazy val with `@volatile`. In + + @volatile lazy val x = expr + +it is guaranteed that readers of a lazy val will see the value of `x` +once it is assigned. + +The [ScalaFix](https://scalacenter.github.io/scalafix/) rewrite tool +as well as Dotty's own `-migration` option will rewrite all normal +lazy vals to volatile ones in order to keep their semantics compatible +with current Scala's. diff --git a/docs/sidebar.yml b/docs/sidebar.yml index bec8c2b95ee7..eb9986b8119a 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -35,6 +35,12 @@ sidebar: url: docs/reference/auto-parameter-tupling.html - title: Named Type Arguments url: docs/reference/named-typeargs.html + - title: Changed Features + subsection: + - title: Volatile Lazy Vals + url: docs/reference/changed/lazy-vals.md + - title: Structural Types + url: docs/reference/changed/structural-types.md - title: Dropped Features subsection: - title: DelayedInit From aa4217f6e04b45d8eb73be258822c6e71ebff9f8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 29 May 2017 22:05:32 +0200 Subject: [PATCH 2/7] Add section on programmatic structural types --- .../reference/changed/structural-types.md | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 docs/docs/reference/changed/structural-types.md diff --git a/docs/docs/reference/changed/structural-types.md b/docs/docs/reference/changed/structural-types.md new file mode 100644 index 000000000000..f69c37c29392 --- /dev/null +++ b/docs/docs/reference/changed/structural-types.md @@ -0,0 +1,129 @@ +--- +layout: doc-page +title: "Programmatic Structural Types" +--- + +Previously, Scala supported structural types by means of +reflection. This is problematic on other platforms, because Scala's +reflection is JVM-based. Consequently, Scala.js and Scala.native don't +dupport structural types fully. The reflction based implementation is +also needlessly restrictive, since it rules out other implementation +schemes. This makes structural types unsuitable for e.g. modelling +rows in a database, for which they would otherwise seem to be an ideal +match. + +Dotty allows to implement structural types programmatically, using +"Selectables". `Selectable` is a trait defined as follows: + + trait Selectable extends Any { + def selectDynamic(name: String): Any + def selectDynamicMethod(name: String, paramClasses: ClassTag[_]*): Any = + new UnsupportedOperationException("selectDynamicMethod") + } + +The most important method of a `Selectable` is `selectDynamic`: It +takes a field name and returns the value associated with that name in +the selectable. + +Assume now `r` is a value with structural type `S`.` In general `S` is +of the form `C { Rs }`, i.e. it consists of a class reference `C` and +refinement declarations `Rs`. We call a field selection `r.f` +_structural_ if `f` is a name defined by a declaration in `Rs` whereas +`C` defines no member of name `f`. Assuming the selection has type +`T`, it is mapped to something equivalent to the following code: + + (r: Selectable).selectDynamic("f").asInstanceOf[T] + +That is, we make sure `r` conforms to type `Selectable`, potentially +by adding an implicit conversion. We then invoke the `get` operation +of that instance, passing the the name `"f"` as a parameter. We +finally cast the resulting value back to the statically known type +`T`. + +`Selectable` also defines another access method called +`selectDynamicMethod`. This operation is used to select methods +instead of fields. It gets passed the class tags of the selected +method's formal parameter types as additional arguments. These can +then be used to disambiguate one of several overloaded variants. + +Package `scala.reflect` contains an implicit conversion which can map +any value to a selectable that emulates reflection-based selection, in +a way similar to what was done until now: + + package scala.reflect + + object Selectable { + implicit def reflectiveSelectable(receiver: Any): scala.Selectable = + receiver match { + case receiver: scala.Selectable => receiver + case _ => new scala.reflect.Selectable(receiver) + } + } + +When imported, `reflectiveSelectable` provides a way to access fields +of any structural type using Java reflection. This is similar to the +current implementation of structural types. The main difference is +that to get reflection-based structural access one now has to add an +import: + + import scala.relect.Selectable.reflectiveSelectable + +On the other hand, the previously required language feature import of +`reflectiveCalls` is now redundant and is therefore dropped. + +As you can see from its implementation above, `reflectSelectable` +checks first whether its argument is already a run-time instance of +`Selectable`, in which case it is returned directly. This means that +reflection-based accesses only take place as a last resort, if no +other `Selectable` is defined. + +Other selectable instances can be defined in libraries. For instance, +here is a simple class of records that support dynamic selection: + + case class Record(elems: (String, Any)*) extends Selectable { + def selectDynamic(name: String): Any = elems.find(_._1 == name).get._2 + } + +`Record` consists of a list of pairs of element names and values. Its +`selectDynamic` operation finds the pair with given name and returns +its value. + +For illustration, let's define a record value and cast it to a +structural type `Person`: + + type Person = Record { val name: String; val age: Int } + val person = Record(("name" -> "Emma", "age" -> 42)).asInstanceOf[Person] + +Then `person.name` will have static type `String`, and will produce `"Emma"` as result. + +The safety of this scheme relies on the correctness of the cast. If +the cast lies about the structure of the record, the corresponding +`selectDynamic` operation would fail. In practice, the cast would +likely be part if a database access layer which would ensure its +correctness. + +## Notes: + +1. The scheme does not handle polymorphic methods in structural +refinements. Such polymorphic methods are currently flagged as +errors. It's not clear whether the use case is common enough to +warrant the additional complexity of supporting it. + +2. There are clearly some connections with `scala.Dynamic` here, since +both select members programmatically. But there are also some +differences. + + - Fully dynamic selection is not typesafe, but structural selection + is, as long as the correspondence of the structural type with the + underlying value is as stated. + + - `Dynamic` is just a marker trait, which gives more leeway where and + how to define reflective access operations. By contrast + `Selectable` is a trait which declares the access operations. + + - One access operation, `selectDynamic` is shared between both + approaches, but the other access operations are + different. `Selectable` defines a `selectDynamicMethod`, which + takes class tags indicating the method's formal parameter types as + additional argument. `Dynamic` comes with `applyDynamic` and + `updateDynamic` methods, which take actual argument values. From 717b61cd4c87d9c03b2f40cbc4aa18413b634566 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 29 May 2017 22:28:19 +0200 Subject: [PATCH 3/7] More section on changes --- .../reference/changed/implicit-resolution.md | 46 +++++++++++++++++++ docs/docs/reference/changed/type-checking.md | 6 +++ docs/docs/reference/changed/type-inference.md | 7 +++ docs/sidebar.yml | 8 +++- 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 docs/docs/reference/changed/implicit-resolution.md create mode 100644 docs/docs/reference/changed/type-checking.md create mode 100644 docs/docs/reference/changed/type-inference.md diff --git a/docs/docs/reference/changed/implicit-resolution.md b/docs/docs/reference/changed/implicit-resolution.md new file mode 100644 index 000000000000..d0728043c251 --- /dev/null +++ b/docs/docs/reference/changed/implicit-resolution.md @@ -0,0 +1,46 @@ +--- +layout: doc-page +title: "Changes in Implicit Resolution" +--- + +Implicit resolution uses a new algorithm which caches implicit results +more aggressively for perforance. There are also some changes that +affect implicits on the language level. + + 1. Types of implicit values and result types of implicit methods + must be explicitly declared. Excepted are only values in local blocks + where the type may still be inferred: + + class C { + + val ctx: Context = ... // ok + + /*!*/ implicit val x = ... // error: type must be given explicitly + + /*!*/ next(): Context = ... // error: type must be given explicitly + + val y = { + implicit val ctx = this.ctx // ok + ... + } + + 2. Implicit parameters may not have singleton types. + + /*!*/ def f(implicit x: y.type) // error `y.type` not allowed as type of implicit + + 3. Nesting is now taken into account for selecting an implicit. + Consider for instance the following scenario + + def f(implicit i: C) = { + def g(implicit j: C) = { + implicitly[C] + } + } + + This will now resolve the `implicitly` call to `j`, because `j` is nested + more deeply than `i`. Previously, this would have resulted in an + ambiguity error. + +[//] # todo: expand with precise rules + + diff --git a/docs/docs/reference/changed/type-checking.md b/docs/docs/reference/changed/type-checking.md new file mode 100644 index 000000000000..607f5ae8220c --- /dev/null +++ b/docs/docs/reference/changed/type-checking.md @@ -0,0 +1,6 @@ +--- +layout: doc-page +title: "Changes in Type Checking" +--- + +[//] # todo: fill in diff --git a/docs/docs/reference/changed/type-inference.md b/docs/docs/reference/changed/type-inference.md new file mode 100644 index 000000000000..276a5100dc19 --- /dev/null +++ b/docs/docs/reference/changed/type-inference.md @@ -0,0 +1,7 @@ +--- +layout: doc-page +title: "Changes in Type Inference" +--- + +[//] # todo: fill in + diff --git a/docs/sidebar.yml b/docs/sidebar.yml index eb9986b8119a..c07858506d38 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -27,7 +27,7 @@ sidebar: url: docs/reference/multiversal-equality.html - title: Inline url: docs/reference/inline.html - - title: Smaller Changes + - title: Smaller Additions subsection: - title: By-Name Implicits url: docs/reference/implicit-by-name-parameters.html @@ -41,6 +41,12 @@ sidebar: url: docs/reference/changed/lazy-vals.md - title: Structural Types url: docs/reference/changed/structural-types.md + - title: Type Checking + url: docs/reference/changed/type-checking.md + - title: Type Inference + url: docs/reference/changed/type-inference.md + - title: Implicit Resolution + url: docs/reference/changed/implicit-resolution.md - title: Dropped Features subsection: - title: DelayedInit From 9bb87f06957015832345302328d4464a3b3b8359 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 29 May 2017 22:58:19 +0200 Subject: [PATCH 4/7] Add section on vararg patterns --- docs/docs/reference/changed/lazy-vals.md | 4 ++-- .../docs/reference/changed/vararg-patterns.md | 21 +++++++++++++++++++ docs/sidebar.yml | 2 ++ tests/pos/reference/vararg-patterns.scala | 6 ++++++ 4 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 docs/docs/reference/changed/vararg-patterns.md create mode 100644 tests/pos/reference/vararg-patterns.scala diff --git a/docs/docs/reference/changed/lazy-vals.md b/docs/docs/reference/changed/lazy-vals.md index 699dfff5cd0c..49228d97c429 100644 --- a/docs/docs/reference/changed/lazy-vals.md +++ b/docs/docs/reference/changed/lazy-vals.md @@ -4,7 +4,7 @@ title: Changed: Lazy Vals and @volatile --- Lazy val initialization no longer guarantees safe publishing. This change was done -to avid the performance overhead of thread synchonization because many lazy vals are only used in a single-threaded context. +to avoid the performance overhead of thread synchonization because many lazy vals are only used in a single-threaded context. To get back safe publishing you need to annotate a lazy val with `@volatile`. In @@ -14,6 +14,6 @@ it is guaranteed that readers of a lazy val will see the value of `x` once it is assigned. The [ScalaFix](https://scalacenter.github.io/scalafix/) rewrite tool -as well as Dotty's own `-migration` option will rewrite all normal +as well as Dotty's own `-language:Scala2 -rewrite` option will rewrite all normal lazy vals to volatile ones in order to keep their semantics compatible with current Scala's. diff --git a/docs/docs/reference/changed/vararg-patterns.md b/docs/docs/reference/changed/vararg-patterns.md new file mode 100644 index 000000000000..68e8d67d3964 --- /dev/null +++ b/docs/docs/reference/changed/vararg-patterns.md @@ -0,0 +1,21 @@ +--- +layout: doc-page +title: "Vararg Patterns" +--- + +The syntax of vararg patterns has changed. In the new syntax one +writes varargs in patterns exactly like one writes them in +expressions, using a `: _*` type annotation: + + xs match { + case List(1, 2, xs: _*) => println(xs) // binds xs + case List(1, _ : _*) => // wildcard pattern + } + +The old syntax, which is shorter but less regular, is no longer +supported: + + /*!*/ case List(1, 2, xs @ _*) // syntax error + /*!*/ case List(1, 2, _*) => ... // syntax error + + diff --git a/docs/sidebar.yml b/docs/sidebar.yml index c07858506d38..87a5c68c1f8d 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -47,6 +47,8 @@ sidebar: url: docs/reference/changed/type-inference.md - title: Implicit Resolution url: docs/reference/changed/implicit-resolution.md + - title: Vararg Patterns + url: docs/reference/changed/vararg-patterns.md - title: Dropped Features subsection: - title: DelayedInit diff --git a/tests/pos/reference/vararg-patterns.scala b/tests/pos/reference/vararg-patterns.scala new file mode 100644 index 000000000000..3a2cf96a7175 --- /dev/null +++ b/tests/pos/reference/vararg-patterns.scala @@ -0,0 +1,6 @@ +package varargPatterns +object t1 extends App { + val List(1, 2, xs : _*) = List(1, 2, 3) + println(xs) + val List(1, 2, _ : _*) = List(1, 2, 3) +} From c3ea17d33599b8ffde40b658b9d0fb06a5a31984 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 29 May 2017 23:21:48 +0200 Subject: [PATCH 5/7] Add section on implicit conversions --- .../reference/changed/implicit-conversions.md | 48 +++++++++++++++++++ docs/sidebar.yml | 2 + 2 files changed, 50 insertions(+) create mode 100644 docs/docs/reference/changed/implicit-conversions.md diff --git a/docs/docs/reference/changed/implicit-conversions.md b/docs/docs/reference/changed/implicit-conversions.md new file mode 100644 index 000000000000..72a386eba468 --- /dev/null +++ b/docs/docs/reference/changed/implicit-conversions.md @@ -0,0 +1,48 @@ +--- +layout: doc-page +title: "Restrictions to Implicit Conversions" +--- + +Previously, an implicit value of type `Function1`, or any of its subtypes +could be used as an implicit conversion. That is, the following code would compile +even though it probably masks a type error: + + implicit val m: Map[String, Int] = Map(1 -> "abc") + + val x: String = 1 // scalac: assigns "abc" to x + // Dotty: type error + +By contrast, Dotty only considers _methods_ as implicit conversions, so the +`Map` value `m` above would not qualify as a conversion from `String` to `Int`. + +To be able to express implicit conversions passed as parameters, `Dotty` +introduces a new type + + abstract class ImplicitConverter[-T, +U] extends Function1[T, U] + +Implicit values of type `ImplicitConverter[A, B]` do qualify as implicit +conversions. It is as if there was a global implicit conversion method + + def convert[A, B](x: A)(implicit converter: ImplicitConverter[A, B]): B = + converter(x) + +(In reality the Dotty compiler simulates the behavior of this method directly in +its type checking because this turns out to be more efficient). + +In summary, previous code using implicit conversion parameters such as + + def useConversion(implicit f: A => B) { + val y: A = ... + val x: B = a // error under Dotty + } + +is no longer legal and has to be rwritten to + + def useConversion(implicit f: ImplicitConverter[A, B]) { + val y: A = ... + val x: B = a // OK + } + + + + diff --git a/docs/sidebar.yml b/docs/sidebar.yml index 87a5c68c1f8d..b48f2b44c844 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -47,6 +47,8 @@ sidebar: url: docs/reference/changed/type-inference.md - title: Implicit Resolution url: docs/reference/changed/implicit-resolution.md + - title: Implicit Conversions + url: docs/reference/changed/implicit-conversions.md - title: Vararg Patterns url: docs/reference/changed/vararg-patterns.md - title: Dropped Features From 331eb09418754d1dac70024d424059e221bfe257 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 29 May 2017 23:32:41 +0200 Subject: [PATCH 6/7] Sidebar re-org --- docs/sidebar.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/sidebar.yml b/docs/sidebar.yml index b48f2b44c844..a75fd36d5eca 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -5,14 +5,14 @@ sidebar: subsection: - title: New Types subsection: - - title: Implicit Function Types - url: docs/reference/implicit-function-types.md - title: Intersection types url: docs/reference/intersection-types.html - title: Union types url: docs/reference/union-types.html - title: Type lambdas url: docs/reference/type-lambdas.html + - title: Implicit Function Types + url: docs/reference/implicit-function-types.md - title: Enums subsection: - title: Enumerations @@ -21,14 +21,14 @@ sidebar: url: docs/reference/adts.html - title: Translation url: docs/reference/desugarEnums.html - - title: Trait Parameters - url: docs/reference/trait-parameters.html - - title: Multiversal Equality - url: docs/reference/multiversal-equality.html - - title: Inline - url: docs/reference/inline.html - - title: Smaller Additions + - title: Other New Features subsection: + - title: Multiversal Equality + url: docs/reference/multiversal-equality.html + - title: Inline + url: docs/reference/inline.html + - title: Trait Parameters + url: docs/reference/trait-parameters.html - title: By-Name Implicits url: docs/reference/implicit-by-name-parameters.html - title: Auto Parameter Tupling From f14335b05964b272ee543404024044c3ea348406 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 29 May 2017 23:34:35 +0200 Subject: [PATCH 7/7] Fix typo --- docs/docs/reference/changed/structural-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/reference/changed/structural-types.md b/docs/docs/reference/changed/structural-types.md index f69c37c29392..95124d030743 100644 --- a/docs/docs/reference/changed/structural-types.md +++ b/docs/docs/reference/changed/structural-types.md @@ -6,7 +6,7 @@ title: "Programmatic Structural Types" Previously, Scala supported structural types by means of reflection. This is problematic on other platforms, because Scala's reflection is JVM-based. Consequently, Scala.js and Scala.native don't -dupport structural types fully. The reflction based implementation is +support structural types fully. The reflction based implementation is also needlessly restrictive, since it rules out other implementation schemes. This makes structural types unsuitable for e.g. modelling rows in a database, for which they would otherwise seem to be an ideal