Design notes changed according to changed annotation option design
This commit is contained in:
@@ -9,20 +9,20 @@ See [related discussion about Scala](http://lampwww.epfl.ch/~mihaylov/attributes
|
||||
|
||||
For each option of annotations there's a general dichotomy of how it can be specified in code.
|
||||
|
||||
Option 0: Separate annotations
|
||||
Option 0 (final): Separate annotations in the same way as Java annotation options
|
||||
|
||||
``` kotlin
|
||||
retention(SOURCE)
|
||||
target(CLASSIFIER, FIELD)
|
||||
@Retention(SOURCE)
|
||||
@Target(CLASS, FIELD)
|
||||
annotation class example
|
||||
```
|
||||
|
||||
Option 1: Make `annotation` into an annotation, and use its properties
|
||||
|
||||
``` kotlin
|
||||
annotation(
|
||||
@annotation(
|
||||
retention = SOURCE,
|
||||
targets = array(CLASSIFIER, FIELD)
|
||||
targets = array(CLASS, FIELD)
|
||||
)
|
||||
class example
|
||||
```
|
||||
@@ -30,7 +30,7 @@ class example
|
||||
A variation of this is
|
||||
|
||||
``` kotlin
|
||||
annotation(target(CLASSIFIER, FIELD), retention = SOURCE) class example
|
||||
@annotation(target(CLASS, FIELD), retention = SOURCE) class example
|
||||
```
|
||||
|
||||
Annotations can be parameters to other annotations.
|
||||
@@ -39,10 +39,10 @@ Having option as separate annotation is what Java has and seems more extensible,
|
||||
|
||||
Having those as parameters is more discoverable, but has some syntactic shortcomings: no varargs can be used.
|
||||
|
||||
Option 2 (final): combination
|
||||
Option 2: combination
|
||||
|
||||
``` kotlin
|
||||
target(CLASSIFIER, FIELD) annotation(retention = SOURCE, repeatable = false, documented = false) class example
|
||||
@Target(CLASS, FIELD) @annotation(retention = SOURCE, repeatable = false, documented = false) class example
|
||||
```
|
||||
|
||||
It makes sense because target can have vararg as its argument, and everything else (retention, repeatable, and may be documented / inherited in future) is combined into one annotation.
|
||||
@@ -59,8 +59,7 @@ To check applicability, we can use the following constants:
|
||||
|
||||
| Kotlin constant | Java constant |
|
||||
|-----------------|---------------|
|
||||
| PACKAGE | \<same> |
|
||||
| CLASSIFIER | TYPE |
|
||||
| CLASS | TYPE |
|
||||
| ANNOTATION_CLASS | ANNOTATION_TYPE |
|
||||
| TYPE_PARAMETER | \<same>
|
||||
| PROPERTY | \<no analog> |
|
||||
@@ -114,34 +113,36 @@ Also there are some exotic type usages, such as ones on outer types: `@A (@B Out
|
||||
|
||||
Kotlin has more possible targets than Java, so there's an issue of mapping back and forth. The table above gives a correspondence.
|
||||
|
||||
When we compile a Kotlin class to Java, we write a `@java.lang.annotation.Target` annotation that reflects the targets. For targets having no correspondent ones in Java (e.g. `EXPRESSION`) nothing is written to `j.l.a.Target`. If the set of Java targets is empy, `j.l.a.Target` is not written to the class file.
|
||||
When we compile a Kotlin class to Java, we write a `@java.lang.annotation.Target` annotation that reflects the targets. For targets having no correspondent ones in Java (e.g. `EXPRESSION`) nothing is written to `j.l.a.Target`. If the set of Java targets is empty, `j.l.a.Target` is not written to the class file.
|
||||
|
||||
In addition to `java.lang.annotation.Target`, a Kotlin-specific annotation `kotlin.target` is written containing all the Kotlin targets listed:
|
||||
In addition to `java.lang.annotation.Target`, a Kotlin-specific annotation `kotlin.annotation.Target` is written containing all the Kotlin targets listed:
|
||||
|
||||
``` kotlin
|
||||
package kotlin.annotation
|
||||
|
||||
enum class AnnotationTarget {
|
||||
PACKAGE
|
||||
CLASS,
|
||||
ANNOTATION_CLASS,
|
||||
...
|
||||
}
|
||||
|
||||
target(ANNOTATION_CLASS)
|
||||
annotation(RUNTIME) class target(vararg allowedTargets: AnnotationTarget)
|
||||
@Target(ANNOTATION_CLASS)
|
||||
@Retention(RUNTIME)
|
||||
annotation class target(vararg allowedTargets: AnnotationTarget)
|
||||
```
|
||||
|
||||
When loading an annotation, we only read `kotlin.target`. When `kotlin.target` is missing, on the JVM, we read `j.l.a.Target` and map its values to Kotlin ones according to the table above. This implies that we can load pure Java annotations that know nothing about Kotlin, and that an annotation written in Java can be targeted, e.g. for Kotlin expressions, because one can simply manually specify `kotlin.target` for it.
|
||||
When loading an annotation, we only read `kotlin.annotation.Target`. When `kotlin.annotation.Target` is missing, on the JVM, we read `j.l.a.Target` and map its values to Kotlin ones according to the table above. This implies that we can load pure Java annotations that know nothing about Kotlin, and that an annotation written in Java can be targeted, e.g. for Kotlin expressions, because one can simply manually specify `kotlin.annotation.Target` for it.
|
||||
|
||||
### Syntax
|
||||
|
||||
It makes sense to use `kotlin.target` explicitly in Kotlin code:
|
||||
It makes sense to use `kotlin.annotation.Target` explicitly in Kotlin code:
|
||||
|
||||
``` kotlin
|
||||
target(EXPRESSION, TYPE)
|
||||
@Target(EXPRESSION, TYPE)
|
||||
annotation class MyAnn
|
||||
```
|
||||
|
||||
> An alternative would be to make target a property of `kotlin.annotation`, but then we'd
|
||||
> An alternative would be to make target a property of `kotlin.annotation.annotation`, but then we'd
|
||||
* lose the advantage of varargs, because there are more optional parameters
|
||||
* be non-uniform with Java, thus making it harder to figure how to make a Java annotation Kotlin-friendly
|
||||
|
||||
@@ -163,13 +164,12 @@ enum class AnnotationRetention {
|
||||
}
|
||||
```
|
||||
|
||||
> Now, we could map `java.lang.annotation.Retention` and `RetentionPolicy` to `kotlin.retention` and `kotlin.AnnotationRetention`, and then map `CLASS` to `BINARY`, but that is a little too much
|
||||
|
||||
Then, it makes sense to make `retention` a property of `kotlin.annotation`:
|
||||
We map `java.lang.annotation.Retention` and `RetentionPolicy` to `kotlin.annotation.Retention` and `kotlin.annotation.AnnotationRetention`, and `CLASS` to `BINARY`.
|
||||
|
||||
``` kotlin
|
||||
target(TYPE)
|
||||
annotation(SOURCE) class MyAnn
|
||||
@Target(TYPE)
|
||||
@Retention(SOURCE)
|
||||
annotation class MyAnn
|
||||
```
|
||||
|
||||
The following checks must be performed at compile time:
|
||||
@@ -179,7 +179,7 @@ The following checks must be performed at compile time:
|
||||
|
||||
> Java has `Repeatable` as an annotation, but we cannot map a Kotlin type to it, because it is only present since JDK 8, and cannot be written to class files with version lower than 8.
|
||||
|
||||
We make `repeatable` a boolean property of `kotlin.annotation`, with default value `false` (as in Java and C#).
|
||||
We make `kotlin.annotation.Repeatable` a separate annotation which makes annotation repeatable if presents.
|
||||
|
||||
If a non-repeatable annotation is used multiple times on the same element, it is a compile-time error.
|
||||
|
||||
@@ -189,21 +189,9 @@ A repeatable annotation with source retention may be used multiple times on any
|
||||
|
||||
## Documented
|
||||
|
||||
We make `documented` a boolean property of `kotlin.annotation`, with default value `false`. This property is mapped to the same platform-specific annotation, if any.
|
||||
We make `kotlin.annotation.MustBeDocumented` a separate annotation. This annotation is mapped to the same platform-specific annotation, if any (e.g. j.l.a.Documented).
|
||||
|
||||
## Inherited
|
||||
|
||||
This one is of rather unclear value, and we do not support it in Kotlin. One can use platform-specific annotation to express it.
|
||||
|
||||
## Appendix. Definition of kotlin.annotation
|
||||
|
||||
``` kotlin
|
||||
package kotlin.annotation
|
||||
|
||||
target(ANNOTATION_CLASS)
|
||||
annotation(SOURCE) class annotation(
|
||||
val retention: AnnotationRetention = RUNTIME,
|
||||
val repeatable: Boolean = false,
|
||||
val documented: Boolean = false
|
||||
)
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user