Skip to main content

Proposal to add metadata to Dart language

Posted by Peter von der Ahé

Disclaimer: This is an early proposal, it is not in the Dart language spec yet. This might change or be retracted. Comments welcome!

UPDATE: Join the discussion about this proposal on the Dart mailing list.

Dart Metadata Level 1

We propose to add metadata in the form of constant expressions prefixed with ‘@’. For example:

class Object {
  …
 @native int hashCode();
}

In the example above, the metadata is highlighted in blue.

The grammatical rule for metadata is:

metadata: '@' expression ;

The expression must be a constant expression.

The example above assumes these additional declarations:

class Native {
 const Native();
}

const native = const Native();

Informally, metadata can appear before a class, interface, typedef, constructor, factory, function, field, parameter, or variable declaration. For example:

@metadata
interface MyInterface {
 @metadata var field;
 @metadata get getter();
 @metadata String method(@metadata parameter, [@metadata optional]);
}

@42
class MyClass {
 @metadata MyClass(@metadata parameter) {
   @metadata localFunction() => 42;
   @metadata var variable = null;
   for (@metadata var i in [1, 2, 3]) {
     print(i);
   }
 }
}

Since metadata can be any constant expression, the following is possible:

@const <int>[1, 2, 3]
class MyOtherClass {
}

Metadata is fully reified and available through mirror-based reflection, in other words, unless reflection is enabled, metadata can be ignored.

Q: Can I access metadata on local variables?
A: It depends: Does the mirror API expose AST nodes? Most likely not, initially.

Q: Can I access metadata on a local function?
A: An object mirror on a closurized local function should be able to return the metadata of the corresponding function declaration. In addition, if the mirror API exposes AST nodes, such AST nodes will include the metadata.

Open question: what about raw strings?



As always, please join the discussion on the Dart mailing list.

