Suggestions for better terminology and acronyms are welcome, although I don't 
think I agree on what is "optimized compiler output".

You are correct that private statics won't be minified as well as they used to, 
but switching to getters solved a lot of other problems so I'm pushing these 
changes for now and we can try to do better for private statics later if it 
turns out there are lots of them.  There is code in the commit that tries to 
determine if the initialization expression references external dependencies.  
That code could get smarter and further reduce the number of private statics 
that get converted to getter/setter.  In a quick search of the framework code, 
there are only a few static vars that reference other classes.  Also, it is my 
understanding that the defineProperties call where the variable/constant name 
is a key in the structure passed into defineProperties is what prevents 
renaming, not the string passed into defineProperty.

My main concern about static code blocks is how well GCC handles them.

I'm not sure what you mean by "string name for a renamed member", but if you 
look at the modules examples they output the renaming map so the module can use 
the same renaming.

Flash runs class verification and class initialization in the runtime's 
verifier at the first use of a class.  I have no idea how to replicate that in 
JS.  IOW, in JS, I don't know what line of code is going to be the first 
reference to a class.

And if it really does become a problem, we might be able to do what GCC does 
and rename the private static ourselves since we know the only places that 
reference it are in the class we are compiling.

My 2 cents,
-Alex

On 11/5/19, 11:34 AM, "Greg Dove" <[email protected]> wrote:

    Side comment: I actually prefer to limit the way I think of 'PAYG' as
    enabling options for the user to compose incremental pieces of
    functionality together, instead of using it to describe 'anything' that
    represents optimized compiler output. For me, PAYG is something that users
    actively 'do'.  The more I talk to new people about Royale the more it
    becomes apparent that a lot of the terms and concepts are confusing, which
    is the only reason I am mentioning this. To me this is just finding ways to
    make compatible output that is optimized (presumably because GCC can't
    optimize it itself).
    
    
    The approach described works well for public static const
    
    For static vars, or for private static consts, using the string value to
    redefine the property does mean that the var name can now no longer be
    minimified in these cases I think. That would be a small price to pay if it
    now works. I have looked in GCC/goog a few times to see if there is any way
    to get the string name for a renamed member, but I could not find anything
    (so far).
    The only way to keep things as they are there that I can think of is to
    swap the private static consts for vars (so they can be undefined at class
    definition) and initialize them all in a static code block. That could
    perhaps be achieved using something very similar to what you described at
    the class level if the class was determined to need it - the first
    reference to the class would run the getter for the class reference itself,
    which would run static init code and then replace itself with the original
    class reference. That would essentially make it possible to match the way
    swf does it. Whether that plays nice with GCC or not I don't know.
    I have not actually tried to use explicit static code blocks in Royale yet
    (I did not expect them to work, but perhaps they do already), and only used
    them rarely in as3 in the past in general. If these don't currently work
    then the same approach would allow us to do that. Things like:
    
    
    class Test {
    
      public static const myConstArray:Array = [new OtherClass(),new
    OtherClass(), new OtherClass()];
    
      {
          //explicit static init code
          for each(var other:OtherClass in myConstArray)
          {
              trace(other.toString());
          }
      }
    
      //normal stuff
    
    }
    
    I think it might even be possible in normal as3 to have multiple static
    code blocks like that. So running that code from inside a 'class' getter
    could perhaps solve that problem as well in a similar way. If that is being
    done though, it might as well initialize all the values. I think the
    argument about lazy initialization for the individual items could be offset
    by avoiding extra code to support each individual lazy initialization as
    well, and in some cases also mean that minification is maintained.
    
    
    
    On Wed, Nov 6, 2019 at 7:06 AM Harbs <[email protected]> wrote:
    
    > Makes sense to me.
    >
    > > On Nov 5, 2019, at 7:41 PM, Alex Harui <[email protected]> wrote:
    > >
    > > FWIW, here is the pattern that appears to work in JSFiddle for a "static
    > var foo":
    > >
    > > o.get__foo = function() {
    > >   var value = <initializer expression>
    > >   Object.defineProperty(o, 'foo', {value : value, writable: true});
    > >   return value;
    > > }
    > > o.set__foo = function(value) {
    > >    Object.defineProperty(o, 'foo', {value : value, writable: true});
    > > }
    > > Object.defineProperties(o, { foo: { get: o.get__foo,set: o.set__foo,
    > configurable: true}})
    > >
    > > We have to use Object.defineProperties in order to use an @lends JSDoc
    > annotation (not shown) for the minifier.
    > >
    > > A similar pattern will be used for "static const foo":
    > >
    > > o.get__foo = function() {
    > >   var value = <initializer expression>
    > >   Object.defineProperty(o, 'foo', {value : value, writable: false});
    > >   return value;
    > > }
    > > Object.defineProperties(o, { foo: { get: o.get__foo, configurable:
    > true}})
    > >
    > > Of course, I could be wrong...
    > >
    > > -Alex
    > >
    > > On 11/5/19, 8:56 AM, "Harbs" <[email protected]> wrote:
    > >
    > >    Good point on PAYG.
    > >
    > >    If we use #2 with one-time lazy evaluation, I think that’s the best
    > of both worlds.
    > >
    > >    Thanks,
    > >    Harbs
    > >
    > >> On Nov 5, 2019, at 6:44 PM, Alex Harui <[email protected]>
    > wrote:
    > >>
    > >> Yeah, in my local branch I'm playing with various ways to not run the
    > initializer more than once.  We can tweak the pattern later.  It involves
    > re-defining the property, but isn't  quite the patterns offered below.
    > >>
    > >> IMO, #2 is more PAYG than #1.  In #1, all initializers run regardless
    > of whether your code uses that value or not.  In #2, the initializers run
    > on demand, which is actually somewhat more like the Flash runtime.  AIUI,
    > Flash does not run a class's static initializers until the class is about
    > to be accessed by code.  All initializers for a class then run, but if 
