Skip to content

Commit 87bce7b

Browse files
committed
Update reference pages
1 parent b7b1e1b commit 87bce7b

File tree

6 files changed

+117
-52
lines changed

6 files changed

+117
-52
lines changed

docs/docs/reference/changed-features/operators.md

Lines changed: 19 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,17 @@ layout: doc-page
33
title: Rules for Operators
44
---
55

6-
The rules for infix operators have changed. There are two annotations that regulate operators: `infix` and `alpha`.
7-
Furthermore, a syntax change allows infix operators to be written on the left in a multi-line expression.
6+
The rules for infix operators have changed in some parts:
87

9-
## The @alpha Annotation
10-
11-
An `@alpha` annotation on a method definition defines an alternate name for the implementation of that method: Example:
12-
```scala
13-
import scala.annotation.alpha
14-
15-
object VecOps {
16-
@alpha("append") def (xs: Vec[T]) ++= [T] (ys: Vec[T]): Vec[T] = ...
17-
}
18-
```
19-
Here, the `++=` operation is implemented (in Byte code or native code) under the name `append`. The implementation name affects the code that is generated, and is the name under which code from other languages can call the method. For instance, `++=` could be invoked from Java like this:
20-
```
21-
VecOps.append(vec1, vec2)
22-
```
23-
The `@alpha` annotation has no bearing on Scala usages. Any application of that method in Scala has to use `++=`, not `append`.
24-
25-
### Motivation
26-
27-
The `@alpha` annotation serves a dual purpose:
28-
29-
- It helps interoperability between Scala and other languages.
30-
- It serves as a documentation tool by providing an alternative regular name
31-
as an alias of a symbolic operator.
32-
33-
### Details
34-
35-
1. `@alpha` is defined in package `scala.annotation`. It takes a single argument
36-
of type `String`. That string is called the _external name_ of the definition
37-
that's annotated.
38-
39-
2. An `@alpha` annotation can be given for all kinds of definitions.
40-
41-
3. The name given in an `@alpha` annotation must be a legal name
42-
for the defined entities on the host platform.
43-
44-
4. Definitions with symbolic names should have an `@alpha` annotation. Lack of such
45-
an annotation will raise a deprecation warning.
46-
47-
5. Definitions with names in backticks that are not legal host platform names
48-
should have an `@alpha` annotation. Lack of such an annotation will raise a deprecation warning.
49-
50-
6. `@alpha` annotations must agree: If two definitions are members of an object or class with the same name and matching types, then either none of them has an `@alpha` annotation, or both have `@alpha` annotations with the same name.
51-
52-
7. There must be a one-to-one relationship between external and internal names:
53-
If two definitions are members of an object or class with matching types and both have `@alpha` annotations with the same external name, then their internal method names must also be the same.
8+
First, an alphanumeric method can be used as an infix operator only if its definition carries an `@infix` annotation. Second, it is recommended (but not enforced) to
9+
augment definitions of symbolic operators with `@targetName` annotations. Finally,
10+
a syntax change allows infix operators to be written on the left in a multi-line expression.
5411

5512
## The @infix Annotation
5613

