User Defined Attributes/Annotations

Hi,
I’m interested in adding user defined annotations. For example,

	@MyAnnotation func foo() {
	}

This would help enable third party linting and behavioral documentation. This is useful in its own right, but it can also help inform the future direction of static checks within the language.

I’ve started hacking on this (adding a new “Annotation” attribute and associated declaration), but I figured before I went too far I should get some feedback.

···

I imagine you would declare one of these in the following way:
  

	annotation MyAnnotation

and use it as above, using a qualified path if necessary: ``@MyModule.MyClass.MyAnnotation``.

You could also imagine just having a single extendable attribute that takes a string, similar to how C compilers do it, ``@Annotate(“whatever”)`` but that seems error prone and really only works in C because you #define it once and count on the preprocessor to avoid typos. It also doesn’t help prepare for more interesting annotation usage later.

As such, this would introduce a new keyword “annotation”. I think these are sufficiently useful - especially if they end up tying into a macro system - that they deserve a keyword. However, an alternate approach is to overload the existing attribute syntax:

	@Annotation(MyAnnotation)

  or

	@annotation MyAnnotation

  
  To me this seems awkward, as it does not match the style of any other declarations, but adding a new keyword is a big deal, so there’s an obvious trade off.

This proposal does not include annotations with arguments nor does it ascribe any dynamic behavior to those annotations. The static content is limited to checking whether the annotation is already defined.

I deliberately skipped arguments for annotations since there are a lot of questions about defining the types of those arguments, but it's an obvious future extension.

Other possible extensions this proposal needs to not prevent:

1. Providing annotations that actually do things like:
  - Evaluate macros
  - Connect to a protocol or class in some way a la java
  - Python style decorators
2. Limiting annotations to certain syntactic classes.
3. New built in attributes.
4. <Insert your feature idea here>

This initial version is sufficiently minimal that I don’t think any of those would be blocked by it*.

It’s not obvious to me what is the right way to scope user annotations vs new compiler ones. A simple namespace might be best, forcing the compiler to use “_” or lowercase or something like that, but that would involve further migration for existing code.

Anyway, I’m happy to write this up into a proper proposal if there’s general interest.

-Akiva Leffert

* Strawman examples of being compatible with possible extensions

// arguments
annotation Foo(A, B, C)

// macros
annotation macro Bar(A, B, C) {
  … do stuff ...
}

// decorators
annotation func Baz(f : Int -> String) -> (Int -> String) {
  … do stuff ...
}

// only certain syntactic classes
annotation Foo { usage { func, decl, struct, class } }

Hi Akiva,

You mention documentation/linting and static checks - could you elaborate a bit on what exactly the use case for user-defined annotations would be for these things? How would one define a static runtime check in your proposed syntax?

For documentation, it would perhaps suffice if the compiler just ignored any 'unknown' annotations, but would provide them to external lint/documentation tools. Then again we already have documentation comment blocks.

A few other use cases I can think of: serialization (annotate field name to property), concurrency (so you can implement something like @synchronized) and reflection. Not sure whether any of these are in scope for Swift 3.0 though.

Best,
Tommy.

···

Op 10 dec. 2015, om 06:40 heeft Akiva Leffert via swift-evolution <swift-evolution@swift.org> het volgende geschreven:

Hi,
I’m interested in adding user defined annotations. For example,

	@MyAnnotation func foo() {
	}

This would help enable third party linting and behavioral documentation. This is useful in its own right, but it can also help inform the future direction of static checks within the language.

I’ve started hacking on this (adding a new “Annotation” attribute and associated declaration), but I figured before I went too far I should get some feedback.

I imagine you would declare one of these in the following way:
  

	annotation MyAnnotation

and use it as above, using a qualified path if necessary: ``@MyModule.MyClass.MyAnnotation``.

You could also imagine just having a single extendable attribute that takes a string, similar to how C compilers do it, ``@Annotate(“whatever”)`` but that seems error prone and really only works in C because you #define it once and count on the preprocessor to avoid typos. It also doesn’t help prepare for more interesting annotation usage later.

As such, this would introduce a new keyword “annotation”. I think these are sufficiently useful - especially if they end up tying into a macro system - that they deserve a keyword. However, an alternate approach is to overload the existing attribute syntax:

	@Annotation(MyAnnotation)

  or

	@annotation MyAnnotation

  
  To me this seems awkward, as it does not match the style of any other declarations, but adding a new keyword is a big deal, so there’s an obvious trade off.

