Tapestry 5
  1. Tapestry 5
  2. TAP5-777

Tapestry should ensure that mixins are applied in a deterministic order.

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 5.1.0.5
    • Fix Version/s: 5.2.0
    • Component/s: None
    • Labels:
      None

      Description

      Currently, the only ordering tapestry does on mixins is to ensure that render phase methods on @MixinAfter mixins are invoked after the corresponding component event handler.
      Beyond that, ordering is stochastic. It would be nice if mixins were applied in a deterministic order. Consider the case where a mixin shortcuts some phase of rendering. Another mixin may need that phase to be executed to perform properly. With stochastic ordering, the resulting behavior is basically unknown and could vary from application executing to application execution. With deterministic ordering, the mixins could be defined in such a way that both mixins function properly.

      As I see it, there are two ways this problem could be solved.
      One is to have a simple, pre-defined ordering, something like: template mixins in the order they are defined, followed by mixins defined via the @Mixins annotation in the order listed, followed by the implementation mixins, in the order the field are defined in the class. This has the advantage of simplicity. However, I can imagine scenarios where one might want an instance mixin to execute before an implementation mixin. The ordering could be reverse, but then the opposite problem applies: what if you want something executed after?
      A compromise would be something like: @Mixins mixins, @Mixin mixins, template-defined mixins. But this starts to get confusing.

      An alternative approach would be to allow the ordering of mixins to be defined explicitly, similar to how ordered configurations are defined and processed. Something like:
      <t:textfield t:mixins="mixina,mixinb;before:*,mixinc,mixind;after:mixina mixinb"/>

      This would be backwards compatible in that:
      <t:textfield t:mixins="mixina,mixinb,mixinc,mixind"/> would still function, and would function as before: stochastic ordering, whereas the first approach would slightly alter component/mixin behavior for previously defined component trees.

        Activity

        Hide
        Robert Zeigler added a comment -

        After giving this some more thought, it seems like the "right" way to do this is option #2.
        1) Allows the most flexibility
        2) Preserves current behavior for existing component trees.

        Show
        Robert Zeigler added a comment - After giving this some more thought, it seems like the "right" way to do this is option #2. 1) Allows the most flexibility 2) Preserves current behavior for existing component trees.
        Hide
        Alfie Kirkpatrick added a comment -

        My main interest in this enhancement is to ensure that Javascript event handlers are executed in a deterministic order, so would want to ensure that if two mixins call renderSupport.addInit, we can control the order of init methods which may then add onclick and other event listeners. Am assuming your approach would achieve this.

        Show
        Alfie Kirkpatrick added a comment - My main interest in this enhancement is to ensure that Javascript event handlers are executed in a deterministic order, so would want to ensure that if two mixins call renderSupport.addInit, we can control the order of init methods which may then add onclick and other event listeners. Am assuming your approach would achieve this.
        Hide
        Robert Zeigler added a comment -

        The implementation (it's done, but needs documenting and therefore hasn't been committed yet) allows you to order mixins just like you order services for an OrderedContribution (same underlying algorithm). So: before:* works, or before:somemixinid, etc. You can definitely control the order in which addInit is called. That said, you would need to check renderSupport.addInit to ensure that the order that initializations are rendered is the order in which they are added; I'm not positive that it makes that guarantee at the moment.

        Show
        Robert Zeigler added a comment - The implementation (it's done, but needs documenting and therefore hasn't been committed yet) allows you to order mixins just like you order services for an OrderedContribution (same underlying algorithm). So: before:* works, or before:somemixinid, etc. You can definitely control the order in which addInit is called. That said, you would need to check renderSupport.addInit to ensure that the order that initializations are rendered is the order in which they are added; I'm not positive that it makes that guarantee at the moment.

          People

          • Assignee:
            Robert Zeigler
            Reporter:
            Robert Zeigler
          • Votes:
            1 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development