98 lines
3.2 KiB
Markdown
98 lines
3.2 KiB
Markdown
# 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
|
|
```
|