Create annotation-arguments.md
(cherry picked from commit 202ea7c)
This commit is contained in:
committed by
Denis Zharkov
parent
27b1f1ddad
commit
84ed0e7255
@@ -0,0 +1,93 @@
|
||||
# Annotation Arguments
|
||||
|
||||
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 sould 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
|
||||
```
|
||||
Reference in New Issue
Block a user