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 > >>>> > >>> > >>> > >> > >> > > > > > > > >
