From 84ed0e7255c0baaf3bd72bb736b4f11894f02c8a Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 26 Mar 2015 19:59:57 +0300 Subject: [PATCH] Create annotation-arguments.md (cherry picked from commit 202ea7c) --- spec-docs/annotation-arguments.md | 93 +++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 spec-docs/annotation-arguments.md diff --git a/spec-docs/annotation-arguments.md b/spec-docs/annotation-arguments.md new file mode 100644 index 00000000000..afd9e63a5c6 --- /dev/null +++ b/spec-docs/annotation-arguments.md @@ -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 +```