dart-lang / language

Design of the Dart language
Other
2.67k stars 205 forks source link

Allow functions to be used directly as metadata annotations #3210

Open GregoryConrad opened 1 year ago

GregoryConrad commented 1 year ago

I haven't actually looked at the language spec to know for sure whether this is considered a bug or not, but this definitely seems like some unwanted behavior. Filing here instead of sdk since I'm guessing it is due to the language specification.

void foo() {}
const bar = foo;

class Metadata {
  const Metadata(this.f);
  final void Function() f;
}

// @foo        // fails to compile, but this seems like it should
@bar           // ok, despite just being = foo
@Metadata(foo) // ok
void foobar() {}

Using functions as metadata annotations will be useful for when static metaprogramming roles around.

eernstg commented 1 year ago

Metadata is specified to be a reference to a constant variable, or an invocation of a constant constructor, and everything else is a compile-time error.

I'm not quite sure why the rules are so strict (these rules haven't been changed recently, if ever), and you have already mentioned that the function object foo can be used as metadata by declaring a constant variable bar and using that.

Syntactically, an expression that denotes a statically resolved function is already covered by the grammar rule about metadata.

So we should be able to introduce this generalization without breaking anything.

lrhn commented 1 year ago

(these rules haven't been changed recently, if ever)

Only change I remember was to allow type arguments to constructor invocations. Don't remember if we added "qualified identifier" at some much earlier point, but I think named constructors predate metadata, so it was probably there since the start.

If we allow constant function tear-offs, we should consider whether to allow instantiated function tear-offs (with constant type arguments).

That won't actually complicate the grammar much, since we already accounted for all the problems when introducing record types:

... since @metadata<T> appears to be a generic instantiation and could potentially be valid syntax in the future.

It should just work.

We already allow <qualifiedIdentifier>, which is enough to denote any static function, even if it requires three steps like prefix.ClassName.methodName.

If we allow static functions, we can also allow constructor tear-offs, which would mean allowing new as final "identifier", and generics after the next-to-last name in the chain.

So, something like:

<metadatum> ::= 
     <identifier> <typeArguments>? 
   | (<typeIdentifier> '.')? <typeIdentifier> <typeArguments>? ('.' <constructorName>)? (NO_SP <arguments>)?

<constructorName> ::= <identifier> | 'new'
jtkeyva commented 9 months ago

+1

munificent commented 8 months ago

I think named constructors predate metadata

I believe you're correct.

m-sadegh-sh commented 4 months ago

+1