your
    > code never gets to the point where the verifier needs to verify the class,
    > the initializers are not run.
    > >>
    > >> -Alex
    > >>
    > >> On 11/4/19, 11:49 PM, "Greg Dove" <[email protected]> wrote:
    > >>
    > >>   Yeah, in all cases where I had to do this manually I used a private
    > static
    > >>   backing var and populated it on first request similar to what is
    > typically
    > >>   done for singleton-like get accessors. Otherwise it's not really safe
    > >>   compared to the original (and as you say, could have performance
    > issues
    > >>   too).
    > >>
    > >>   On Tue, 5 Nov 2019, 20:31 Harbs, <[email protected]> wrote:
    > >>
    > >>> It seems to me that the getter approach can have an impact on
    > performance.
    > >>> With approach #1, the static consts will only be evaluated once, while
    > with
    > >>> #2, it will be evaluated every time it’s accessed.
    > >>>
    > >>> Maybe we could use a hybrid approach where “bar” is redefined as the
    > >>> evaluated value the first time it’s accessed.
    > >>>
    > >>> Something like this:
    > >>>
    > >>> Foo.get__bar = function() {
    > >>> var val = ResourceManager.getInstance().getString("baz");
    > >>> delete Foo.bar;
    > >>> Foo.bar = val;
    > >>> return val;
    > >>> Object.defineProperty(Foo, "bar", {get: Foo.get__bar});
    > >>>
    > >>> or maybe this:
    > >>>
    > >>> Foo.get__bar = function() {
    > >>> var val = ResourceManager.getInstance().getString("baz");
    > >>> // is delete needed?
    > >>> delete Foo.bar;
    > >>> Object.defineProperty(Foo, "bar", {get: function(){return val}});
    > >>> return val;
    > >>> }
    > >>> Object.defineProperty(Foo, "bar", {get: Foo.get__bar});
    > >>>
    > >>>
    > >>> Harbs
    > >>>
    > >>>> On Nov 5, 2019, at 2:52 AM, Alex Harui <[email protected]>
    > wrote:
    > >>>>
    > >>>> Hi,
    > >>>>
    > >>>> The issue of complex static initializers and dependency order keeps
    > >>> coming up.  In reviewing the past discussions, there were a couple of
    > >>> suggestions:
    > >>>> 1) separate static initializers into a block of code that runs after
    > the
    > >>> class is defined
    > >>>> 2) use getters
    > >>>>
    > >>>> I'm going to try #2.  I'm not convinced #1 will work well with
    > minifiers
    > >>> or help us get the dependency order right.
    > >>>>
    > >>>> Thoughts?  Is there a case where getters won't work?
    > >>>>
    > >>>> For:
    > >>>>
    > >>>> public class Foo {
    > >>>> public static const bar:String =
    > >>> ResourceManager.getInstance().getString("baz");
    > >>>> }
    > >>>>
    > >>>> We currently generate:
    > >>>>
    > >>>> Foo.bar = ResourceManager.getInstance().getString("baz");
    > >>>>
    > >>>> And lots of other code tries to understand that the
    > >>> goog.require("ResourceManager") is more important than other
    > goog.requires
    > >>> in the remove-circulars dependency calculation.
    > >>>>
    > >>>> But if we generate:
    > >>>> Foo.get__bar = function() { return
    > >>> ResourceManager.getInstance().getString("baz");};
    > >>>> Object.defineProperty(Foo, "bar", {get: Foo.get__bar});
    > >>>>
    > >>>> Then I think no statics will get evaluated at load time.
    > >>>>
    > >>>> Of course, I could be wrong...
    > >>>> -Alex
    > >>>>
    > >>>
    > >>>
    > >>
    > >>
    > >
    > >
    > >
    >
    >
    

Reply via email to