Thanks, I will definitely come back to this as a reference when I look at that.
On Wed, Nov 6, 2019 at 1:38 PM Alex Harui <[email protected]> wrote: > I noticed and wondered if it was dialect. __ > > Just to try to dump related information into this thread so it is all here > if you do get back to it: > > In a Royale class's JS file, we used to set up the Object.definePropertles > like this: > > public class A { > private var _foo:int = 0; > public function get foo():int { return _foo } > } > > Would be transpiled to: > > A.prototype._foo = 0; > Object.defineProperties(A.prototype, { foo : get: function() { return > this._foo }}); > > This worked in js-debug but when transpiled, GCC would give the two _foo > different names, maybe like: > > A.prototype.a = 0; // 'a' > Object.defineProperties(A.prototype, { foo : get: function() { return > this.b }}); // 'b' > > And this would not work. GCC didn't think that the code in the > Object.defineProperties structure was associated with the class A so it > would use a different renaming scheme. > For that and some other reasons we currently generate all method bodies in > the class pattern: > > A.prototype._foo = 0; > A.prototype.get__foo = function() { return this._foo }; > Object.defineProperties(A.prototype, { foo : get: A.prototype.get_foo }}); > > So when I say I have concerns about GCC and static init code, the concern > is that GCC will not know that the static init code is referencing certain > things in the class code. But that might all work out as there is no > 'this' in static init code. > > -Alex > > On 11/5/19, 4:15 PM, "Greg Dove" <[email protected]> wrote: > > 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 > >> > > >>>> > >> > > >>> > >> > > >>> > >> > > >> > >> > > >> > >> > > > > >> > > > > >> > > > > >> > > > >> > > > >> > > >> > > >> > > >> > >> > >> > > >
