File: annotation-arguments.md

package info (click to toggle)
kotlin 1.3.31%2Bds1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 109,908 kB
  • sloc: java: 454,756; xml: 18,599; javascript: 10,452; sh: 513; python: 97; makefile: 69; ansic: 4
file content (97 lines) | stat: -rw-r--r-- 3,283 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# Annotation Arguments

**NOTE**: This document contains old language design notes and does not correspond to the current state of Kotlin. Please see http://kotlinlang.org/docs/reference/annotations.html for up-to-date documentation on this topic. 

***

Goals:
* Sort out problems of positional parameters and varargs in annotations
* \[TBD later] Better syntax for array arguments to annotations

Related issues:
* [KT-6652 Prohibit using java annotations with positional arguments](https://youtrack.jetbrains.com/issue/KT-6652)
* [KT-6220 Annotations: handling of "value" members](https://youtrack.jetbrains.com/issue/KT-6220)
* [KT-6641 Annotations with multiple array values](https://youtrack.jetbrains.com/issue/KT-6641)
* [KT-2576 Shortcut notation for annotations with single-value array elements](https://youtrack.jetbrains.com/issue/KT-2576)

## Problem Statement

In Java annotation elements (this is the term java uses for "fields"/"attributes"/"properties" of an annotation) are defined as methods in the corresponding `@interface`, so there is no ordering rule that we can use when loading a fictitious primary constructor for a Java annotation.

Example:

Let's say there's a Java annotation with two elements:

``` java
@interface Ann {
    int foo();
    String bar();
}
```

When we use it in Kotlin, we can use positional arguments:

``` kotlin
[Ann(10, "asd")]
class Baz
```

Now, it's both source- and binary- compatible to reorder methods in a Java interface:

``` java
@interface Ann {
    String bar();
    int foo();
}
```

But the code above will break.

Also, we now load all array arguments as varargs, which may break for the same reason.

## Loading Java Annotations

Fictitious constructors for Java annotations could be built as follows:
* if there is an element named `value`, it is put first on the parameter list
* if all other elements have default values, and `value` has an array type, it is marked `vararg` and has the type of the elements of the array
* parameters corresponding to all elements but `value` can not be used positionally, only named arguments are allowed for them (this requires adding a platform-specific check to `frontend.java`)
* note that elements with default values should be transformed to parameters with default values

>**NOTE**: when `value` parameter is marked `vararg` and no arguments are passed, behavior will depend on presence of parameter's default value:
* if it has no default value, an empty array is emitted in the byte code
* if it has a default value, then no value is emitted in the byte code, so the default value will be used

> Thus, **behavior of the same code can change after adding a default value to parameter and recompiling kotlin
sources**

## \[TBD later] Array Syntax Examples

**NOTE**: Scala still uses `Array(...)` in annotations, no matter how ugly it is

Option 1: Use `[]` for array literal

``` kotlin
@User(
  firstName = "John",
  names = ["Marie", "Spencer"],
  lastName = "Doe"
)
class JohnDoe

@Values([FOO, BAR]) // ugly, but it's the same in Java: @Ann({FOO, BAR})
class WithValues
```

Option 2: Use `@(...)`

``` kotlin
@User(
  firstName = "John",
  names = @("Marie", "Spencer"),
  lastName = "Doe"
)
class JohnDoe

@Values(@(FOO, BAR)) // looks bad
class WithValues
```