This proposal does not include annotations with arguments nor does it ascribe any dynamic behavior to those annotations. The static content is limited to checking whether the annotation is already defined.

I deliberately skipped arguments for annotations since there are a lot of questions about defining the types of those arguments, but it's an obvious future extension.

Other possible extensions this proposal needs to not prevent:

1. Providing annotations that actually do things like:
  - Evaluate macros
  - Connect to a protocol or class in some way a la java
  - Python style decorators
2. Limiting annotations to certain syntactic classes.
3. New built in attributes.
4. <Insert your feature idea here>

This initial version is sufficiently minimal that I don’t think any of those would be blocked by it*.

It’s not obvious to me what is the right way to scope user annotations vs new compiler ones. A simple namespace might be best, forcing the compiler to use “_” or lowercase or something like that, but that would involve further migration for existing code.

Anyway, I’m happy to write this up into a proper proposal if there’s general interest.

-Akiva Leffert

* Strawman examples of being compatible with possible extensions

// arguments
annotation Foo(A, B, C)

// macros
annotation macro Bar(A, B, C) {
  … do stuff ...
}

// decorators
annotation func Baz(f : Int -> String) -> (Int -> String) {
  … do stuff ...
}

// only certain syntactic classes
annotation Foo { usage { func, decl, struct, class } }
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Quick feedback: I’d love to see Swift have this sort of functionality someday, but when it exists, it should almost certainly tie into the reflection system. One of our stretch goals for Swift 3 is to rework the "mirror” APIs into a proper reflection system, and the design of user-defined annotations should wait until that settles out IMO.

-Chris

···

On Dec 9, 2015, at 9:40 PM, Akiva Leffert via swift-evolution <swift-evolution@swift.org> wrote:

Hi,
I’m interested in adding user defined annotations. For example,

	@MyAnnotation func foo() {
	}

This would help enable third party linting and behavioral documentation. This is useful in its own right, but it can also help inform the future direction of static checks within the language.

Just chiming in here to say that I've always wanted to add something like @animatable to all animatable properties for my classes. It'd be so much better than searching docs.

R+

···

Sent from my iPhone

On 10 Dec 2015, at 08:30, Tommy van der Vorst via swift-evolution <swift-evolution@swift.org> wrote:

Hi Akiva,

You mention documentation/linting and static checks - could you elaborate a bit on what exactly the use case for user-defined annotations would be for these things? How would one define a static runtime check in your proposed syntax?

For documentation, it would perhaps suffice if the compiler just ignored any 'unknown' annotations, but would provide them to external lint/documentation tools. Then again we already have documentation comment blocks.

A few other use cases I can think of: serialization (annotate field name to property), concurrency (so you can implement something like @synchronized) and reflection. Not sure whether any of these are in scope for Swift 3.0 though.

Best,
Tommy.

Op 10 dec. 2015, om 06:40 heeft Akiva Leffert via swift-evolution <swift-evolution@swift.org> het volgende geschreven:

Hi,
I’m interested in adding user defined annotations. For example,

	@MyAnnotation func foo() {
	}

This would help enable third party linting and behavioral documentation. This is useful in its own right, but it can also help inform the future direction of static checks within the language.

I’ve started hacking on this (adding a new “Annotation” attribute and associated declaration), but I figured before I went too far I should get some feedback.

I imagine you would declare one of these in the following way:
  

	annotation MyAnnotation

and use it as above, using a qualified path if necessary: ``@MyModule.MyClass.MyAnnotation``.

You could also imagine just having a single extendable attribute that takes a string, similar to how C compilers do it, ``@Annotate(“whatever”)`` but that seems error prone and really only works in C because you #define it once and count on the preprocessor to avoid typos. It also doesn’t help prepare for more interesting annotation usage later.

As such, this would introduce a new keyword “annotation”. I think these are sufficiently useful - especially if they end up tying into a macro system - that they deserve a keyword. However, an alternate approach is to overload the existing attribute syntax:

	@Annotation(MyAnnotation)

  or

	@annotation MyAnnotation

  
  To me this seems awkward, as it does not match the style of any other declarations, but adding a new keyword is a big deal, so there’s an obvious trade off.

