Skip to content

@deco before or after export keyword? #69

Closed

Description

@hax
@deco
export class A {}

or

export @deco class A {}

or allow both?

Activity

  1. rbuckton commented on Mar 4, 2018

    @rbuckton
    Member

    My preference (and the current TypeScript implementation) is before export. More complex decorators like Angular's Component decorator often span multiple lines and the export keyword would end up oddly orphaned at the top otherwise.

    export
    @dec1
    @dec2({
      option1: "foo" 
    })
    class C {
    } 
    
    // vs
    
    @dec1
    @dec2({
      option1: "foo" 
    })
    export class C {
    } 
  2. rbuckton commented on Mar 4, 2018

    @rbuckton
    Member

    I suppose "both" might be an acceptable mix though:

    @dec1
    @dec2({
      option1: "foo" 
    })
    export @sealed class C {
    } 
  3. littledan commented on Mar 4, 2018

    @littledan
    Member

    The current proposal only permits decorators after export. The DecoratorList is part of the ClassDeclaration, which is the thing that the export keyword. Should we revisit this decision?

    This might be a change vs previous versions, which should be documented as part of #50 .

  4. rbuckton commented on Mar 4, 2018

    @rbuckton
    Member

    I recall discussions with @wycats over the past two years where we discussed this and I had thought we had settled on "before export" in the past.

    One of the other reasons for TypeScript's implementation is that we have other possible keywords that can come before class (i.e. declare and abstract) and it seemed weird to write:

    export
    @decorator1
    @decorator2
    abstract class C {
    }

    With multi-line decorators you can end up losing track of the export keyword when looking at the class. It also fairly common to want to refactor your code by adding the export keyword and you might naturally assume you just put the keyword before class (which is the case in other languages like Java (annotations) and C# (attributes)).

  5. rbuckton commented on Mar 4, 2018

    @rbuckton
    Member

    The only other part of the conversation I recall was whether we wanted to eventually allow users to decorate an export binding separate from the class itself. Whether we would ever do such a thing and what that would mean is unclear.

    I had suggested an extension to the syntax to support this in a way similar to how C# attributes allow you to specify placement, via a prefix:

    [assembly: AssemblyVersion("1.0.0")]
    
    class C {
      [return: MarshalAs(UnmanagedType.LPWStr)]
      string Method() { ... }
    }

    We could do the same thing with decorators:

    @decorator1
    @decorator2
    @export: decorator3 // decorates the export binding
    export class C {
      @route("/foo")
      @method: permit("administrators") // decorates the method (optional here)
      @return: serializeAs("json") // decorates the return value
      method() { ... }
    }

    I'm not necessarily saying we have to figure out what those mean, but that there's room in the design space to put together something meaningful that isn't dependent on whether the decorator is before or after the export keyword.

  6. doodadjs commented on Mar 4, 2018

    @doodadjs

    export is static, so I think decorating it is impossible. I think that's better to have the class's decorators just before the class keyword because it clearly shows that the decorators apply to the class, and not to export.

  7. ljharb commented on Mar 4, 2018

    @ljharb
    Member

    Given that export isn't the declaration nor the thing being decorated, I think "after export" is the only thing that makes sense.

    In other words, you don't need to "keep track" of export when you're looking at a long chain of decorators, because the fact that it's exported isn't directly relevant to what's being decorated and how.

  8. rbuckton commented on Mar 4, 2018

    @rbuckton
    Member

    What about if a future proposal adds other keywords before class, for example abstract, final, sealed, static, etc.? Those are logically associated with the class and not the ExportDeclaration, so if they are added there will be an odd mix of export before and these after.

    When TypeScript adds support for ES decorators it will be an all-or-nothing switch, so we can definitely support export-before. Since TypeScript has export-after currently, I will see if I can get some feedback from our community as to whether they find our current syntax ergonomic or unergonomic. Having used it myself for a few years now, I personally find export-after the most ergonomic, easiest to refactor, and visually appealing.

  9. doodadjs commented on Mar 4, 2018

    @doodadjs

    That could be :

    export @mydecorator abstract class {}

    But I think abstract, final, sealed, static and etc. will probably be decorators, so :

    export @mydecorator @abstract class {}
  10. littledan commented on Mar 4, 2018

    @littledan
    Member

    What about if a future proposal adds other keywords before class, for example abstract, final, sealed, static, etc.? Those are logically associated with the class and not the ExportDeclaration, so if they are added there will be an odd mix of export before and these after.

    Why would these keywords make sense before export rather than after? Would @ljharb 's logic in #69 (comment) apply differently to decorators vs these keywords?

  11. rbuckton commented on Mar 4, 2018

    @rbuckton
    Member

    I'm not talking about those keywords before export, but rather the inconsistency of, say:

    export
    @dec
    abstract class C {}
    
    // vs
    
    @dec
    export abstract class C {} 

    In discussing this with others on the TypeScript team, so far the consensus is that we haven't yet heard any negative feedback about our current placement of "before export", which generally indicates that our customers have been happy or at least accepting of that behavior after having decorators as a feature for several years.

    Also, there are some things that can't currently be done in a decorator (i.e. final or sealed) so we can't necessarily wash our hands of the possibility of other future keywords.

  12. ljharb commented on Mar 4, 2018

    @ljharb
    Member

    I guess i don’t understand the inconsistency. If you add or delete the export keyword, the declaration should be the same, conceptually - id find it very inconsistent if the ordering wasn’t “export”, “decorators for the thing”, “thing I’m exporting”.

  13. rbuckton commented on Mar 5, 2018

    @rbuckton
    Member

    Coming from C#, I find the separation of the export keyword from the class keyword by its decorators confusing. In C#, you would write this:

    [attr1]
    [attr2]
    public abstract class C {
    }

    Where public is what makes the class reachable outside of the assembly (i.e. exported). If export needs to be before decorators, it seems like a refactoring pitfall:

    class B {
    }
    
    @dec1
    @dec2
    class C { 
    }

    If I want to export B, I add export before the class keyword. If I want to export C its easy to assume that export goes before the class keyword, just like async goes before the function keyword. It all depends on how you view export. The spec treats it as a declaration in its own right, but its fairly easy for someone to assume export is just a modifier for class just like static is a modifier for a method:

    class C {
      @dec1
      @dec2
      method() {}
    }

    I would refactor method by adding static after the decorators, but before the method name.

  14. rbuckton commented on Mar 5, 2018

    @rbuckton
    Member

    I'd be happy if the spec allowed me to chose one or the other as a personal preference, something like (simplified for brevity's sake):

    ExportDeclaration:
      DecoratorList `export` ClassDeclaration[~Decoratable]
      `export` Declaration[+Decoratable]
    
    ClassDecoratorList[Decoratable]:
      [empty]
      [+Decoratable] DecoratorList
    
    ClassDeclaration[Decoratable]:
      ClassDecoratorList[?Decoratable] `class` BindingIdentifier ...  
    

    Something like that would allow you to choose either export @dec class C {} or @dec export class C {}, but would disallow @dec export @dec class C {}.

  15. doodadjs commented on Mar 5, 2018

    @doodadjs

    @rbuckton The question is : What do you want to decorate with @decorator (while reading from Left-To-Right) ?

    // Decorate "export" ?
    @decorator export abstract class A {}
    
    // Decorate the abstract class ?
    export @decorator abstract class A {}
    
    // Decorate a method ?
    export abstract class A {
        @decorator
        method() {}
    }
  16. 364 remaining items

  17. hax commented on Feb 2, 2023

    @hax
    MemberAuthor

    As the plenary, the consensus is allowing decorators before export XOR after export. (XOR means, @deco export class X {} and export @deco class X {} are both valid, @deco export @deco class X {} is not valid.)

    Thank you everyone to contribute to this 5 years long discussion.

  18. javiervelezreyes commented on Feb 2, 2023

    @javiervelezreyes
  19. bathos commented on Feb 3, 2023

    @bathos

    As the plenary, the consensus is allowing decorators before export XOR after export. (XOR means, @deco export class X {} and export @deco class X {} are both valid, @deco export @deco class X {} is not valid.)

    Thank you everyone to contribute to this 5 years long discussion.

    Wow. Surprise twist in the eleventh hour and it’s like ... beautiful. A rainbow bikeshed!

    I raise my @ to all who fought on this storied battlefield, whether on the right side or the wrong side. Especially those who gave their lives ... you will not be forgotten. Three cheers for decorators!

  20. olee commented on Feb 16, 2023

    @olee

    @hax so if I read this correctly, decorators can now go before export for classes, but the spec in README.md has not been updated yet - is that correct? It still says this:

    • Class decorators come after export and default.
  21. pwhissell commented on Feb 23, 2023

    @pwhissell

    There were only two options for which the community was divided; either the export keyword comes before of after the decorator. In the end the allowing both options was the best solution TC39 could have made.

    It just took too long for this proposal to conclude... way too long.

  22. pwhissell commented on Feb 23, 2023

    @pwhissell

    It feels like there should be a post-mortem focused on how to avoid 5 years of opinionated discussion over a single proposal

  23. ljharb commented on Feb 23, 2023

    @ljharb
    Member

    @pwhissell most proposals are discussed for more years than that, so i'm not sure a postmortem is needed. It's just an expected part of the process for something that by and large we can never reverse (shipping something on the web, i mean)

  24. david0178418 commented on Feb 23, 2023

    @david0178418

    In this case, I think it would have been better to have removed exports entirely from the spec until this was sorted out. Decorators as a whole don't directly depend on this. Anyone using decorators could have just exported them on a separate line in the interim.

    Perhaps future contentious, nonintegral items could be evaluated for piece-wise deferment while the bulk of a proposal goes forward?

  25. pzuraq commented on Feb 23, 2023

    @pzuraq
    Collaborator

    @david0178418 this was not the blocker for the majority of the time that decorators were delayed. This came up again recently, but the main issues that delayed this feature were around performance and API complexity. We went through many, many iterations of design before we found one that worked and solved all constraints.

    I'm planning on writing a blog post on this when I have some time to outline all the different iterations and changes that were made for this feature over time.

  26. david0178418 commented on Feb 23, 2023

    @david0178418

    @pzuraq Ah, I see. Good to know. Thanks for the clarification.

  27. pwhissell commented on Feb 24, 2023

    @pwhissell

    Ah makes sens. I'm curious to understand more about the performance issue

  28. trusktr commented on Mar 12, 2023

    @trusktr
    Contributor

    Comment moved to new issue: #503

  29. pzuraq commented on Mar 12, 2023

    @pzuraq
    Collaborator

    @trusktr this issue has been settled, please don't continue commenting on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions