-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
100 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
docs/docs/reference/other-new-features/generalized-method-syntax.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
--- | ||
layout: doc-page | ||
title: "Generalized Method Syntax" | ||
movedTo: https://docs.scala-lang.org/scala3/reference/other-new-features/generalized-method-syntax.html | ||
--- | ||
|
||
The inclusion of using clauses is not the only way in which methods have been updated, type parameter clauses are now allowed in any number and at any position. | ||
|
||
## Syntax Changes | ||
|
||
### In Scala 2 | ||
|
||
The old syntax only allowed zero or one type parameter clause, followed by any number of term clauses, optionnally followed by an implicit clause: | ||
|
||
```scala | ||
def foo[T, U](x: T)(y: U)(z: Int, s: String)(a: Array[T])(implicit List[U]) | ||
``` | ||
|
||
### In Scala 3 | ||
|
||
The new syntax allows any number of type, term and using clause, in any order, optionnaly followed by an implicit clause: | ||
(do note however that [implicit clause are discouraged, in favor of using clauses](https://docs.scala-lang.org/scala3/reference/contextual/relationship-implicits.html)) | ||
|
||
```scala | ||
def foo[T, U](x: T)(y: U)[V](z: V, s: String)[A](a: Array[A])(implicit List[U]) | ||
``` | ||
|
||
### Unchanged | ||
|
||
Class definitions and type declarations are unaffected, there can only be up to one type clause, in leading posion. | ||
|
||
## Motivation | ||
|
||
The new syntax is a powerful but natural extension of the old one, it allows new design patterns while staying intuitive and legible. | ||
|
||
### Dependent Type Clauses | ||
|
||
As type clauses can come after term clauses, it is now possible to have type parameters depend on term parameters: | ||
|
||
```scala | ||
trait Key { type Value } | ||
trait DB { | ||
def get(k: Key): Option[k.Value] // dependent return type | ||
def getOrElse(k: Key)[V >: k.Value](default: V): V // dependent type parameter | ||
} | ||
``` | ||
|
||
Note that simply replacing `V` by `k.Value` would not be equivalent. For example, if `k.Value` is `Int`, the above allows: | ||
`getOrElse(k)[Number](0.1)`, which returns a `Number`. | ||
|
||
### Partial Inference | ||
|
||
It is now possible to only infer some of the type parameters, this reduces boilerplate at the use site: | ||
```scala | ||
trait StaticSizeList[S <: Int & Singleton, T] | ||
def filled[S <: Int & Singleton][T](x: T): StaticSizeList[S,T] = ??? | ||
val helloes = filled[4]("Hello!") // S=4, and T is inferred | ||
``` | ||
|
||
## Details | ||
|
||
### Application | ||
|
||
Method application is unchanged, in cases where multiple type clauses are expected but not all are passed, the leftmost ones are inferred. | ||
|
||
In particular, the following does not type check, even though the argument `Char` is only valid for `C`: | ||
```scala | ||
def triple[A <: Int][B <: String][C <: Char](a: A, b: B, c: C) = ??? | ||
triple[Int][Char](0,"",'c') // error: Char does not conform to upperbound String | ||
``` | ||
|
||
### Extension Methods | ||
|
||
Naturally extension methods follow the same syntax, so the following is valid: | ||
```scala | ||
extension [T](l1: List[T]) | ||
def zipWith[U](l2: List[U])[V](l3: List[V]): List[(T,U,V)] | ||
``` | ||
|
||
### Formal syntax | ||
|
||
``` | ||
DefDcl ::= DefSig ‘:’ Type | ||
DefDef ::= DefSig [‘:’ Type] ‘=’ Expr | ||
DefSig ::= id [DefParamClauses] [DefImplicitClause] | ||
DefParamClauses ::= DefParamClause { DefParamClause } | ||
DefParamClause ::= DefTypeParamClause | ||
| DefTermParamClause | ||
| UsingParamClause | ||
DefTypeParamClause::= [nl] ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’ | ||
DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeParamBounds | ||
DefTermParamClause::= [nl] ‘(’ [DefTermParams] ‘)’ | ||
UsingParamClause ::= [nl] ‘(’ ‘using’ (DefTermParams | FunArgTypes) ‘)’ | ||
DefImplicitClause ::= [nl] ‘(’ ‘implicit’ DefTermParams ‘)’ | ||
DefTermParams ::= DefTermParam {‘,’ DefTermParam} | ||
DefTermParam ::= {Annotation} [‘inline’] Param | ||
Param ::= id ‘:’ ParamType [‘=’ Expr] | ||
``` |