Skip to content

Enhancing Annotations and Macros #4238

Open
@RohitSaily

Description

@RohitSaily

Proposal: Enhancing Annotations in Dart with Postfix and Expression Syntax

Annotations, including macros, are powerful tools for ensuring systems are robust and for code generation. However, their current usage is limited by where they can be applied in the code. This proposal aims to remove that limitation while maintaining backward compatibility and promoting a consistent and deterministic coding style.

Overview of Changes

Annotations in Expressions

Consider a scenario where there is a performance bottleneck in your code, and you want to optimize a function, c, by inlining it or using an annotation to alter its behavior—such as disabling runtime checks. The function is widely used across the codebase, but the performance-related alteration should only apply at the bottleneck.

Currently, the closest approach to achieving this is:

@noRuntimeChecks final cResult = c();
a(b(cResult));

This requires a verbose multi-line expression to specify the annotation. A more concise and readable solution would be to place the annotation directly within the function call:

a(b(@noRuntimeChecks c()));

Even better, we could place the annotation after the function call to indicate that it's secondary to the implementation logic:

a(b(c() @noRuntimeChecks));

This approach keeps the annotation close to the expression it modifies without interrupting the readability of the code. The annotation is still important, but it's less intrusive and aligns with the overall design of the code. This brings us to the other part of the proposed changes.

Postfix Annotations

One additional change proposed is the ability to define annotations that must be used in a postfix manner. This would enforce consistent and predictable code formatting, which improves readability, especially when dealing with development-time behaviors.

For example, suppose you want to log the result of a function call, validate its invariants, and ensure it's inlined. The current approach requires placing multiple annotations in front of the declaration:

@log @validateInvariants @inline final data = fetchData(id);

With postfix annotations, this could be written as:

final data = fetchData(id) @log @validateInvariants @inline;

This not only improves readability in a single line of code, but it becomes even more advantageous in larger code blocks where annotations might otherwise disrupt the flow. By placing annotations as postfixes, we ensure they are secondary details and don’t interfere with the core implementation logic.

One clear, but still simple, example for multiple lines:

Without postfix annotations

@log @validateInvariants @inline
final data1 = fetchData(id);
@log @validateInvariants @inline
final data2 = fetchData(id + 1);
@log @validateInvariants @inline
final data3 = fetchData(id + 2);

With postfix annotations

final data1 = fetchData(id) @log @validateInvariants @inline;
final data2 = fetchData(id + 1) @log @validateInvariants @inline;
final data3 = fetchData(id + 2) @log @validateInvariants @inline;

Implementation Considerations

To maintain backward compatibility and ensure predictable behavior, postfix annotations must be explicitly defined. This can be achieved through a marker type or by using a prefix annotation.

Example using an annotation:

@postfix const Null annotation = null;

Alternatively, an annotation could implement a PostfixAnnotation marker type:

class Annotation implements PostfixAnnotation
{	const Annotation();
}

These are just a few possible ways to implement this feature. The details of the implementation can vary, but the core idea is to have a clear distinction for postfix annotations.

Conclusion

Dart is already a powerful and customizable language, and adding support for postfix and expression annotations would significantly enhance its flexibility. This proposal aims to improve the readability of code by allowing annotations to be used in more natural and less disruptive ways. Additionally, I foresee this feature being widely adopted by Domain-Specific Languages (DSLs), as it would allow them to define more intuitive and natural syntax for augmenting expressions with additional behaviour.

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureProposed language feature that solves one or more problems

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions