I don't know where I got 'overally' from. I think I started that one with generally and got halfway through changing it. :)
On Wed, Nov 6, 2019 at 1:07 PM Greg Dove <[email protected]> wrote: > Yeah, that's pretty much what I meant. And the issue you expressed is a > more detailed analysis of what I was anticipating as the main issue with > this approach. The split out of private statics was not something that I > thought about, but overally it could still be a viable option - at least > worth a bit more investigation, but definitely not something urgent at this > point. > I actually just tried the following static init code: > > private static var i:uint; > > { > for (i=0;i<10;i++) { > trace('static init block testing '+i); > } > } > > You should simply be able to paste that into pretty much any class that > does not have a static var i already defined. > It is a very rare pattern and probably rightly so (I have used it for some > things in the past, but it was never a 'goto' option), but it is valid in > as3 and does allow for some one-off processing on first class access. I had > forgotten some of the 'rules' inside the code block, it seems that > declaring local vars is not an option, so you can't use 'for (var i:uint=0; > ...' above. I am pretty sure I 'learnt' that on previous occasions too. > For Royale, this works the same for swf as it did for legacy flex compiler > and you get the trace output. At the moment the code in the static init > above is not generated at all for js. But like I said, this does not seem > high priority! > > > > On Wed, Nov 6, 2019 at 12:10 PM Alex Harui <[email protected]> > wrote: > >> I won't be doing any more work in this area unless the lack of >> minification of private statics becomes a major issue for a user. Or if >> there is a bug in the just-committed implementation. >> >> I think I now understand what you are proposing. That's really good >> thinking, however, I'm not sure it would work for minified code as statics >> are essentially removed from the class and turned into a global var. IOW: >> >> package org.apache.royale.events { >> public class MouseEvent { >> private static somePrivateStatic = <some expression> >> } >> } >> >> Gets transpiled to: >> >> org.apache.royale.events.MouseEvent = function() {} >> org.apache.royale.events.MouseEvent.somePrivateStatic = <some expression> >> >> which gets minified to something like >> >> pv = function() {} >> exportSymbol(pv, " org.apache.royale.events.MouseEvent"); >> pu = <some expression> >> >> so there isn't always a package tree of objects to hook and add a getter >> to, and there could be direct access to "pu" before any access to >> org.apache.royale.events.MouseEvent or even "pv". >> >> Of course, I could be wrong... >> -Alex >> >> >> On 11/5/19, 2:51 PM, "Greg Dove" <[email protected]> wrote: >> >> Suggestions for better terminology and acronyms are welcome, although >> I >> don't think I agree on what is "optimized compiler output". >> >> All I was trying to say is that I think we over-use the term 'PAYG' >> for >> things outside its specific and unique (for Royale) meaning. As far >> as I >> can see, this topic is focused on getting emulation of something to >> work >> right at the language level, and then making sure it is optimized (in >> some >> way - the common tradeoff between performance and size). That is >> pretty >> general and easily understood and does not need a new name or >> acronym, imo. >> I think about it in terms of how easy it would be for someone new to >> read >> this thread and how much they could understand it. Anyway, I just >> wanted to >> point that out as I have thought about doing so on other occasions >> and did >> not, but I have no intention of pursuing it further as a topic. >> >> >> "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." >> I know it is available 'outside'. I was thinking more in terms of >> injecting >> the renamed name into the code somehow, but even if it were possible >> I am >> not sure it would make sense, because it would mean code that would >> rely on >> something that would only ever work with GCC. I presume that there is >> no >> way to add this into GCC/GCL in such a way that the javascript would >> work >> the same in other minifiers. This was more of a pipe dream, I could >> have >> used something like this to do variables reflection differently, for >> example, but I'm happy with what we have now, which I think will >> support >> other future targets. >> >> "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. " >> I thought about it the same way, until reviewing both Harbs and your >> earlier examples in this thread. >> A javascript class itself is basically a static access of a value on >> its >> package chain. >> My point was to consider make the class itself a getter for first >> access in >> the same way you are proposing for its static members. >> >> org.apache.royale.MyClass <- 'MyClass' could a js getter for first >> access >> if the class has static init code it needs to run. >> >> The initialization code could then run in the getter for the class and >> replace itself on 'org.apache.royale' as a 'value' similar to what >> you are >> proposing for its static members. That is the trick to how it might >> be a >> way to replicate (sort of) what SWF does in js, I think, without doing >> something complicated at compile time. >> >> The one issue I can think of is that while it is exported with the >> full >> package path, there is also a minified reference. That means it might >> need >> to reassign to both its exported package name (for the 'export' >> consistency) and its own original package name reference (which should >> support the minified version) in the part of the accessor which does >> the >> reassignment back to a simple value. >> >> If you don't have time to look into this, I can explore it at some >> point. >> >> >> >> On Wed, Nov 6, 2019 at 10:52 AM Alex Harui <[email protected]> >> wrote: >> >> > 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 >> > > >>>> >> > > >>> >> > > >>> >> > > >> >> > > >> >> > > > >> > > > >> > > > >> > > >> > > >> > >> > >> > >> >> >>
