Update: Inspired by Erik’s suggestion to use @expose, I found that I can
use @expose on the structure keys instead of having to create more
prototype slots. So the pattern now is:
Object.defineProperties(org_apache_flex_utils_BinaryData.prototype, {
/** @expose */
productService: {
/** @this {org_apache_flex_utils_BinaryData} */
get: function() {
return this.productService_;
},
/** @this {org_apache_flex_utils_BinaryData} */
set: function(value) {
this.productService_ = value + 10;
}
}
});
Adding @expose was a simple enough change that I was able to implement it
in a few hours. A few more fixes later and the release version is up and
running!
Google has deprecated @expose so this solution may stop working some day.
I took a quick look at what the Closure Compiler does with @expose. It
looks like it replaces all dot.path syntax with obj[‘prop’] syntax so
other passes simply don’t rename the string literal. If @expose goes
away, we might need to change FalconJX to do the same thing: replace
dot.path with obj[‘prop]. We currently don’t visit all of the
hand-written JS source we write, but we might some day for another related
reason: right now we don’t want renaming of variables used in binding
expressions, and we don’t have a way to support renaming of variables with
MXML ids. If FlexJS apps turn out to be heavy with strings, we might
consider making FalconJX smarter and have it inject the @expose tags for
only the strings involved in binding expressions. Then if we’re visiting
all of the source to do that, we could later implement @expose directly if
it goes away.
Anyway, I hope to check the defineProperties change in as soon as I can
adjust the tests and merge the branch. Thanks again to Erik for his
advice.
-Alex
On 4/6/15, 3:14 PM, "Alex Harui" <[email protected]> wrote:
>Hi Erik,
>
>Well, this renaming issue is coming from an actual scenario that runs
>correctly when not minified. I think what you are showing is that the
>code-flow analyzer contributes to the renaming logic. In this actual test
>case, someFunction is called from an event handler, so maybe the renaming
>logic can’t follow the code-flow in those situations, especially because
>lots of things are set up via the MXML data structure.
>
>However, if we can just prevent renaming, I think that will also work.
>Having to define both a dummy prototype slot with @expose as well as the
>defineProperties seems redundant to me, but I think that’s the route to
>take, so thanks for finding that. I’ll see if I can get to the finish
>line with that.
>
>One more question: Defining a slot without a value generates warnings
>from GCC when called from FalconJX. IOW, adding this:
>
> /**
> * @expose
> */
> org_apache_flex_utils_BinaryData.prototype.productService;
>
>Will result in:
>
>
> WARNING - Suspicious code. The result of the 'getprop' operator is not
>being used.
>
>
>I’m not sure why we get this warning in FalconJX but not in the GCC
>Service UI or from the GCC command line. And also @expose is deprecated.
>But if you’re ok with using @expose and finding a way to shut off those
>warnings, I’ll go with that.
>
>Thanks for the help,
>-Alex
>
>On 4/6/15, 2:33 PM, "Erik de Bruin" <[email protected]> wrote:
>
>>Alex,
>>
>>I think what you're seeing is an artifact of the way you've set up
>>your example... You don't instantiate the object and never reference
>>the property outside of the class' internals. WIth such a minimal
>>case, that basically doesn't execute, the compiler thinks it can be
>>smart and 'optimize' away vital parts of the code... If I rework your
>>example a bit to make it feel more 'real world' to the compiler:
>>
>>
>>
>>/**
>> * @constructor
>> */
>>var org_apache_flex_utils_BinaryData = function () {
>>
>> /**
>> * @private {number}
>> */
>> this.productService_;
>>
>>}
>>
>>org_apache_flex_utils_BinaryData.prototype.someFunction = function() {
>> console.log(this.productService);
>>};
>>
>>Object.defineProperties(org_apache_flex_utils_BinaryData.prototype, {
>> productService: {
>> /** @this {org_apache_flex_utils_BinaryData} */
>> get: function() {
>> return this.productService_;
>> },
>> /** @this {org_apache_flex_utils_BinaryData} */
>> set: function(value) {
>> this.productService_ = value + 10;
>> }
>> }
>>});
>>
>>var binaryData = new org_apache_flex_utils_BinaryData();
>>
>>binaryData.productService = 100;
>>
>>binaryData.someFunction();
>>
>>
>>
>>... You get, without errors or warnings:
>>
>>
>>
>>'use strict';function
>>a(){}Object.defineProperties(a.prototype,{a:{get:function(){return
>>this.b},set:function(c){this.b=c+10}}});var b=new
>>a;b.a=100;console.log(b.a);
>>
>>
>>
>>This code does actually execute and it gives the expected 110, showing
>>the setter is called and the 'defineProperties' is not simply ignored.
>>You see the property is renamed to the same string 'everywhere', so
>>the compiler knows what it is and how to handle it.
>>
>>In this example you can prevent the renaming by declaring the property
>>with an @expose annotation on the object's prototype just before
>>calling 'Object.defineProperties':
>>
>>
>>
>>/**
>> * @expose
>> */
>>org_apache_flex_utils_BinaryData.prototype.productService;
>>
>>
>>
>>Which, combined, gives a compiled output:
>>
>>
>>
>>'use strict';function
>>a(){}Object.defineProperties(a.prototype,{productService:{get:function(){
>>r
>>eturn
>>this.a},set:function(c){this.a=c+10}}});var b=new
>>a;b.productService=100;console.log(b.productService);
>>
>>
>>
>>Isn't that what you're looking for?
>>
>>EdB
>>
>>
>>
>>--
>>Ix Multimedia Software
>>
>>Jan Luykenstraat 27
>>3521 VB Utrecht
>>
>>T. 06-51952295
>>I. www.ixsoftware.nl
>