Skip to content

Trial: Replace implied by implicit #6372

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 1 commit into from
Apr 25, 2019
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
30 changes: 30 additions & 0 deletions docs/docs/reference/contextual-implicit/context-bounds.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
layout: doc-page
title: "Context Bounds"
---

## Context Bounds

A context bound is a shorthand for expressing a common pattern of an inferable parameter that depends on a type parameter. Using a context bound, the `maximum` function of the last section can be written like this:
```scala
def maximum[T: Ord](xs: List[T]): T = xs.reduceLeft(max)
```
A bound like `: Ord` on a type parameter `T` of a method or class indicates an inferable parameter `given Ord[T]`. The inferable parameter(s) generated from context bounds come last in the definition of the containing method or class. E.g.,
```scala
def f[T: C1 : C2, U: C3](x: T) given (y: U, z: V): R
```
would expand to
```scala
def f[T, U](x: T) given (y: U, z: V) given C1[T], C2[T], C3[U]: R
```
Context bounds can be combined with subtype bounds. If both are present, subtype bounds come first, e.g.
```scala
def g[T <: B : C](x: T): R = ...
```

## Syntax

```
TypeParamBounds ::= [SubtypeBounds] {ContextBound}
ContextBound ::= ‘:’ Type
```
75 changes: 75 additions & 0 deletions docs/docs/reference/contextual-implicit/conversions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
layout: doc-page
title: "Implicit Conversions"
---

Implicit conversions are defined by implicits for the `scala.Conversion` class.
This class is defined in package `scala` as follows:
```scala
abstract class Conversion[-T, +U] extends (T => U)
```
For example, here is an implicit conversion from `String` to `Token`:
```scala
implicit for Conversion[String, Token] {
def apply(str: String): Token = new KeyWord(str)
}
```
Using an implicit alias this can be expressed more concisely as:
```scala
implicit for Conversion[String, Token] = new KeyWord(_)
```
An implicit conversion is applied automatically by the compiler in three situations:

1. If an expression `e` has type `T`, and `T` does not conform to the expression's expected type `S`.
2. In a selection `e.m` with `e` of type `T`, but `T` defines no member `m`.
3. In an application `e.m(args)` with `e` of type `T`, if `T` does define
some member(s) named `m`, but none of these members can be applied to the arguments `args`.

In the first case, the compiler looks for an implicit value of class
`scala.Conversion` that maps an argument of type `T` to type `S`. In the second and third
case, it looks for an evidance value of class `scala.Conversion` that maps an argument of type `T`
to a type that defines a member `m` which can be applied to `args` if present.
If such an instance `C` is found, the expression `e` is replaced by `C.apply(e)`.

## Examples

1. The `Predef` package contains "auto-boxing" conversions that map
primitive number types to subclasses of `java.lang.Number`. For instance, the
conversion from `Int` to `java.lang.Integer` can be defined as follows:
```scala
implicit int2Integer for Conversion[Int, java.lang.Integer] =
java.lang.Integer.valueOf(_)
```

2. The "magnet" pattern is sometimes used to express many variants of a method. Instead of defining overloaded versions of the method, one can also let the method take one or more arguments of specially defined "magnet" types, into which various argument types can be converted. E.g.
```scala
object Completions {

// The argument "magnet" type
enum CompletionArg {
case Error(s: String)
case Response(f: Future[HttpResponse])
case Status(code: Future[StatusCode])
}
object CompletionArg {

// conversions defining the possible arguments to pass to `complete`
// these always come with CompletionArg
// They can be invoked explicitly, e.g.
//
// CompletionArg.fromStatusCode(statusCode)

implicit fromString for Conversion[String, CompletionArg] = Error(_)
implicit fromFuture for Conversion[Future[HttpResponse], CompletionArg] = Response(_)
implicit fromStatusCode for Conversion[Future[StatusCode], CompletionArg] = Status(_)
}
import CompletionArg._

def complete[T](arg: CompletionArg) = arg match {
case Error(s) => ...
case Response(f) => ...
case Status(code) => ...
}
}
```
This setup is more complicated than simple overloading of `complete`, but it can still be useful if normal overloading is not available (as in the case above, since we cannot have two overloaded methods that take `Future[...]` arguments), or if normal overloading would lead to a combinatorial explosion of variants.
Loading