I did a sweep on some of the less common bindings a couple of years ago.
I think a few things that were working then may no longer be working after
various changes. I need to check the test project for that.
I'm happy to revisit that if people send me their binding bugs (better
still add an issue wtih example and assign to me).
But I want to get some other things in first, so probably won't get to that
until end of next week.

-Greg


On Fri, Dec 7, 2018 at 9:43 AM Harbs <harbs.li...@gmail.com> wrote:

> What I’m not sure is how any of this worked in minified code.
>
> I’ve used [Bindable]private quite a lot…
>
> I’m not sure how to best fix this, but it does seem like a problem which
> needs fixing.
>
> > On Dec 6, 2018, at 9:59 PM, Greg Dove <greg.d...@gmail.com> wrote:
> >
> > The other thing to consider is the ValueChangeEvent  that is being
> > dispatched for automatically generated private [Bindable] vars
> >
> > It keeps the undecorated name in terms of what it dispatches.
> >
> > so for
> > [Bindable]
> > private var test:String
> >
> > you get
> >
> this.dispatchEvent(org.apache.royale.events.ValueChangeEvent.createUpdateEvent(
> >         this, "test", oldValue, value));
> >
> > in the generated setter
> > but the test with the local name is
> > if (value != this.com_foo_bar_test_)
> > or similar
> >
> > I did not use private bindings very often. I wonder what would happen in
> > legacy flex code if a parent class had a bindable private var and a
> > subclass had a bindable private var with the same name. I expect they
> both
> > might dispatch the same property change events. And of course they could
> be
> > completely different types. I'm not going to test this :).
> >
> > The point is that I assume the dispatched event should still have the
> > original (undecorated) name. So maybe this is more tricky and should
> always
> > be with a getter/setter like Alex suggests.
> >
> > Just sounding off some quick thoughts. I have not thought too deeply
> about
> > this, I am sure you will!
> >
> >
> >
> >
> >
> >
> >
> >
> > On Fri, Dec 7, 2018 at 8:16 AM Greg Dove <greg.d...@gmail.com> wrote:
> >
> >> Hi Andrew, I just had a quick go at doing this locally. I *think* it
> >> should be able to be done in MXMLRoyaleEmitter with minor changes.
> >>
> >> I have not tested extensively, so I will just describe what I did and
> you
> >> can see if it works, and if it is universally applicable.
> >>
> >> The following is what I did:
> >>
> >> change the
> >> encodeWatcher method signature to this:
> >> private void encodeWatcher(WatcherInfoBase watcherInfoBase, IDefinition
> >> sourceDefinition)
> >>
> >> and make 2 changes inside that method:
> >>
> >> #1.
> >> for the part that is:
> >> writeNewline(ASEmitterTokens.DOUBLE_QUOTE.getToken() +
> >> propertyWatcherInfo.getPropertyName() +
> >>                    ASEmitterTokens.DOUBLE_QUOTE.getToken() +
> >> ASEmitterTokens.COMMA.getToken());
> >>
> >> replace with this:
> >>
> >>            String outputName = propertyWatcherInfo.getPropertyName();
> >>            if (sourceDefinition != null && sourceDefinition.isPrivate()
> >> && getMXMLWalker().getProject().getAllowPrivateNameConflicts()) {
> >> JSRoyaleEmitter fjs = (JSRoyaleEmitter) ((IMXMLBlockWalker)
> >> getMXMLWalker())
> >> .getASEmitter();
> >> outputName =
> >> fjs.formatPrivateName(sourceDefinition.getParent().getQualifiedName(),
> >> outputName);
> >> }
> >>            writeNewline(ASEmitterTokens.DOUBLE_QUOTE.getToken() +
> >> outputName +
> >>                    ASEmitterTokens.DOUBLE_QUOTE.getToken() +
> >> ASEmitterTokens.COMMA.getToken());
> >>
> >>
> >> #2
> >> further down, comply with the new method signature:
> >> replace:
> >> encodeWatcher(ent.getValue());
> >>
> >> with:
> >> IDefinition childSourceDefinition = (IDefinition) ent.getKey();
> >>                encodeWatcher(ent.getValue(), childSourceDefinition);
> >>
> >>
> >>
> >> And also in
> >> outputBindingInfoAsData method:
> >> comply with the new method signature for encodeWatcher
> >>
> >>  IDefinition sourceDefinition = (IDefinition) entry.getKey();
> >>                encodeWatcher(watcherInfoBase, sourceDefinition);
> >>
> >>
> >> I think that might work for the general case, and maybe it can be
> >> simplified. I only tested quickly and just looked at the output, did not
> >> actually try the resulting app. If this does not work, it might give
> you a
> >> lead.
> >> -Greg
> >>
> >> On Fri, Dec 7, 2018 at 7:58 AM Alex Harui <aha...@adobe.com.invalid>
> >> wrote:
> >>
> >>> Hi Andrew,
> >>>
> >>> Thanks for looking into this.
> >>>
> >>> One of the things to keep in mind about the compiler that isn't
> >>> immediately obvious is that the JS compiler can be thought of almost
> as a
> >>> subclass of the SWF compiler.  It isn't truly that way in the code,
> but the
> >>> way it is now, even if you don't want SWF output, we actually run the
> most
> >>> of the SWF compiler tasks on the source code before generating the JS
> >>> because the transpiler's AST walk (that uses the Emitters to generate
> the
> >>> JS) does not have the smarts for semantic analysis and similar things
> like
> >>> binding and watcher analysis.
> >>>
> >>> The clue to that is which Eclipse projects or jars the various source
> >>> files belong to.  We will try not to introduce any files from the
> >>> compiler-jx project/jar into the compiler and compiler-common
> >>> project/jars.  Doing so could create build order/dependency issues.
> And
> >>> thus, we don't want to access the Emitters from the WatcherAnalyzer,
> nor
> >>> have the WatcherAnalyzer know that it is talking to a RoyaleJSProject
> >>> instead of a RoyaleProject (the latter which is designed for SWF
> output).
> >>>
> >>> And, even if you did find a way to access the Emitter, I think the same
> >>> Watcher database is used for SWF output as well, so you don't always
> want
> >>> to decorate the name of private variables in the data structure.
> >>>
> >>> After a quick think, I would suggest doing a bit more digging.  I
> noticed
> >>> that in the snippet you posted, a getter function appeared to be
> correctly
> >>> generated.  Is that part of the Watcher data or the Binding data?  In
> the
> >>> ActionScript code (DataBindingBase and subclasses) the Binding data is
> >>> supposed to discriminate between "simple" property chains that it can
> >>> create more efficient Bindings for vs GenericBinding that can handle
> more
> >>> complex cases.  The idea is that in some cases, we can't just access
> the
> >>> value by an instance.propName lookup and a getterFunction is generated
> >>> instead.   This is absolutely required in SWF code since external
> classes
> >>> like the Binding classes can't access private members of the class it
> is
> >>> watching.  It has always felt like a "cheat" to me that Binding pokes
> holes
> >>> in the private access protection for Bindings, but that's pretty much
> the
> >>> only way we can do it in SWF code (which also sort of means you lose
> the
> >>> advantage of binding to private variables in the first place).  In
> fact, I
> >>> think one of the optimizations for Royale binding will be that bindings
> >>> will be faster/smaller on public variables than private variables.
> >>>
> >>> So, having said all that, one possible solution is to have the
> >>> ActionScript code use the getter function instead of the propertyName
> for
> >>> private variables.  I thought that the transpiler did not always
> output a
> >>> getter function if public property chains could access the value.  The
> AS
> >>> code could then know to use a function instead of the property name.
> If
> >>> some future version of JS actually does provide private access
> protection
> >>> someday, we'll be glad we did this.  Right now, the Royale JS binding
> code
> >>> has been relying on direct access to private variables, which is also a
> >>> "cheat", IMO.
> >>>
> >>> Another possible approach is to change what is stored in the Watcher
> >>> database.  Add new fields to store the fact that the property is
> private.
> >>> Then in MXMLRoyaleEmitter, the watcher output code should have access
> to an
> >>> emitter, and there is no need to access compiler-jx classes from the
> >>> WatcherAnalyzer.  This approach (just adding more info in the shared
> >>> Analyzer code instead of generating code) is probably more
> >>> platform/output-independent.
> >>>
> >>> Or maybe you'll need both.
> >>>
> >>> Hope that made sense.  Good luck,
> >>> -Alex
> >>>
> >>>
> >>> On 12/6/18, 6:30 AM, "Frost, Andrew" <andrew.fr...@harman.com> wrote:
> >>>
> >>>    Hi all
> >>>
> >>>    I found recently that binding had stopped working when we were using
> >>> private variables, for example:
> >>>      <test:TestComponent id="testing" width="100" height="20"
> >>> boundValue="{_model.value}">
> >>>    where we declare:
> >>>    private var _model : Model = Model.getModel();
> >>>
> >>>    However it works with protected/public variables..
> >>>
> >>>    The reason is clear when you look at the generated _bindings array,
> >>> which contains:
> >>>      function() { return this.test_MainView__model.value; },
> >>>    and then
> >>>      "_model",
> >>>      "valueChange",
> >>>
> >>>    So basically the watcher list is using "_model" whereas the property
> >>> is actually generated as "test_MainView__model".
> >>>
> >>>    Looking at the compiler code, there's a function on the emitter
> which
> >>> does this translation:
> >>>          public String formatPrivateName(String className, String
> name) {
> >>>                return className.replace(".", "_") + "_" + name;
> >>>          }
> >>>
> >>>    However I can't work out how to get the watcher analyser class to
> >>> access the emitter.. I think this is where the logic should go, because
> >>> within "WatcherAnalyzer. analyzeIdentifierNode" we're getting the name
> as a
> >>> string and creating the watcher object based on this string. So I want
> to
> >>> do:
> >>>                name = def.getBaseName();
> >>>                if (def.isPrivate() &&
> >>> project.getAllowPrivateNameConflicts())
> >>>                {
> >>>                      name =
> >>> getEmitter().formatPrivateName(def.getParent().getQualifiedName(),
> name);
> >>>                }
> >>>
> >>>    My issue is that there's no access that I can see to the Emitter.
> >>>
> >>>    So I thought I'd ask:
> >>>
> >>>      1.  does anyone know how I could actually get a valid reference to
> >>> the emitter from this point in the code? i.e. just through the
> >>> JSRoyaleProject object from what I can see..
> >>>      2.  or is there a better place where this should be? e.g. within
> >>> getBaseName itself, or where the base name is set up on the
> definition..?
> >>>      3.  or could we move the "formatPrivateName" method to somewhere
> >>> more accessible?
> >>>      4.  or can I just reproduce the "formatPrivateName" functionality
> >>> here, and add comments so that future maintainers know to update two
> >>> locations in case this changes?
> >>>
> >>>    The last option is simplest but very hacky.. but would appreciate
> >>> thoughts on the best approach.
> >>>
> >>>
> >>>    thanks
> >>>
> >>>       Andrew
> >>>
> >>>
> >>>
> >>>
> >>>
> >>>
>
>

Reply via email to