This proposal does not include annotations with arguments nor does it ascribe any dynamic behavior to those annotations. The static content is limited to checking whether the annotation is already defined.

I deliberately skipped arguments for annotations since there are a lot of questions about defining the types of those arguments, but it's an obvious future extension.

Other possible extensions this proposal needs to not prevent:

1. Providing annotations that actually do things like:
  - Evaluate macros
  - Connect to a protocol or class in some way a la java
  - Python style decorators
2. Limiting annotations to certain syntactic classes.
3. New built in attributes.
4. <Insert your feature idea here>

This initial version is sufficiently minimal that I don’t think any of those would be blocked by it*.

It’s not obvious to me what is the right way to scope user annotations vs new compiler ones. A simple namespace might be best, forcing the compiler to use “_” or lowercase or something like that, but that would involve further migration for existing code.

Anyway, I’m happy to write this up into a proper proposal if there’s general interest.

-Akiva Leffert

* Strawman examples of being compatible with possible extensions

// arguments
annotation Foo(A, B, C)

// macros
annotation macro Bar(A, B, C) {
  … do stuff ...
}

// decorators
annotation func Baz(f : Int -> String) -> (Int -> String) {
  … do stuff ...
}

// only certain syntactic classes
annotation Foo { usage { func, decl, struct, class } }
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Hi Akiva,

You mention documentation/linting and static checks - could you elaborate a bit on what exactly the use case for user-defined annotations would be for these things? How would one define a static runtime check in your proposed syntax?

You wouldn’t define a static runtime check directly. That's the responsibility of external tools. Swift linter tools have already started to appear, though I don’t think any of them are taking advantage of the compiler tooling yet. User defined annotations would give them a lot more options and potential power and help motivate an ecosystem. You could imagine a way to have pluggable checks be part of the core language infrastructure, but that seemed out of scope.

As an example of a check, there was a previous discussion of a scope based access control modifier. It would be relatively straightforward to define an attribute for that and linter pass for it, see if people find it has value and if so, feed it back into the core language.

Some other off the cuff examples of annotations include:
1. Key-value observable
2. Must call super
3. Animatable (as mentioned by Rudolf)
4. Should be on main thread
5. Side effect free

Some of these are just for standardizing documentation, and some could have actual checks associated with them.

I haven’t looked at this closely, but I expect it would allow several existing attributes, like IBAction and friends, to move out of the core language and into libraries.

Further, part of the point of custom annotations is to allow the community to experiment with new features without having to accept them into the core language. Having a feature like this helps prepare for whatever good ideas people have later. Some of those ideas will of course, not be good, but by allowing them to start out as user defined tags we can validate them and find the ones that have real value. You can see this sort of thing happening in the Java community around annotations like @Override and @Nonnull.

For documentation, it would perhaps suffice if the compiler just ignored any 'unknown' annotations, but would provide them to external lint/documentation tools. Then again we already have documentation comment blocks.

I think having the compiler check that your annotations exist has value. Typos are easy to make.

A few other use cases I can think of: serialization (annotate field name to property), concurrency (so you can implement something like @synchronized) and reflection. Not sure whether any of these are in scope for Swift 3.0 though.

Yeah, these are useful features for sure and annotations could go that way in the long term. This proposal is more of a stake in the ground to get things started and help inform the direction of those designs, while also providing enough initial value to be worthwhile on its own.

-Akiva Leffert

···

On Dec 10, 2015, at 2:30 AM, Tommy van der Vorst <tommy@pixelspark.nl> wrote:

Really thrilled to hear that this is a priority. Custom annotation types (and a reflection API to consume them) were something I took advantage of constantly when writing Java and would very much love to see them in Swift.

···

On Dec 10, 2015, at 9:09 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 9, 2015, at 9:40 PM, Akiva Leffert via swift-evolution <swift-evolution@swift.org> wrote:

Hi,
I’m interested in adding user defined annotations. For example,

	@MyAnnotation func foo() {
	}

This would help enable third party linting and behavioral documentation. This is useful in its own right, but it can also help inform the future direction of static checks within the language.

Quick feedback: I’d love to see Swift have this sort of functionality someday, but when it exists, it should almost certainly tie into the reflection system. One of our stretch goals for Swift 3 is to rework the "mirror” APIs into a proper reflection system, and the design of user-defined annotations should wait until that settles out IMO.

-Chris

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution