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 <[email protected]> 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 <[email protected]> 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 <[email protected]>
>> 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" <[email protected]> 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