Skip to content

Add docs on changed features #2592

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/docs/reference/adts.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
48 changes: 48 additions & 0 deletions docs/docs/reference/changed/implicit-conversions.md
Original file line number Diff line number Diff line change
@@ -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
}




46 changes: 46 additions & 0 deletions docs/docs/reference/changed/implicit-resolution.md
Original file line number Diff line number Diff line change
@@ -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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is that by the way?


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


19 changes: 19 additions & 0 deletions docs/docs/reference/changed/lazy-vals.md
Original file line number Diff line number Diff line change
@@ -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 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

@volatile lazy val x = expr

it is guaranteed that readers of a lazy val will see the value of `x`
once it is assigned.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly is the difference in behavior between volatile and non-volatile lazy vals?


The [ScalaFix](https://scalacenter.github.io/scalafix/) rewrite tool
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.
129 changes: 129 additions & 0 deletions docs/docs/reference/changed/structural-types.md
Original file line number Diff line number Diff line change
@@ -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
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
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.
6 changes: 6 additions & 0 deletions docs/docs/reference/changed/type-checking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
layout: doc-page
title: "Changes in Type Checking"
---

[//] # todo: fill in
7 changes: 7 additions & 0 deletions docs/docs/reference/changed/type-inference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
layout: doc-page
title: "Changes in Type Inference"
---

[//] # todo: fill in

21 changes: 21 additions & 0 deletions docs/docs/reference/changed/vararg-patterns.md
Original file line number Diff line number Diff line change
@@ -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

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When developing Scalameta 2.x that's supposed to crosscompile against 2.x and 3.x, I found this to be an unfortunate problem. There's currently no way to write crosscompilable code that contains sequence wildcards. Can something be done with this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xeno-by AFAIK, we support both syntaxes under -language:Scala2
#1059

On 30 May 2017 01:14:25 Eugene Burmako [email protected] wrote:

xeno-by commented on this pull request.

+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

When developing Scalameta 2.x that's supposed to crosscompile against 2.x
and 3.x, I found this to be an unfortunate problem. There's currently no
way to write crosscompilable code that contains sequence wildcards. Can
something be done with this?

--
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
#2592 (review)


34 changes: 25 additions & 9 deletions docs/sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -21,20 +21,36 @@ 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 Changes
- 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
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: 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: Implicit Conversions
url: docs/reference/changed/implicit-conversions.md
- title: Vararg Patterns
url: docs/reference/changed/vararg-patterns.md
- title: Dropped Features
subsection:
- title: DelayedInit
Expand Down
6 changes: 6 additions & 0 deletions tests/pos/reference/vararg-patterns.scala
Original file line number Diff line number Diff line change
@@ -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)
}