5714
An `@infix` annotation on a method definition allows using the method as an infix operation. Example:
5815
```scala
59-
import scala.annotation.alpha
16+
import scala.annotation.{infix, targetName}
6017

6118
trait MultiSet[T] {
6219

@@ -65,7 +22,7 @@ trait MultiSet[T] {
6522

6623
def difference(other: MultiSet[T]): MultiSet[T]
6724

68-
@alpha("intersection")
25+
@targetName("intersection")
6926
def *(other: MultiSet[T]): MultiSet[T]
7027
}
7128

@@ -133,6 +90,19 @@ The purpose of the `@infix` annotation is to achieve consistency across a code b
13390
5. To smooth migration to Scala 3.0, alphanumeric operators will only be deprecated from Scala 3.1 onwards,
13491
or if the `-source 3.1` option is given in Dotty/Scala 3.
13592

93+
## The @targetName Annotation
94+
95+
It is recommended that definitions of symbolic operators carry a [@targetName annotation](../other-new-features/targetName.html) that provides an encoding of the operator with an alphanumeric name. This has several benefits:
96+
97+
- It helps interoperability between Scala and other languages. One can call
98+
a Scala-defined symbolic operator from another language using its target name,
99+
which avoids having to remember the low-level encoding of the symbolic name.
100+
- It helps legibility of stacktraces and other runtime diagnostics, where the
101+
user-defined alphanumeric name will be shown instead of the low-level encoding.
102+
- It serves as a documentation tool by providing an alternative regular name
103+
as an alias of a symbolic operator. This makes the definition also easier
104+
to find in a search.
105+
136106
## Syntax Change
137107

138108
Infix operators can now appear at the start of lines in a multi-line expression. Examples:
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
---
2+
layout: doc-page
3+
title: The @targetName annotation
4+
---
5+
6+
A `@targetName` annotation on a definition defines an alternate name for the implementation of that definition: Example:
7+
```scala
8+
import scala.annotation.targetName
9+
10+
object VecOps {
11+
@targetName("append") def (xs: Vec[T]) ++= [T] (ys: Vec[T]): Vec[T] = ...
12+
}
13+
```
14+
Here, the `++=` operation is implemented (in Byte code or native code) under the name `append`. The implementation name affects the code that is generated, and is the name under which code from other languages can call the method. For instance, `++=` could be invoked from Java like this:
15+
```
16+
VecOps.append(vec1, vec2)
17+
```
18+
The `@targetName` annotation has no bearing on Scala usages. Any application of that method in Scala has to use `++=`, not `append`.
19+
20+
### Details
21+
22+
1. `@targetName` is defined in package `scala.annotation`. It takes a single argument
23+
of type `String`. That string is called the _external name_ of the definition
24+
that's annotated.
25+
26+
2. A `@targetName` annotation can be given for all kinds of definitions.
27+
28+
3. The name given in a `@targetName` annotation must be a legal name
29+
for the defined entities on the host platform.
30+
31+
4. It is recommended that definitions with symbolic names have a `@targetName` annotation. This will establish an alternate name that is easier to search for and
32+
will avoid cryptic encodings in runtime diagnostics.
33+
34+
5. Definitions with names in backticks that are not legal host platform names
35+
should also have a `@targetName` annotation.
36+
37+
### Relationship with Overriding
38+
39+
`@targetName` annotations are significant for matching two method definitions to decide whether they conflict or override each other. Two method definitions match if they have the same name, signature, and erased name. Here,
40+
41+
- The _signature_ of a definition consists of the names of the erased types of all (value-) parameters and the method's result type.
42+
- The _erased name_ of a method definition is its target name if a `@targetName`
43+
annotation is given and its defined name otherwise.
44+
45+
This means that `@targetName` annotations can be used to disambiguate two method definitions that would otherwise clash. For instance.
46+
```scala
47+
def f(x: => String): Int = x.length
48+
def f(x: => Int): Int = x + 1 // error: double definition
49+
```
50+
The two definitions above clash since their erased parameter types are both `Function0`, which is the type of the translation of a by-name-parameter. Hence
51+
they have the same names and signatures. But we can avoid the clash by adding a `@targetName` annotation to either method or to both of them. E.g.
52+
```scala
53+
@targetName("f_string")
54+
def f(x: => String): Int = x.length
55+
def f(x: => Int): Int = x + 1 // OK
56+
```
57+
This will produce methods `f_string` and `f` in the generated code.
58+
59+
As usual, any overriding relationship in the generated code must also
60+
be present in the original code. So the following example would be in error:
61+
```scala
62+
import annotation.targetName
63+
class A:
64+
def f(): Int = 1
65+
class B extends A:
66+
targetName("f") def g(): Int = 2
67+
```
68+
Here, the original methods `g` and `f` do not override each other since they have
69+
different names. But once we switch to target names, there is a clash that is reported by the compiler:
70+
```
71+
-- [E120] Naming Error: test.scala:4:6 -----------------------------------------
72+
4 |class B extends A:
73+
| ^
74+
| Name clash between defined and inherited member:
75+
| def f(): Int in class A at line 3 and
76+
| def g(): Int in class B at line 5
77+
| have the same name and type after erasure.
78+
1 error found
79+
```

docs/docs/reference/overview.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ These constructs are restricted to make the language safer.
5858
- [Given Imports](contextual/given-imports.md): implicits now require a special form of import, to make the import clearly visible.
5959
- [Type Projection](dropped-features/type-projection.md): only classes can be used as prefix `C` of a type projection `C#A`. Type projection on abstract types is no longer supported since it is unsound.
6060
- [Multiversal Equality](contextual/multiversal-equality.md) implements an "opt-in" scheme to rule out nonsensical comparisons with `==` and `!=`.
61-
- [@infix and @alpha](changed-features/operators.md)
62-
make method application syntax uniform across code bases and require alphanumeric aliases for all symbolic names (proposed, not implemented).
61+
- [@infix annotations](changed-features/operators.md)
62+
make method application syntax uniform across code bases.
6363

6464
Unrestricted implicit conversions continue to be available in Scala 3.0, but will be deprecated and removed later. Unrestricted versions of the other constructs in the list above are available only under `-source 3.0-migration`.
6565

@@ -109,6 +109,7 @@ These are additions to the language that make it more powerful or pleasant to us
109109
- [Dependent Function Types](new-types/dependent-function-types.md) generalize dependent methods to dependent function values and types.
110110
- [Polymorphic Function Types](https://github.com/lampepfl/dotty/pull/4672) generalize polymorphic methods to dependent function values and types. _Current status_: There is a proposal, and a prototype implementation, but the implementation has not been finalized or merged yet.
111111
- [Kind Polymorphism](other-new-features/kind-polymorphism.md) allows the definition of operators working equally on types and type constructors.
112+
- [@targetName Annotations](other-new-features/targetName.md) make it easier to interoperate with code written in other languages and give more flexibility for avoiding name clashes.
112113

113114
## Metaprogramming
114115

docs/sidebar.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,10 @@ sidebar:
103103
url: docs/reference/other-new-features/kind-polymorphism.html
104104
- title: Tupled Function
105105
url: docs/reference/other-new-features/tupled-function.html
106-
- title: threadUnsafe Annotation
106+
- title: @threadUnsafe Annotation
107107
url: docs/reference/other-new-features/threadUnsafe-annotation.html
108+
- title: @targetName Annotation
109+
url: docs/reference/other-new-features/targetName.html
108110
- title: New Control Syntax
109111
url: docs/reference/other-new-features/control-syntax.html
110112
- title: Optional Braces
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- [E120] Naming Error: tests/neg/override-erasure-clash.scala:4:6 -----------------------------------------------------
2+
4 |class B extends A: // error
3+
| ^
4+
| Name clash between defined and inherited member:
5+
| def f(): Int in class A at line 3 and
6+
| def g(): Int in class B at line 5
7+
| have the same name and type after erasure.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import annotation.targetName
2+
class A:
3+
def f(): Int = 1
4+
class B extends A: // error
5+
@targetName("f") def g(): Int = 2
6+

0 commit comments

Comments
 (0)