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