Comments

  1. I like it. I think unit tests are a bit clunky at the moment due to the fact that you can't just annotate a class with @TestFixture, @Test, etc. It would make dart more analogous to languages like C# and Java, which I think is a good thing.

    ReplyDelete
  2. Are these going to be annotations or are they going to be python decorator style?

    ReplyDelete
    Replies
    1. I still think dart should "have" python style decorators :)

      Delete
    2. For someone who hasn't touched python for quite some time, what is the distinction? Annotate, decorate -- It seems to me they set out to accomplish the same thing.

      Delete
    3. Python decorations are completely different. The "decoration" means that the declaration it's decorating is passed through the decoration, and then the return value from that is used as the declaration. So they can change the declaration however they want to, to do whatever they want to. It's a semi-structured way to have meta-programming, or to simply put a field in the declaration, whichever you want.

      Delete
  3. I like the fact that the metadata is a constant.

    ReplyDelete
  4. What problem(s) is the meta data feature meant to solve?

    It's impossible to evaluate a proposed feature without knowing this.


    Are those problem(s) widespread?

    One thing I've learned about good software design is to make the common case simple. If the meta data isn't solving significant common problems, then don't clutter Dart with it and it's conceptual overhead. In other words, keep Dart as simple as possible for the most common uses.

    What other solutions might solve those problems?

    Once you list the problems metadata aims to solve, then you can begin to compare it to other possible solutions.

    ReplyDelete
  5. I think it's a bad idea to not have the decorators/metadata/attributes not be sourced through a single inheritance hierarchy. Can you imagine code that just has some object as metadata? Is it extensible, portable, explicable, maintainable? You can't force people to write good code, but you don't have to give them the tools to write bad code.

    Forcing everything into a hierarchy means that documentation can clearly isolate them like exceptions are now, that development tools can give strong hints on what can be applied, and it allows future extensibility of the concept for restricted attributes (like saying that an attribute only works on classes) or attributes that actively change the code (similar to how Python does it, but more structured).

    If I'm understanding constness as it stands right now though, it's actually impossible to have an attribute object because "new" is not const. So I'd have to join DevDanke in wondering what on Earth this is supposed to be used for.

    ReplyDelete
    Replies
    1. Actually, annotations constrained to const expressions are still pretty powerful -- at least as powerful as in Java, maybe more. There's only a small hint at the end of the article, "@const <int>[1, 2, 3]", but it shows that you can really use an arbitrary compile-time constant expression. So the original "@native" could just as well be "@const Native()", but the former variant is better for often used features.

      Remember that you can write const constructors for your own classes, and also that static methods and top-level functions are compile-time constants... that is pretty powerful, right?

      Now I don't really understand questions about the reason -- Java and C# both proved that the ability to attach metadata to code is extremely valuable. If you want to see that the Dart project needs it, then look at http://dartbug.com/3752 or http://dartbug.com/3753.

      Delete
    2. Thanks Ladislav, const constructors were the piece of information I was missing here. I fully agree that structured attributes/decorators/metadata are very useful. But attaching random data to a declaration is worse than useless, and there's no excuse for it - a class doesn't take that much effort to create, and puts the methods to process the data in the right place. Why retain a clumsy syntax just so we can support something (random metadata) that shouldn't be used?

      So I'd still say the metadata/attributes/decorators should inherit from a root class, and use a tiny bit of syntax sugar to allow that to just be "@Native".

      Delete
    3. I don't see why forcing annotations to always be classes inheriting from a specific single root would "add more structure" -- they already inherit from Object. I know that C# (or actually .NET) does this (as opposed to Java), and the System.Attribute class doesn't seem to contain any valuable methods (all those GetCustomAttribute[s] and IsDefined could/would/should be part of the reflection API in Dart). And it would actually complicate the metadata system -- a great value of this proposal is its huge simplicity (which doesn't take away any power).

      Delete
    4. Like I said, it's because it more naturally leads into extensions to the metadata system like restrictions on application and metaprogramming, and the advantage in documentation and development tools. If you don't force a single class hierarchy and you want to do that later, then you're going to have to say that one class is magical and has completely different effects from every other class that could be applied as metadata - that's different than saying that one class is special and needs to be your common inheritance source. I'm against magical classes, they're sloppy. Special classes, though, are great. Can you think of a non-contrived scenario where you just can't inherit your metadata from Metannotattribute?

      Java's annotations actually source from a single class/interface - annotations are just another way to write a class that's somewhat less burdensome in that language. It's here:

      http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/annotation/Annotation.html

      They shouldn't actually have any methods (the few in C# ARE duplicated in the reflection types and should be there). That's not what makes them useful. They're special types upon which hang special handling by the compiler and future extensions, and serve as a common source for documentation and other stuff.

      Delete
    5. Doh, right about that common superinterface in Java.

      What I like about this proposal is that it adds very little to the machinery -- it reuses everything that is already there. Wanna add multiple annotations? Just write a const list. Wanna specify a behavior in metadata (preconditions, for example)? Use a top-level function. Etc. No special ceremony necessary.

      Maybe forcing all annotations to implement a special interface / inherit from a special class does add some structure, which Dart is all about, but it would complicate stuff a bit. At the very least, we would need a special capability for adding multiple annotations, because I can't see List implementing a special interface just for this purpose. Thinking about it some more, I wouldn't oppose such change (and I think that it's quite likely that it will happen), but I still love the simplicity of this proposal.

      Delete
  6. It looks like a solution in search of a problem...

    ReplyDelete
  7. Can someone provide an example where metadata is necessary/improves readability a lot? The only case I know is JUnit from Java. Since dart has callbacks, this isn't a problem:

    class Tests {
    A() {}
    }

    main() {
    var test = new Tests();
    test('testA', test.A);
    }

    ReplyDelete
  8. IMO, abstractly, the callback way is stronger or more invasive than metadata way in the syntax and semantics. your "Callback" still advocates the hard coupled codes.(although I do not think your "callback" is the same level concept to the metadata)

    ReplyDelete
  9. Metadata is used for _many_ purposes including allowing frameworks to apply behaviors to user-defined classes and provide performance hints to runtime environments. In Hibernate you can use annotations to do things like indicate a field is commonly searched and should therefor be indexed, in Spring its used for IoC, in JUnit they identify tests, etc. The question of whether metadata is useful was answered long ago. The addition of annotations to Java and C# greatly enhanced the languages in many ways including reducing the mess of XML files that used to accompany even trivial applications.

    ReplyDelete

Post a Comment

Popular posts from this blog

Const, Static, Final, Oh my!

Posted by Seth Ladd

(This is an "oldie but a goodie" misc@dartlang.org post originally written by Bob Nystrom. It is being posted here as the explanations still ring true.)

Bob writes:


"static", "final", and "const" mean entirely distinct things in Dart:

"static" means a member is available on the class itself instead of on instances of the class. That's all it means, and it isn't used for anything else. static modifies *members*.

"final" means single-assignment: a final variable or field *must* have an initializer. Once assigned a value, a final variable's value cannot be changed. final modifies *variables*.

"const" has a meaning that's a bit more complex and subtle in Dart. const modifies *values*. You can use it when creating collections, like const [1, 2, 3], and when constructing objects (instead of new) like const Point(2, 3). Here, const means that the object's entire deep state can be determ…

AngularDart 4

AngularDart v4 is now available. We've been busy since the release angular2 v3.1.0 in May. Not only did we "drop the 2", but we also improved the compiler and tightened up the framework to give you smaller code, we updated the package structure to improve usability, and we added several new features. Check out the updated documentation to get started.
Just angular Upgrading to v4 will require more than updating your version constraint. The package has changed names (back) to angular – dropping the 2. You'll need to update your pubspec.yaml and the corresponding imports in your code. In most instances, find-and-replace should do the trick. Going forward, the package will be called package:angular. We'll just update the version number.
Smaller code The updated compiler in 4.0 allows type-based optimizations that not only improve runtime performance but generate better code because we are able to strongly type templates. A big result of the update is that many ap…

The new AdWords UI uses Dart — we asked why

Google just announced a re-designed AdWords experience. In case you’re not familiar with AdWords: businesses use it to advertise on google.com and partner websites. Advertising makes up majority of Google’s revenue, so when Google decides to completely redo the customer-facing front end to it, it’s a big deal. The Dart team is proud to say that this new front end is built with Dart and Angular 2. Whenever you asked us whether Google is ‘even using Dart for anything,’ this is what we had in mind but couldn’t say aloud. Until now. We asked Joshy Joseph, the primary technical lead on the project, some questions. Joshy is focusing on things like infrastructure, application latency and development velocity, so he’s the right person to ask about Dart.Q: What exactly did we launch on Monday?It’s a complete redesign of the AdWords customer experience that is rolling out slowly as a test to a small initial set of advertisers. The most noticeable thing is probably the Material Design look and f…