# Extension Methods

Note The syntax described in this section is currently under revision. Here is the new version which will be implemented in Dotty 0.19.

Extension methods allow one to add methods to a type after the type is defined. Example:

``````case class Circle(x: Double, y: Double, radius: Double)

def (c: Circle) circumference: Double = c.radius * math.Pi * 2
``````

Like regular methods, extension methods can be invoked with infix `.`:

``````val circle = Circle(0, 0, 1)
circle.circumference
``````

### Translation of Extension Methods

Extension methods are methods that have a parameter clause in front of the defined identifier. They translate to methods where the leading parameter section is moved to after the defined identifier. So, the definition of `circumference` above translates to the plain method, and can also be invoked as such:

``````def circumference(c: Circle): Double = c.radius * math.Pi * 2

assert(circle.circumference == circumference(circle))
``````

### Translation of Calls to Extension Methods

When is an extension method applicable? There are two possibilities.

• An extension method is applicable if it is visible under a simple name, by being defined or inherited or imported in a scope enclosing the application.
• An extension method is applicable if it is a member of some given instance at the point of the application.

As an example, consider an extension method `longestStrings` on `Seq[String]` defined in a trait `StringSeqOps`.

``````trait StringSeqOps {
def (xs: Seq[String]) longestStrings = {
val maxLength = xs.map(_.length).max
xs.filter(_.length == maxLength)
}
}
``````

We can make the extension method available by defining a given `StringSeqOps` instance, like this:

``````given ops1 as StringSeqOps
``````

Then

``````List("here", "is", "a", "list").longestStrings
``````

is legal everywhere `ops1` is available. Alternatively, we can define `longestStrings` as a member of a normal object. But then the method has to be brought into scope to be usable as an extension method.

``````object ops2 extends StringSeqOps
import ops2.longestStrings
List("here", "is", "a", "list").longestStrings
``````

The precise rules for resolving a selection to an extension method are as follows.

Assume a selection `e.m[Ts]` where `m` is not a member of `e`, where the type arguments `[Ts]` are optional, and where `T` is the expected type. The following two rewritings are tried in order:

1. The selection is rewritten to `m[Ts](e)`.
2. If the first rewriting does not typecheck with expected type `T`, and there is a given instance `i` in either the current scope or in the implicit scope of `T`, and `i` defines an extension method named `m`, then selection is expanded to `i.m[Ts](e)`. This second rewriting is attempted at the time where the compiler also tries an implicit conversion from `T` to a type containing `m`. If there is more than one way of rewriting, an ambiguity error results.

So `circle.circumference` translates to `CircleOps.circumference(circle)`, provided `circle` has type `Circle` and `CircleOps` is given (i.e. it is visible at the point of call or it is defined in the companion object of `Circle`).

### Given Instances Defining Only Extension Methods

Given instances that define extension methods can also be defined without a parent clause. E.g.,

``````given stringOps: {
def (xs: Seq[String]) longestStrings: Seq[String] = {
val maxLength = xs.map(_.length).max
xs.filter(_.length == maxLength)
}
}

given {
def (xs: List[T]) second[T] = xs.tail.head
}
``````

If an extensions is anonymous (as in the second clause), its name is synthesized from the name of the first defined extension method.

### Given Extensions with Collective Parameters

If a given extension defines several extension methods one can pull out the left parameter section as well as any type parameters of these extension methods into the given instance itself. For instance, here is a given instance with two extension methods.

``````given listOps: {
def (xs: List[T]) second[T]: T = xs.tail.head
def (xs: List[T]) third[T]: T = xs.tail.tail.head
}
``````

The repetition in the parameters can be avoided by moving the parameters in front of the opening brace. The following version is a shorthand for the code above.

``````given listOps: [T](xs: List[T]) {
def second: T = xs.tail.head
def third: T = xs.tail.tail.head
}
``````

This syntax just adds convenience at the definition site. Applications of such extension methods are exactly the same as if their parameters were repeated in each extension method. Examples:

``````val xs = List(1, 2, 3)
xs.second[Int]
ListOps.third[T](xs)
``````

### Operators

The extension method syntax also applies to the definition of operators. In each case the definition syntax mirrors the way the operator is applied. Examples:

``````def (x: String) < (y: String) = ...
def (x: Elem) +: (xs: Seq[Elem]) = ...

"ab" + "c"
1 +: List(2, 3)
``````

The two definitions above translate to

``````def < (x: String)(y: String) = ...
def +: (xs: Seq[Elem])(x: Elem) = ...
``````

Note that swap of the two parameters `x` and `xs` when translating the right-binding operator `+:` to an extension method. This is analogous to the implementation of right binding operators as normal methods.

### Generic Extensions

The `StringSeqOps` examples extended a specific instance of a generic type. It is also possible to extend a generic type by adding type parameters to an extension method. Examples:

``````def (xs: List[T]) second [T] =

def (xs: List[List[T]]) flattened [T] =
xs.foldLeft[List[T]](Nil)(_ ++ _)

def (x: T) + [T : Numeric](y: T): T =
the[Numeric[T]].plus(x, y)
``````

As usual, type parameters of the extension method follow the defined method name. Nevertheless, such type parameters can already be used in the preceding parameter clause.

### Syntax

Here are the required syntax extensions compared to the current syntax.

``````DefSig            ::=  ...
|  ‘(’ DefParam ‘)’ [nl] id [DefTypeParamClause] DefParamClauses
GivenDef          ::=  ...
|  [id ‘:’] [ExtParamClause] TemplateBody
ExtParamClause    ::=  [DefTypeParamClause] ‘(’ DefParam ‘)’ {GivenParamClause}
``````