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 3 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
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 avid the performance overhead of thread synchonization because many lazy vals are only used in a single-threaded context.
Copy link
Member

Choose a reason for hiding this comment

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

typo: avid -> avoid


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 `-migration` option will rewrite all normal
Copy link
Member

Choose a reason for hiding this comment

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

-migration is only for migration warnings, to get dotty to rewrite stuff you need -language:Scala2 -rewrite.

Copy link
Member

Choose a reason for hiding this comment

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

It might be best to not mention the dotty internal rewrite mechanism until we know what we want to do with it.

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
dupport structural types fully. The reflction based implementation is
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: dupport -> support

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed, thanks!

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

14 changes: 13 additions & 1 deletion docs/sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,26 @@ 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
- 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: Dropped Features
subsection:
- title: DelayedInit
Expand Down