You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@flex.apache.org by Alex Harui <ah...@adobe.com> on 2016/01/07 22:55:13 UTC

[FALCONJX][FLEXJS] "as" keyword handling

How many of you use the "as" keyword as part of a test?  IOW things like:

 var foo:SomeType = someVar as SomeType;
 if (foo == null)

IMO, I have yet to use "as" in this way in the FlexJS framework. I just
use it to make the compiler happy.  IOW things like:

 var foo:SomeType = someVar as SomeType;
 foo.someProp

If foo really isn't of SomeType, I am going to get an NPE, but I know it
will never be null, I am just casting/coercing so the compiler will check
that someProp really exists on SomeType.

The reason I'm asking is because the use of "as" as become a negative
factor in several cases:
1) In JS, it results in a function call
2) As Om noted yesterday, it doesn't work for Native JS types
3) It causes unnecessary class dependencies which complicates the
goog.requires list

Currently there is an @flexjsignorecoercion hack you can use to tell
FalconJX to skip code-generation for an "as" operation.  However, we are
adding more and more of these, and they are more frequently the cause of
something not working, so I am thinking about flipping the logic and not
generating code for any "as" operation unless you specifically ask for it
via @flexjsgeneratecoercion or something like that.

Thoughts?
-Alex


Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Alex Harui <ah...@adobe.com>.

On 1/8/16, 11:03 AM, "Andy Dufilie" <an...@gmail.com> wrote:

>On Fri, Jan 8, 2016 at 12:53 PM, Alex Harui <ah...@adobe.com> wrote:
>
>>
>> On 1/8/16, 7:23 AM, "Andy Dufilie" <an...@gmail.com> wrote:
>>
>> >In all above cases, if Foo is a primitive type, function-style casting
>>can
>> >never be optimized out because Foo(x) will actually change the type of
>>x.
>> >For example, String(x) will convert null to the String "null".
>>
>> Well, IMO, it isn't always NO.  Sometimes you can optimize that code
>>away.
>>  It isn't "never".  Currently, FalconJX does know if you are using
>> function-style casting to primitives and won't optimize that away.
>
>
>Does it know if this code is using primitive casting or not?
>var type:Class = String;
>var y = type(x);
>
>And what I'm playing with now for function-style casting won't optimize it
>> away if it finds a try/catch around it.
>>
>
>But that won't work if the try/catch is in function A that calls function
>B
>which has the function-style cast.

For sure, there are scenarios it won't handle, which is why I'm looking at
directives that allow you to override what the compiler will do.  I'm
trying to get a sense for how often folks code this way.  For me it is
rare to catch type errors in outer function thrown from an inner.
Although I definitely do that for file read/write errors.

>
>You were just complaining about how much code massaging you have to do.
>>
>
>I'm happy with the current situation where it preserves the behavior of
>the
>explicit type casting code and I recommend not changing it. Speed
>optimizations will always require code massaging. If you're referring to
>automatic casts for typed variables and parameters, I can live with that
>because I know if the compiler added those casts everywhere that the
>performance hit would likely be too much, but I wouldn't be opposed to
>adding that automatic casting with an option to enable or disable it.

IMO, speed optimizations can also come via code hinting instead of
massaging, which is what these directives intend to do.

>
>
>> We've heard similar feedback from others, so my first instinct is to
>>find
>> a way to give you control over your code output with less massaging.
>>This
>> new syntax would still require massaging.
>
>
>Adding new syntax does not *require* massaging to existing code, because
>you don't *have* to update your code to use the new syntax.  It should be
>looked at as an optional speed optimization for those that are
>performance-conscious.  If you change the behavior of existing syntax,
>then
>that does require massaging.

True, depending on the practical definition of "require".  If the default
result is going to have performance problems then you have essentially
forced everyone to massage their code and then we lose the
lower-cost-of-migration advantage that I think we want to keep.

>
>
>> The @flexjsignorecoercion (or
>> now @flexjsemitcoercion) is a function-level directive.  We could add
>> project-level, file-level and/or line-level directives if that is easier
>> than massaging the code.
>>
>
>If you insist on making the compiler misbehave by default, then a
>project-level setting to bring it back to the correct behavior is
>absolutely necessary. I'd rather not have to add a directive to every
>single function just to prevent the compiler from mangling the code.  If I
>write an explicit cast, I expect the compiler to respect that rather than
>act like it knows better.
>
>
>> IMO, an optimizing compiler would be smart enough to know when to remove
>> the Language.as calls.  All I'm trying to provide is some smarts in the
>> compiler to do that optimization and some directives to help if we get
>>it
>> wrong.
>>
>
>I believe risky automatic optimizations should enabled or disabled through
>a flag passed to the build command.  The default behavior of the compiler
>should be to preserve the behavior of the code. Extra directives should
>not
>be required to let the compiler know that you actually mean what you typed
>if what you typed is valid code.  Why should we have to tell it twice
>everywhere? ("Hey compiler, do this.  No, seriously, I really want you to
>do what I just asked you to do.")
>
>
>> If you still want to add a new language feature, (x:Foo) is valid
>>pattern
>> in a function parameter list, so I don't know if the compiler would give
>> you trouble implementing it.  Another option might be another keyword
>>like
>> "as" (maybe "_as_").
>>
>
>I'm feeling the pain of the performance hit, but I am opposed to breaking
>language features by default, so I would like to explore different
>options.
>I think (x:Foo) is doable.
>

Of course it is doable.  But we have to be concerned about its impact on
the greater eco-system of IDEs.

>
>
>> I think I will put the circularity scan as a compiler option for folks
>>who
>> still need it.
>>
>
>I think it's a good idea to disable the scan by default because the error
>messages actually help you write better code, which is the job of
>compilers
>and IDEs.  It still needs to be an option to support existing codebases.

I will spend some time putting more options and directives around this
optimization so you can easily get what you want and what I think I want.

Thanks for your input,
-Alex


Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Michael Schmalle <te...@gmail.com>.
In the Randori compiler, I wrote the emitter to strip the cast during the
emit stage.

Mike

On Fri, Jan 8, 2016 at 2:38 PM, Josh Tynjala <jo...@gmail.com> wrote:

> I wonder if we could define some kind of special global function that would
> make the compiler and IDEs happy with assignments that would normally
> require casting, but the JS emitter could strip out the function call and
> assign directly. We could take advantage of the fact that the * type can be
> assigned to anything without a cast:
>
> // Example "Implementation"
>
> function __assign(value:*):*
> {
>     return value;
> }
>
> // ActionScript Usage
>
> var before:SuperClass = new SubClass();
> var after:SubClass = __assign(before);
>
> // JS Output:
>
> var before = new SubClass();
> var after = before;
>
> As you can see, it becomes a simple assignment in JS, without the function
> call overhead.
>
> Obviously, if someone can come up with a better name than __assign(),
> that's cool. Just something off the top of my head.
>
> It's worth noting that TypeScript casting does not have a runtime fail
> state. It's just there to make the compiler happy too. If the types in a
> cast aren't compatible at runtime, the code just continues running without
> error until the incompatibility surfaces elsewhere. This would have a
> similar effect.
>
> - Josh
>
>
> On Fri, Jan 8, 2016 at 11:03 AM, Andy Dufilie <an...@gmail.com>
> wrote:
>
> > On Fri, Jan 8, 2016 at 12:53 PM, Alex Harui <ah...@adobe.com> wrote:
> >
> > >
> > > On 1/8/16, 7:23 AM, "Andy Dufilie" <an...@gmail.com> wrote:
> > >
> > > >In all above cases, if Foo is a primitive type, function-style casting
> > can
> > > >never be optimized out because Foo(x) will actually change the type of
> > x.
> > > >For example, String(x) will convert null to the String "null".
> > >
> > > Well, IMO, it isn't always NO.  Sometimes you can optimize that code
> > away.
> > >  It isn't "never".  Currently, FalconJX does know if you are using
> > > function-style casting to primitives and won't optimize that away.
> >
> >
> > Does it know if this code is using primitive casting or not?
> > var type:Class = String;
> > var y = type(x);
> >
> > And what I'm playing with now for function-style casting won't optimize
> it
> > > away if it finds a try/catch around it.
> > >
> >
> > But that won't work if the try/catch is in function A that calls
> function B
> > which has the function-style cast.
> >
> > You were just complaining about how much code massaging you have to do.
> > >
> >
> > I'm happy with the current situation where it preserves the behavior of
> the
> > explicit type casting code and I recommend not changing it. Speed
> > optimizations will always require code massaging. If you're referring to
> > automatic casts for typed variables and parameters, I can live with that
> > because I know if the compiler added those casts everywhere that the
> > performance hit would likely be too much, but I wouldn't be opposed to
> > adding that automatic casting with an option to enable or disable it.
> >
> >
> > > We've heard similar feedback from others, so my first instinct is to
> find
> > > a way to give you control over your code output with less massaging.
> > This
> > > new syntax would still require massaging.
> >
> >
> > Adding new syntax does not *require* massaging to existing code, because
> > you don't *have* to update your code to use the new syntax.  It should be
> > looked at as an optional speed optimization for those that are
> > performance-conscious.  If you change the behavior of existing syntax,
> then
> > that does require massaging.
> >
> >
> > > The @flexjsignorecoercion (or
> > > now @flexjsemitcoercion) is a function-level directive.  We could add
> > > project-level, file-level and/or line-level directives if that is
> easier
> > > than massaging the code.
> > >
> >
> > If you insist on making the compiler misbehave by default, then a
> > project-level setting to bring it back to the correct behavior is
> > absolutely necessary. I'd rather not have to add a directive to every
> > single function just to prevent the compiler from mangling the code.  If
> I
> > write an explicit cast, I expect the compiler to respect that rather than
> > act like it knows better.
> >
> >
> > > IMO, an optimizing compiler would be smart enough to know when to
> remove
> > > the Language.as calls.  All I'm trying to provide is some smarts in the
> > > compiler to do that optimization and some directives to help if we get
> it
> > > wrong.
> > >
> >
> > I believe risky automatic optimizations should enabled or disabled
> through
> > a flag passed to the build command.  The default behavior of the compiler
> > should be to preserve the behavior of the code. Extra directives should
> not
> > be required to let the compiler know that you actually mean what you
> typed
> > if what you typed is valid code.  Why should we have to tell it twice
> > everywhere? ("Hey compiler, do this.  No, seriously, I really want you to
> > do what I just asked you to do.")
> >
> >
> > > If you still want to add a new language feature, (x:Foo) is valid
> pattern
> > > in a function parameter list, so I don't know if the compiler would
> give
> > > you trouble implementing it.  Another option might be another keyword
> > like
> > > "as" (maybe "_as_").
> > >
> >
> > I'm feeling the pain of the performance hit, but I am opposed to breaking
> > language features by default, so I would like to explore different
> options.
> > I think (x:Foo) is doable.
> >
> >
> >
> > > I think I will put the circularity scan as a compiler option for folks
> > who
> > > still need it.
> > >
> >
> > I think it's a good idea to disable the scan by default because the error
> > messages actually help you write better code, which is the job of
> compilers
> > and IDEs.  It still needs to be an option to support existing codebases.
> >
>

Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Alex Harui <ah...@adobe.com>.
OK, I have pushed changes so that all mucking with the output is
controlled by compiler flags.  They are:

-remove-circulars
-js-output-optimization=<optimization strategy>

None of these options are on by default, so you may start seeing errors
when compiling your app and need to add one or more of these options
because what -remove-circulars did was on by default before this commit.

The -remove-circulars options scans the goog.require lines in every .JS
file in the app and starting with the main app, chases down the tree of
class dependencies and removes goog.requires that have already been seen
in order to prevent Google Closure Compiler from seeing a circular
dependency.

I have implemented two optimization strategies:
-js-output-optimization=skipAsCoercions does not generate Language.as
calls where it sees the "as" keyword used in casting/coercion.  You can
also control Language.as calls with special asdoc tags
"@flexjsignorecoercion <fully-qualified class name>"
-js-output-optimization=skipFunctionCoercions does not generate
Language.as calls for uses of "function" coercions if it finds the no
try-catch blocks in the function surrounding the code.

Interestingly, this means that we can implement other strategies as well
and let folks choose.  I pondered whether to implement a strategy called
"SkipAsAfterIs" that would skip the Language.as call if it found the "as"
was immediately preceded by an "is" check.  Or another strategy called
"skipAsUnlessAssignment" that would skip the Language.as call if it found
the "as" was used outside an assignment expression such as (foo as
Bar).someProperty.

I have updated the examples to use some of these flags since they would
otherwise report circular dependency errors.

I'm now going start on the folder renaming and other refactoring to get a
more Maven-friendly folder structure in the flex-asjs repo.

-Alex

On 1/8/16, 11:52 PM, "Alex Harui" <ah...@adobe.com> wrote:

>
>
>On 1/8/16, 11:39 PM, "jude" <fl...@gmail.com> wrote:
>
>>I would expect it to keep the same behavior and take a performance hit in
>>exchange. You can always add the option to "speed up" the JS version by
>>removing any of the casting methods. Have you tested the difference with
>>it
>>and without it in JS?
>
>I haven't, but it is not always a cheap function call.
>
>>
>>
>>*"...but the Google Closure Compiler implies that you should have
>>goog.require statements for all dependencies in an output file, and then
>>complains about circular dependencies if you do."*
>>It seems like the problem is with the Google Closure Compiler. That
>>sounds
>>broken to me.
>
>Google is insisting that you should use interfaces and not have classes
>depend on other classes.  So they will say it isn't broken.  I've just
>about finished putting all of these options into compiler options.  None
>of them will be on by default so you will all get to see where Google
>thinks you have circularities.
>
>What the defaults are when we release will depend on customer feedback.
>
>-Alex
>


Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Alex Harui <ah...@adobe.com>.

On 1/8/16, 11:39 PM, "jude" <fl...@gmail.com> wrote:

>I would expect it to keep the same behavior and take a performance hit in
>exchange. You can always add the option to "speed up" the JS version by
>removing any of the casting methods. Have you tested the difference with
>it
>and without it in JS?

I haven't, but it is not always a cheap function call.

>
>
>*"...but the Google Closure Compiler implies that you should have
>goog.require statements for all dependencies in an output file, and then
>complains about circular dependencies if you do."*
>It seems like the problem is with the Google Closure Compiler. That sounds
>broken to me.

Google is insisting that you should use interfaces and not have classes
depend on other classes.  So they will say it isn't broken.  I've just
about finished putting all of these options into compiler options.  None
of them will be on by default so you will all get to see where Google
thinks you have circularities.

What the defaults are when we release will depend on customer feedback.

-Alex


Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by jude <fl...@gmail.com>.
I would expect it to keep the same behavior and take a performance hit in
exchange. You can always add the option to "speed up" the JS version by
removing any of the casting methods. Have you tested the difference with it
and without it in JS?


*"...but the Google Closure Compiler implies that you should have
goog.require statements for all dependencies in an output file, and then
complains about circular dependencies if you do."*
It seems like the problem is with the Google Closure Compiler. That sounds
broken to me.

On Fri, Jan 8, 2016 at 12:42 PM, Andy Dufilie <an...@gmail.com>
wrote:

> I understand what you're trying to do, and I want the same things.  The
> greatest thing about FlexJS is that I am able to easily port my large
> project (seven years of development work) with minimal change.  However,
> since my project relies heavily on the exact behavior of every AS language
> feature, I need it to behave exactly the same after cross-compiling, or I
> end up having to do painful runtime debugging of the JS output to find out
> where the cross-compiler changed the behavior of my code.  I'm willing to
> take a performance hit if it means I can get things up and running sooner,
> knowing that I can always go back and optimize the code later and/or play
> with the optimization settings.  I understand that if you make it easy to
> put it back to the default behavior that it's not so bad, but keep in mind
> that new users will expect things to "just work" and may not know about the
> the compiler options or directives.
>
> On Fri, Jan 8, 2016 at 3:20 PM, Alex Harui <ah...@adobe.com> wrote:
>
> >
> >
> > On 1/8/16, 12:11 PM, "Josh Tynjala" <jo...@gmail.com> wrote:
> >
> > >I should add that I strongly agree with Andy that we shouldn't change
> the
> > >default behavior of the existing forms of casting. That's why I made the
> > >above proposal for a special function that the emitter would know to
> strip
> > >away. It would allow us preserve the existing casting behavior, while
> > >providing a separate option that simply makes the compiler and IDEs
> happy.
> > >It's something additional to learn instead of discovering that what you
> > >already learned is now completely wrong. I think that's safer and less
> > >likely to make people angry and frustrated.
> >
> > I don't feel like I'm changing behavior.  I think I'm trying to implement
> > some compiler optimizations via hinting.  For sure I will make sure there
> > are enough knobs so the compiler doesn't try to optimize at all.  And
> when
> > you set the flag to not remove circular requires, then we'll see how
> folks
> > feel about re-writing their code to deal with it.  I think the feedback
> > we've received so far is that we need to do some of this stuff because
> > some folks don't want to massage their code that much.  The more they
> have
> > to massage, the more likely they are to just port to some other
> > framework/language.
> >
> > -Alex
> >
> >
>

Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Andy Dufilie <an...@gmail.com>.
I understand what you're trying to do, and I want the same things.  The
greatest thing about FlexJS is that I am able to easily port my large
project (seven years of development work) with minimal change.  However,
since my project relies heavily on the exact behavior of every AS language
feature, I need it to behave exactly the same after cross-compiling, or I
end up having to do painful runtime debugging of the JS output to find out
where the cross-compiler changed the behavior of my code.  I'm willing to
take a performance hit if it means I can get things up and running sooner,
knowing that I can always go back and optimize the code later and/or play
with the optimization settings.  I understand that if you make it easy to
put it back to the default behavior that it's not so bad, but keep in mind
that new users will expect things to "just work" and may not know about the
the compiler options or directives.

On Fri, Jan 8, 2016 at 3:20 PM, Alex Harui <ah...@adobe.com> wrote:

>
>
> On 1/8/16, 12:11 PM, "Josh Tynjala" <jo...@gmail.com> wrote:
>
> >I should add that I strongly agree with Andy that we shouldn't change the
> >default behavior of the existing forms of casting. That's why I made the
> >above proposal for a special function that the emitter would know to strip
> >away. It would allow us preserve the existing casting behavior, while
> >providing a separate option that simply makes the compiler and IDEs happy.
> >It's something additional to learn instead of discovering that what you
> >already learned is now completely wrong. I think that's safer and less
> >likely to make people angry and frustrated.
>
> I don't feel like I'm changing behavior.  I think I'm trying to implement
> some compiler optimizations via hinting.  For sure I will make sure there
> are enough knobs so the compiler doesn't try to optimize at all.  And when
> you set the flag to not remove circular requires, then we'll see how folks
> feel about re-writing their code to deal with it.  I think the feedback
> we've received so far is that we need to do some of this stuff because
> some folks don't want to massage their code that much.  The more they have
> to massage, the more likely they are to just port to some other
> framework/language.
>
> -Alex
>
>

Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Alex Harui <ah...@adobe.com>.

On 1/8/16, 12:11 PM, "Josh Tynjala" <jo...@gmail.com> wrote:

>I should add that I strongly agree with Andy that we shouldn't change the
>default behavior of the existing forms of casting. That's why I made the
>above proposal for a special function that the emitter would know to strip
>away. It would allow us preserve the existing casting behavior, while
>providing a separate option that simply makes the compiler and IDEs happy.
>It's something additional to learn instead of discovering that what you
>already learned is now completely wrong. I think that's safer and less
>likely to make people angry and frustrated.

I don't feel like I'm changing behavior.  I think I'm trying to implement
some compiler optimizations via hinting.  For sure I will make sure there
are enough knobs so the compiler doesn't try to optimize at all.  And when
you set the flag to not remove circular requires, then we'll see how folks
feel about re-writing their code to deal with it.  I think the feedback
we've received so far is that we need to do some of this stuff because
some folks don't want to massage their code that much.  The more they have
to massage, the more likely they are to just port to some other
framework/language.

-Alex


Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Josh Tynjala <jo...@gmail.com>.
I should add that I strongly agree with Andy that we shouldn't change the
default behavior of the existing forms of casting. That's why I made the
above proposal for a special function that the emitter would know to strip
away. It would allow us preserve the existing casting behavior, while
providing a separate option that simply makes the compiler and IDEs happy.
It's something additional to learn instead of discovering that what you
already learned is now completely wrong. I think that's safer and less
likely to make people angry and frustrated.

- Josh

On Fri, Jan 8, 2016 at 11:38 AM, Josh Tynjala <jo...@gmail.com> wrote:

> I wonder if we could define some kind of special global function that
> would make the compiler and IDEs happy with assignments that would normally
> require casting, but the JS emitter could strip out the function call and
> assign directly. We could take advantage of the fact that the * type can be
> assigned to anything without a cast:
>
> // Example "Implementation"
>
> function __assign(value:*):*
> {
>     return value;
> }
>
> // ActionScript Usage
>
> var before:SuperClass = new SubClass();
> var after:SubClass = __assign(before);
>
> // JS Output:
>
> var before = new SubClass();
> var after = before;
>
> As you can see, it becomes a simple assignment in JS, without the function
> call overhead.
>
> Obviously, if someone can come up with a better name than __assign(),
> that's cool. Just something off the top of my head.
>
> It's worth noting that TypeScript casting does not have a runtime fail
> state. It's just there to make the compiler happy too. If the types in a
> cast aren't compatible at runtime, the code just continues running without
> error until the incompatibility surfaces elsewhere. This would have a
> similar effect.
>
> - Josh
>
>
> On Fri, Jan 8, 2016 at 11:03 AM, Andy Dufilie <an...@gmail.com>
> wrote:
>
>> On Fri, Jan 8, 2016 at 12:53 PM, Alex Harui <ah...@adobe.com> wrote:
>>
>> >
>> > On 1/8/16, 7:23 AM, "Andy Dufilie" <an...@gmail.com> wrote:
>> >
>> > >In all above cases, if Foo is a primitive type, function-style casting
>> can
>> > >never be optimized out because Foo(x) will actually change the type of
>> x.
>> > >For example, String(x) will convert null to the String "null".
>> >
>> > Well, IMO, it isn't always NO.  Sometimes you can optimize that code
>> away.
>> >  It isn't "never".  Currently, FalconJX does know if you are using
>> > function-style casting to primitives and won't optimize that away.
>>
>>
>> Does it know if this code is using primitive casting or not?
>> var type:Class = String;
>> var y = type(x);
>>
>> And what I'm playing with now for function-style casting won't optimize it
>> > away if it finds a try/catch around it.
>> >
>>
>> But that won't work if the try/catch is in function A that calls function
>> B
>> which has the function-style cast.
>>
>> You were just complaining about how much code massaging you have to do.
>> >
>>
>> I'm happy with the current situation where it preserves the behavior of
>> the
>> explicit type casting code and I recommend not changing it. Speed
>> optimizations will always require code massaging. If you're referring to
>> automatic casts for typed variables and parameters, I can live with that
>> because I know if the compiler added those casts everywhere that the
>> performance hit would likely be too much, but I wouldn't be opposed to
>> adding that automatic casting with an option to enable or disable it.
>>
>>
>> > We've heard similar feedback from others, so my first instinct is to
>> find
>> > a way to give you control over your code output with less massaging.
>> This
>> > new syntax would still require massaging.
>>
>>
>> Adding new syntax does not *require* massaging to existing code, because
>> you don't *have* to update your code to use the new syntax.  It should be
>> looked at as an optional speed optimization for those that are
>> performance-conscious.  If you change the behavior of existing syntax,
>> then
>> that does require massaging.
>>
>>
>> > The @flexjsignorecoercion (or
>> > now @flexjsemitcoercion) is a function-level directive.  We could add
>> > project-level, file-level and/or line-level directives if that is easier
>> > than massaging the code.
>> >
>>
>> If you insist on making the compiler misbehave by default, then a
>> project-level setting to bring it back to the correct behavior is
>> absolutely necessary. I'd rather not have to add a directive to every
>> single function just to prevent the compiler from mangling the code.  If I
>> write an explicit cast, I expect the compiler to respect that rather than
>> act like it knows better.
>>
>>
>> > IMO, an optimizing compiler would be smart enough to know when to remove
>> > the Language.as calls.  All I'm trying to provide is some smarts in the
>> > compiler to do that optimization and some directives to help if we get
>> it
>> > wrong.
>> >
>>
>> I believe risky automatic optimizations should enabled or disabled through
>> a flag passed to the build command.  The default behavior of the compiler
>> should be to preserve the behavior of the code. Extra directives should
>> not
>> be required to let the compiler know that you actually mean what you typed
>> if what you typed is valid code.  Why should we have to tell it twice
>> everywhere? ("Hey compiler, do this.  No, seriously, I really want you to
>> do what I just asked you to do.")
>>
>>
>> > If you still want to add a new language feature, (x:Foo) is valid
>> pattern
>> > in a function parameter list, so I don't know if the compiler would give
>> > you trouble implementing it.  Another option might be another keyword
>> like
>> > "as" (maybe "_as_").
>> >
>>
>> I'm feeling the pain of the performance hit, but I am opposed to breaking
>> language features by default, so I would like to explore different
>> options.
>> I think (x:Foo) is doable.
>>
>>
>>
>> > I think I will put the circularity scan as a compiler option for folks
>> who
>> > still need it.
>> >
>>
>> I think it's a good idea to disable the scan by default because the error
>> messages actually help you write better code, which is the job of
>> compilers
>> and IDEs.  It still needs to be an option to support existing codebases.
>>
>
>

Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Alex Harui <ah...@adobe.com>.

On 1/8/16, 11:38 AM, "Josh Tynjala" <jo...@gmail.com> wrote:

>I wonder if we could define some kind of special global function that
>would
>make the compiler and IDEs happy with assignments that would normally
>require casting, but the JS emitter could strip out the function call and
>assign directly. We could take advantage of the fact that the * type can
>be
>assigned to anything without a cast:
>
>// Example "Implementation"
>
>function __assign(value:*):*
>{
>    return value;
>}
>
>// ActionScript Usage
>
>var before:SuperClass = new SubClass();
>var after:SubClass = __assign(before);
>
>// JS Output:
>
>var before = new SubClass();
>var after = before;
>
>As you can see, it becomes a simple assignment in JS, without the function
>call overhead.
>
>Obviously, if someone can come up with a better name than __assign(),
>that's cool. Just something off the top of my head.

Interesting idea.  It also requires massaging code which I am trying to
avoid.  I'm not opposed to anyone implementing it.  We can give folks
choices.

>
>It's worth noting that TypeScript casting does not have a runtime fail
>state. It's just there to make the compiler happy too. If the types in a
>cast aren't compatible at runtime, the code just continues running without
>error until the incompatibility surfaces elsewhere. This would have a
>similar effect.

One thing I should mention:  In my vision for FlexJS, folks would produce
a SWF version as well as a HTML/JS/CSS version. That isn't true for folks
doing native JS with JS.swc, but one of the advantages of having a SWF
version is that if even if you just use it for testing and never deploy
it, you will get the advantage of the Flash/AIR runtime verifier to help
you make sure all of your types and interfaces are matching up as they
should, making the need for checking in the JS version even lower.

For those of you who work on really large projects with cross-team
integration, this can be very important, because Flash will detect that a
module you loaded doesn't match the loader's interface expectations at the
time of the load, as opposed to waiting for you to finally hit the code
path that will expose the error.

-Alex


Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Josh Tynjala <jo...@gmail.com>.
I wonder if we could define some kind of special global function that would
make the compiler and IDEs happy with assignments that would normally
require casting, but the JS emitter could strip out the function call and
assign directly. We could take advantage of the fact that the * type can be
assigned to anything without a cast:

// Example "Implementation"

function __assign(value:*):*
{
    return value;
}

// ActionScript Usage

var before:SuperClass = new SubClass();
var after:SubClass = __assign(before);

// JS Output:

var before = new SubClass();
var after = before;

As you can see, it becomes a simple assignment in JS, without the function
call overhead.

Obviously, if someone can come up with a better name than __assign(),
that's cool. Just something off the top of my head.

It's worth noting that TypeScript casting does not have a runtime fail
state. It's just there to make the compiler happy too. If the types in a
cast aren't compatible at runtime, the code just continues running without
error until the incompatibility surfaces elsewhere. This would have a
similar effect.

- Josh


On Fri, Jan 8, 2016 at 11:03 AM, Andy Dufilie <an...@gmail.com>
wrote:

> On Fri, Jan 8, 2016 at 12:53 PM, Alex Harui <ah...@adobe.com> wrote:
>
> >
> > On 1/8/16, 7:23 AM, "Andy Dufilie" <an...@gmail.com> wrote:
> >
> > >In all above cases, if Foo is a primitive type, function-style casting
> can
> > >never be optimized out because Foo(x) will actually change the type of
> x.
> > >For example, String(x) will convert null to the String "null".
> >
> > Well, IMO, it isn't always NO.  Sometimes you can optimize that code
> away.
> >  It isn't "never".  Currently, FalconJX does know if you are using
> > function-style casting to primitives and won't optimize that away.
>
>
> Does it know if this code is using primitive casting or not?
> var type:Class = String;
> var y = type(x);
>
> And what I'm playing with now for function-style casting won't optimize it
> > away if it finds a try/catch around it.
> >
>
> But that won't work if the try/catch is in function A that calls function B
> which has the function-style cast.
>
> You were just complaining about how much code massaging you have to do.
> >
>
> I'm happy with the current situation where it preserves the behavior of the
> explicit type casting code and I recommend not changing it. Speed
> optimizations will always require code massaging. If you're referring to
> automatic casts for typed variables and parameters, I can live with that
> because I know if the compiler added those casts everywhere that the
> performance hit would likely be too much, but I wouldn't be opposed to
> adding that automatic casting with an option to enable or disable it.
>
>
> > We've heard similar feedback from others, so my first instinct is to find
> > a way to give you control over your code output with less massaging.
> This
> > new syntax would still require massaging.
>
>
> Adding new syntax does not *require* massaging to existing code, because
> you don't *have* to update your code to use the new syntax.  It should be
> looked at as an optional speed optimization for those that are
> performance-conscious.  If you change the behavior of existing syntax, then
> that does require massaging.
>
>
> > The @flexjsignorecoercion (or
> > now @flexjsemitcoercion) is a function-level directive.  We could add
> > project-level, file-level and/or line-level directives if that is easier
> > than massaging the code.
> >
>
> If you insist on making the compiler misbehave by default, then a
> project-level setting to bring it back to the correct behavior is
> absolutely necessary. I'd rather not have to add a directive to every
> single function just to prevent the compiler from mangling the code.  If I
> write an explicit cast, I expect the compiler to respect that rather than
> act like it knows better.
>
>
> > IMO, an optimizing compiler would be smart enough to know when to remove
> > the Language.as calls.  All I'm trying to provide is some smarts in the
> > compiler to do that optimization and some directives to help if we get it
> > wrong.
> >
>
> I believe risky automatic optimizations should enabled or disabled through
> a flag passed to the build command.  The default behavior of the compiler
> should be to preserve the behavior of the code. Extra directives should not
> be required to let the compiler know that you actually mean what you typed
> if what you typed is valid code.  Why should we have to tell it twice
> everywhere? ("Hey compiler, do this.  No, seriously, I really want you to
> do what I just asked you to do.")
>
>
> > If you still want to add a new language feature, (x:Foo) is valid pattern
> > in a function parameter list, so I don't know if the compiler would give
> > you trouble implementing it.  Another option might be another keyword
> like
> > "as" (maybe "_as_").
> >
>
> I'm feeling the pain of the performance hit, but I am opposed to breaking
> language features by default, so I would like to explore different options.
> I think (x:Foo) is doable.
>
>
>
> > I think I will put the circularity scan as a compiler option for folks
> who
> > still need it.
> >
>
> I think it's a good idea to disable the scan by default because the error
> messages actually help you write better code, which is the job of compilers
> and IDEs.  It still needs to be an option to support existing codebases.
>

Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Andy Dufilie <an...@gmail.com>.
On Fri, Jan 8, 2016 at 12:53 PM, Alex Harui <ah...@adobe.com> wrote:

>
> On 1/8/16, 7:23 AM, "Andy Dufilie" <an...@gmail.com> wrote:
>
> >In all above cases, if Foo is a primitive type, function-style casting can
> >never be optimized out because Foo(x) will actually change the type of x.
> >For example, String(x) will convert null to the String "null".
>
> Well, IMO, it isn't always NO.  Sometimes you can optimize that code away.
>  It isn't "never".  Currently, FalconJX does know if you are using
> function-style casting to primitives and won't optimize that away.


Does it know if this code is using primitive casting or not?
var type:Class = String;
var y = type(x);

And what I'm playing with now for function-style casting won't optimize it
> away if it finds a try/catch around it.
>

But that won't work if the try/catch is in function A that calls function B
which has the function-style cast.

You were just complaining about how much code massaging you have to do.
>

I'm happy with the current situation where it preserves the behavior of the
explicit type casting code and I recommend not changing it. Speed
optimizations will always require code massaging. If you're referring to
automatic casts for typed variables and parameters, I can live with that
because I know if the compiler added those casts everywhere that the
performance hit would likely be too much, but I wouldn't be opposed to
adding that automatic casting with an option to enable or disable it.


> We've heard similar feedback from others, so my first instinct is to find
> a way to give you control over your code output with less massaging.  This
> new syntax would still require massaging.


Adding new syntax does not *require* massaging to existing code, because
you don't *have* to update your code to use the new syntax.  It should be
looked at as an optional speed optimization for those that are
performance-conscious.  If you change the behavior of existing syntax, then
that does require massaging.


> The @flexjsignorecoercion (or
> now @flexjsemitcoercion) is a function-level directive.  We could add
> project-level, file-level and/or line-level directives if that is easier
> than massaging the code.
>

If you insist on making the compiler misbehave by default, then a
project-level setting to bring it back to the correct behavior is
absolutely necessary. I'd rather not have to add a directive to every
single function just to prevent the compiler from mangling the code.  If I
write an explicit cast, I expect the compiler to respect that rather than
act like it knows better.


> IMO, an optimizing compiler would be smart enough to know when to remove
> the Language.as calls.  All I'm trying to provide is some smarts in the
> compiler to do that optimization and some directives to help if we get it
> wrong.
>

I believe risky automatic optimizations should enabled or disabled through
a flag passed to the build command.  The default behavior of the compiler
should be to preserve the behavior of the code. Extra directives should not
be required to let the compiler know that you actually mean what you typed
if what you typed is valid code.  Why should we have to tell it twice
everywhere? ("Hey compiler, do this.  No, seriously, I really want you to
do what I just asked you to do.")


> If you still want to add a new language feature, (x:Foo) is valid pattern
> in a function parameter list, so I don't know if the compiler would give
> you trouble implementing it.  Another option might be another keyword like
> "as" (maybe "_as_").
>

I'm feeling the pain of the performance hit, but I am opposed to breaking
language features by default, so I would like to explore different options.
I think (x:Foo) is doable.



> I think I will put the circularity scan as a compiler option for folks who
> still need it.
>

I think it's a good idea to disable the scan by default because the error
messages actually help you write better code, which is the job of compilers
and IDEs.  It still needs to be an option to support existing codebases.

Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Alex Harui <ah...@adobe.com>.

On 1/8/16, 7:23 AM, "Andy Dufilie" <an...@gmail.com> wrote:

>On Fri, Jan 8, 2016 at 1:43 AM, Alex Harui <ah...@adobe.com> wrote:
>
>>
>> But, IMO, for FlexJS, what really matters is what should happen in the
>>JS
>> output, and the essence of this thread is that in many cases, we can
>> optimize away the call to Language.as.
>>
>
>
>> Right now, "function" casting also results in a Language.as call with a
>> flag that throws an error if "as" fails.  I think we can optimize out a
>> lot of these calls as well.
>
>
>Here are some different situations to consider:
>
>1.)
>(x as Foo).bar(a,b);
>Foo(x).bar(a,b);
>Can optimize either? MAYBE - you MAY get a different error if x is not of
>type Foo (possibly "function bar not found on x").
>
>2.)
>var y:Foo = x as Foo;
>var y:Foo = Foo(x);
>Can optimize "as"? NO - the code is enforcing x to either be null or an
>instance of Foo. The code that follows is not expecting x to be of any
>type
>besides Foo or null.
>Can optimize (cast)? NO - the code is not expecting to continue if x is
>not
>of type Foo.
>If either cast is removed the code becomes incorrect.
>
>3.)
>var y = (x as Foo).property;
>var y = Foo(x).property;
>Can optimize either? NO - the code should either get the property of an
>instance of Foo or throw an error.  If "as" is optimized out, you can
>either get the property of an unrelated type, or you can get y=undefined.
>Either behavior is wrong and could be very hard to track down. The code is
>not expecting to continue if x is not of type Foo.
>
>4.)
>(x as Foo).property = value;
>Foo(x).property = value;
>Can optimize either? NO - the code should either set the property of an
>instance of Foo or throw an error. If either cast is removed, you may be
>setting the property of an unrelated type which will be very hard to track
>down.  The code is not expecting to continue if x is not of type Foo.
>
>We may be able to make the distinction between the first case and the rest
>and optimize out the first call to "as", but since the resulting code is
>still unpredictable, it should not be the default behavior of the
>cross-compiler.
>
>In all above cases, if Foo is a primitive type, function-style casting can
>never be optimized out because Foo(x) will actually change the type of x.
>For example, String(x) will convert null to the String "null".

Well, IMO, it isn't always NO.  Sometimes you can optimize that code away.
 It isn't "never".  Currently, FalconJX does know if you are using
function-style casting to primitives and won't optimize that away.  And
what I'm playing with now for function-style casting won't optimize it
away if it finds a try/catch around it.

>
>
>
>> In the past, we always generated
>> the call and you could suppress it with @flexjsignorecoercion, but I'm
>> considering pushing the change where we default to not generating the
>>call
>> and you have to opt-in with @flexjsemitcoercion.  But when you opt-in,
>>we
>> do want to cause the same behavior that you will get in a SWF.
>>
>>
>A better solution would be to introduce new syntax that always gets
>optimized out in both AS+JS and only serves the purpose of "making the
>compiler happy".  I suggest the following:
>
>(x:Foo) instead of (x as Foo)
>
>Examples:
>(x:Foo).bar(a,b);
>var y:Foo = x:Foo;
>var y = (x:Foo).property;
>(x:Foo).property = value;
>(obj.prop : Foo).bar();
>var y:Number = (a + b):Number;
>(obj.prop : pkg.name.Foo).bar();
>
>It's easily readable, Action-Scripty, and I believe it can be
>distinguished
>from all other syntax, including ternary operator, line labels, and
>namespacing.
>I can work on implementing this feature.

You were just complaining about how much code massaging you have to do.
We've heard similar feedback from others, so my first instinct is to find
a way to give you control over your code output with less massaging.  This
new syntax would still require massaging.  The @flexjsignorecoercion (or
now @flexjsemitcoercion) is a function-level directive.  We could add
project-level, file-level and/or line-level directives if that is easier
than massaging the code.  New language features may also be a problem for
IDE code assist.

IMO, an optimizing compiler would be smart enough to know when to remove
the Language.as calls.  All I'm trying to provide is some smarts in the
compiler to do that optimization and some directives to help if we get it
wrong.

If you still want to add a new language feature, (x:Foo) is valid pattern
in a function parameter list, so I don't know if the compiler would give
you trouble implementing it.  Another option might be another keyword like
"as" (maybe "_as_").

>
>Maybe someday, we can get the compiler to do
>> code-flow analysis and determine if we can optimize out these calls to
>> Language.as, but for now, not having these calls makes the code smaller,
>> and reduces some of the dependencies/goog.requires which reduces the
>> likelihood the Closure Compiler will find a circular dependency.
>>
>> -Alex
>>
>
>IMO, circular dependencies are developer errors and need not be addressed
>by the compiler.  They simply cannot be resolved in certain situations.
>Ignored, sure, but not necessarily resolved. Circular dependencies are not
>specifically related to casting, so I don't think they should be a factor
>in this decision.

True circular dependencies (that affect initialization) are developer
errors.  Maybe we are doing it wrong in the compiler today, but the Google
Closure Compiler implies that you should have goog.require statements for
all dependencies in an output file, and then complains about circular
dependencies if you do.  Here's the simplest case:

--- Parent.as ---
class Parent
{
  var children:Vector.<Child>;
}

--- Child.as ---
class Child
{
  var parent:Parent;
}

FalconJX currently outputs:
--- Parent.js ---
goog.provide("Parent");
goog.require("Child");
...

--- Child.js ---
goog.provide("Child"):
goog.require("Parent");
...

Sure, we could force folks to re-code this relationship with interfaces to
avoid dependencies, but again, folks migrating large code bases have
indicated that they would rather not.  FalconJX currently has code that
walks the chain of class dependencies from the main class and removes
goog.requires that are not required for static initialization of the
class.  I think I can't know whether to kick out the goog.require in
Parent or Child until I see whether the main class referenced Parent or
Child first.

But it turns out that in all of our FlexJS framework code and examples so
far, we don't have any circularities that aren't generated by casting
calls, and defaulting to optimizing them away meant that the goog.requires
don't get generated and I could save the time of scanning for
circularities.

I think I will put the circularity scan as a compiler option for folks who
still need it.

So, I'm leaning toward thinking of this as an "optimizing compiler"
problem so folks don't have to touch their existing code as much.

Thoughts?
-Alex


Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Andy Dufilie <an...@gmail.com>.
On Fri, Jan 8, 2016 at 1:43 AM, Alex Harui <ah...@adobe.com> wrote:

>
> But, IMO, for FlexJS, what really matters is what should happen in the JS
> output, and the essence of this thread is that in many cases, we can
> optimize away the call to Language.as.
>


> Right now, "function" casting also results in a Language.as call with a
> flag that throws an error if "as" fails.  I think we can optimize out a
> lot of these calls as well.


Here are some different situations to consider:

1.)
(x as Foo).bar(a,b);
Foo(x).bar(a,b);
Can optimize either? MAYBE - you MAY get a different error if x is not of
type Foo (possibly "function bar not found on x").

2.)
var y:Foo = x as Foo;
var y:Foo = Foo(x);
Can optimize "as"? NO - the code is enforcing x to either be null or an
instance of Foo. The code that follows is not expecting x to be of any type
besides Foo or null.
Can optimize (cast)? NO - the code is not expecting to continue if x is not
of type Foo.
If either cast is removed the code becomes incorrect.

3.)
var y = (x as Foo).property;
var y = Foo(x).property;
Can optimize either? NO - the code should either get the property of an
instance of Foo or throw an error.  If "as" is optimized out, you can
either get the property of an unrelated type, or you can get y=undefined.
Either behavior is wrong and could be very hard to track down. The code is
not expecting to continue if x is not of type Foo.

4.)
(x as Foo).property = value;
Foo(x).property = value;
Can optimize either? NO - the code should either set the property of an
instance of Foo or throw an error. If either cast is removed, you may be
setting the property of an unrelated type which will be very hard to track
down.  The code is not expecting to continue if x is not of type Foo.

We may be able to make the distinction between the first case and the rest
and optimize out the first call to "as", but since the resulting code is
still unpredictable, it should not be the default behavior of the
cross-compiler.

In all above cases, if Foo is a primitive type, function-style casting can
never be optimized out because Foo(x) will actually change the type of x.
For example, String(x) will convert null to the String "null".



> In the past, we always generated
> the call and you could suppress it with @flexjsignorecoercion, but I'm
> considering pushing the change where we default to not generating the call
> and you have to opt-in with @flexjsemitcoercion.  But when you opt-in, we
> do want to cause the same behavior that you will get in a SWF.
>
>
A better solution would be to introduce new syntax that always gets
optimized out in both AS+JS and only serves the purpose of "making the
compiler happy".  I suggest the following:

(x:Foo) instead of (x as Foo)

Examples:
(x:Foo).bar(a,b);
var y:Foo = x:Foo;
var y = (x:Foo).property;
(x:Foo).property = value;
(obj.prop : Foo).bar();
var y:Number = (a + b):Number;
(obj.prop : pkg.name.Foo).bar();

It's easily readable, Action-Scripty, and I believe it can be distinguished
from all other syntax, including ternary operator, line labels, and
namespacing.
I can work on implementing this feature.

Maybe someday, we can get the compiler to do
> code-flow analysis and determine if we can optimize out these calls to
> Language.as, but for now, not having these calls makes the code smaller,
> and reduces some of the dependencies/goog.requires which reduces the
> likelihood the Closure Compiler will find a circular dependency.
>
> -Alex
>

IMO, circular dependencies are developer errors and need not be addressed
by the compiler.  They simply cannot be resolved in certain situations.
Ignored, sure, but not necessarily resolved. Circular dependencies are not
specifically related to casting, so I don't think they should be a factor
in this decision.

Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Alex Harui <ah...@adobe.com>.
Way back in the day, I was told that "Function" casting was faster, and
you'll see almost as much of it as "as" casting in the Flex SDK source.  I
ran a test on my Mac using FP20 standalone and for 5,000,000 iterations
"function" casting is only 14ms slower than "as" casting so I'm not sure
it really matters what we use for a SWF.  I don’t know what testing
conditions were in the articles linked in this thread that found a greater
difference.

But, IMO, for FlexJS, what really matters is what should happen in the JS
output, and the essence of this thread is that in many cases, we can
optimize away the call to Language.as.  In the past, we always generated
the call and you could suppress it with @flexjsignorecoercion, but I'm
considering pushing the change where we default to not generating the call
and you have to opt-in with @flexjsemitcoercion.  But when you opt-in, we
do want to cause the same behavior that you will get in a SWF.

Right now, "function" casting also results in a Language.as call with a
flag that throws an error if "as" fails.  I think we can optimize out a
lot of these calls as well.  Maybe someday, we can get the compiler to do
code-flow analysis and determine if we can optimize out these calls to
Language.as, but for now, not having these calls makes the code smaller,
and reduces some of the dependencies/goog.requires which reduces the
likelihood the Closure Compiler will find a circular dependency.

-Alex

On 1/7/16, 8:30 PM, "Josh Tynjala" <jo...@gmail.com> wrote:

>Interesting side note. As I understand it, try-catch is no longer
>expensive
>in the case where no error is thrown. I explained to someone why I didn't
>want to use a try-catch in some performance critical code, and I cited
>Jackson Dunstan's article. They ran the benchmark from the article in a
>newer runtime, and the big performance difference was gone. I was able to
>confirm on my machine.
>
>Regardless, I would never wrap a function-style cast in a try-catch. Not
>my
>style. If I expect it might fail, I check with "is" first, or, sometimes,
>use an as-style cast instead and check for null.
>
>To be honest, my memory of the performance difference between casting
>styles is from 6-8 years ago, so my knowledge may be as out of date as the
>try-catch thing. Or maybe I'm completely misremembering after so many
>years. I've had a few cases where that's true, like the whole toString()
>thing the other day.
>
>- Josh
>On Jan 7, 2016 8:07 PM, "Andy Dufilie" <an...@gmail.com> wrote:
>
>> On Thu, Jan 7, 2016 at 10:54 PM, Josh Tynjala <jo...@gmail.com>
>> wrote:
>>
>> > That's odd. I swear I remember someone from Adobe once explaining that
>> > function-style casting is faster than as-style casting (with the
>> exception
>> > of primitive types that have a top level function that makes
>> function-style
>> > casting impossible, as you mentioned in 1). I've tried to avoid
>>as-style
>> > casting for years, based on this knowledge.
>> >
>> > - Josh
>> >
>>
>> See this stack overflow answer and the articles it links:
>> http://stackoverflow.com/a/14268394
>>
>> *EDIT:* concerning performance, using as is reported to be faster than
>>the
>> > function call style casting in various articles: [1
>> > <http://jacksondunstan.com/articles/830>] [2
>> > 
>><http://upshots.org/actionscript/20-tips-to-optimize-your-actionscript>]
>> [
>> > 3
>> > <
>> 
>>http://gamedevjuice.wordpress.com/2008/02/15/seven-tips-about-performance
>>-optimization-in-actionscript-3/
>> >].
>> > The first article cited looks at the performance differences in depth
>>and
>> > reports that as is 4x-4.5x faster.
>> >
>> > *EDIT 2:* Not only is as 4x-4.5x faster in the normal best case, but
>>when
>> > you wrap the (cast) style conversion in a try-catch block, and an
>>error
>> > actually ends up being thrown, it's more like 30x - 230x faster. In
>>AS3,
>> if
>> > you think you're going to do something exceptional (in that it could
>> throw
>> > an error) then it's clear that you should always look before you leap.
>> > Never use try/catch unless forced to by the API, and indeed that
>>means to
>> > never (cast) It also is instructive to look at the performance
>> > implications of try/catch even when no exception is thrown. There's a
>> > performance penalty to setting up a try/catch block even in the happy
>> case
>> > that nothing goes wrong.
>> >
>> >
>>


Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Josh Tynjala <jo...@gmail.com>.
Interesting side note. As I understand it, try-catch is no longer expensive
in the case where no error is thrown. I explained to someone why I didn't
want to use a try-catch in some performance critical code, and I cited
Jackson Dunstan's article. They ran the benchmark from the article in a
newer runtime, and the big performance difference was gone. I was able to
confirm on my machine.

Regardless, I would never wrap a function-style cast in a try-catch. Not my
style. If I expect it might fail, I check with "is" first, or, sometimes,
use an as-style cast instead and check for null.

To be honest, my memory of the performance difference between casting
styles is from 6-8 years ago, so my knowledge may be as out of date as the
try-catch thing. Or maybe I'm completely misremembering after so many
years. I've had a few cases where that's true, like the whole toString()
thing the other day.

- Josh
On Jan 7, 2016 8:07 PM, "Andy Dufilie" <an...@gmail.com> wrote:

> On Thu, Jan 7, 2016 at 10:54 PM, Josh Tynjala <jo...@gmail.com>
> wrote:
>
> > That's odd. I swear I remember someone from Adobe once explaining that
> > function-style casting is faster than as-style casting (with the
> exception
> > of primitive types that have a top level function that makes
> function-style
> > casting impossible, as you mentioned in 1). I've tried to avoid as-style
> > casting for years, based on this knowledge.
> >
> > - Josh
> >
>
> See this stack overflow answer and the articles it links:
> http://stackoverflow.com/a/14268394
>
> *EDIT:* concerning performance, using as is reported to be faster than the
> > function call style casting in various articles: [1
> > <http://jacksondunstan.com/articles/830>] [2
> > <http://upshots.org/actionscript/20-tips-to-optimize-your-actionscript>]
> [
> > 3
> > <
> http://gamedevjuice.wordpress.com/2008/02/15/seven-tips-about-performance-optimization-in-actionscript-3/
> >].
> > The first article cited looks at the performance differences in depth and
> > reports that as is 4x-4.5x faster.
> >
> > *EDIT 2:* Not only is as 4x-4.5x faster in the normal best case, but when
> > you wrap the (cast) style conversion in a try-catch block, and an error
> > actually ends up being thrown, it's more like 30x - 230x faster. In AS3,
> if
> > you think you're going to do something exceptional (in that it could
> throw
> > an error) then it's clear that you should always look before you leap.
> > Never use try/catch unless forced to by the API, and indeed that means to
> > never (cast) It also is instructive to look at the performance
> > implications of try/catch even when no exception is thrown. There's a
> > performance penalty to setting up a try/catch block even in the happy
> case
> > that nothing goes wrong.
> >
> >
>

Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Andy Dufilie <an...@gmail.com>.
On Thu, Jan 7, 2016 at 10:54 PM, Josh Tynjala <jo...@gmail.com> wrote:

> That's odd. I swear I remember someone from Adobe once explaining that
> function-style casting is faster than as-style casting (with the exception
> of primitive types that have a top level function that makes function-style
> casting impossible, as you mentioned in 1). I've tried to avoid as-style
> casting for years, based on this knowledge.
>
> - Josh
>

See this stack overflow answer and the articles it links:
http://stackoverflow.com/a/14268394

*EDIT:* concerning performance, using as is reported to be faster than the
> function call style casting in various articles: [1
> <http://jacksondunstan.com/articles/830>] [2
> <http://upshots.org/actionscript/20-tips-to-optimize-your-actionscript>] [
> 3
> <http://gamedevjuice.wordpress.com/2008/02/15/seven-tips-about-performance-optimization-in-actionscript-3/>].
> The first article cited looks at the performance differences in depth and
> reports that as is 4x-4.5x faster.
>
> *EDIT 2:* Not only is as 4x-4.5x faster in the normal best case, but when
> you wrap the (cast) style conversion in a try-catch block, and an error
> actually ends up being thrown, it's more like 30x - 230x faster. In AS3, if
> you think you're going to do something exceptional (in that it could throw
> an error) then it's clear that you should always look before you leap.
> Never use try/catch unless forced to by the API, and indeed that means to
> never (cast) It also is instructive to look at the performance
> implications of try/catch even when no exception is thrown. There's a
> performance penalty to setting up a try/catch block even in the happy case
> that nothing goes wrong.
>
>

Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Josh Tynjala <jo...@gmail.com>.
That's odd. I swear I remember someone from Adobe once explaining that
function-style casting is faster than as-style casting (with the exception
of primitive types that have a top level function that makes function-style
casting impossible, as you mentioned in 1). I've tried to avoid as-style
casting for years, based on this knowledge.

- Josh
On Jan 7, 2016 7:24 PM, "Andy Dufilie" <an...@gmail.com> wrote:

> On Thu, Jan 7, 2016 at 8:27 PM, Alex Harui <ah...@adobe.com> wrote:
>
> > If "SomeType(somevar)" is not in a try/catch it will throw an exception.
> > How often are you relying on that vs just trying to make the compiler
> > happy?
> >
>
> "function" casting is slower than "as" in ActionScript, so I have stayed
> away from it.  When I do use it, there are two cases:
>
> 1. If coercing to a primitive type, it actually tries to convert the value
> to that type. With String(value) I expect it to give me a String via
> toString().  With Number(value) I expect it to converting Strings to
> Numbers and undefined -> NaN. I expect it to throw an error if the value
> cannot be converted to a Number. Really I would rather have it return NaN
> instead of throwing an error, but we can't change that behavior because
> that's part of ECMAScript.
>
> 2. When coercing to a non-primitive, I mostly use it to get compiler
> checking for the member variables or functions I access, but I would still
> want it to throw an error even in JavaScript if it is not of the correct
> type, because that's what it does in ActionScript and I expect the
> cross-compiler to faithfully preserve the behavior.
>
>
> On Thu, Jan 7, 2016 at 8:32 PM, Alex Harui <ah...@adobe.com> wrote:
>
> >
> > On 1/7/16, 5:24 PM, "Andy Dufilie" <an...@gmail.com> wrote:
> > >if (obj is Thing1)
> > >    (obj as Thing1).foo(a,b);
> > >else if (obj is Thing2)
> > >    (obj as Thing2).bar(x,y);
> >
> > There are no plans to change "is", just "as".  Are you using "as" as a
> > test or just "is".  In the example above, you are using "as" just to make
> > the compiler happy.
> >
> >
> It's used above to get compiler checking in case I misspelled foo() or
> bar(), or if I pass in bad variable types to either function. In the next
> example, I'm relying on "as" to change the value to null without throwing
> an exception if it is not of the correct type. The code will break if that
> behavior is not preserved:
>
> var thing1:Thing1 = obj as Thing1;
> var thing2:Thing2 = obj as Thing2;
> if (thing1)
>     thing1.foo(a,b);
> if (thing2)
>     thing2.bar(x,y);
>
> Here is similar real-world code relying on this behavior and it will break
> if "as" is removed by the cross-compiler:
>
>
> https://github.com/WeaveTeam/Weave/blob/13f98136a8cfd8dc4662f6014abcd5aa87baa56d/WeaveJS/src/weavejs/core/SessionManager.as#L335
>
>
>
> > >I see "is" and "as" as highly useful features, and I think it would be a
> > >mistake to make the code cross-compile into something that behaves
> > >differently by default.  IMO if cross-compiled code behaves differently
> > >than the original then it's being mangled and can't be trusted.
> >
> > That's the root of my question: how many folks us "as" to actually
> convert
> > data vs just make the compiler happy.  Again, no plans to change "is".
> >
>
>
> This is not just about making the compiler "happy." It's about getting the
> benefit of compiler checking to alert you when you've typed the wrong
> member variable / function name, or giving the wrong parameter types. If I
> was only concerned about making the compiler happy (preventing it from
> yelling at me), I could just use Object(value).whatever() or use untyped
> variables everywhere. I may as well use plain JavaScript at that point.
>
> We shouldn't be planning to change anything that would cause the
> cross-compiled to code to behave differently than the original source.
> This is not something that should require a vote - it is an error to change
> the behavior of code during cross-compilation.  If such an option is added
> to omit portions of code by default, then the compiler should give you a
> warning for every place that occurs so the user knows exactly what is
> happening.  Otherwise the cross-compiler cannot be trusted.
>
>
>
> > >
> > >A related issue is when setting a typed variable or passing in a
> parameter
> > >to a function, it will do type coercion automatically in AS but that
> > >behavior is lost when cross-compiling to JS.  For example, I have
> > >situations like this where I now have to add manual type casting, and I
> > >wish the compiler would do that automatically:
> > >
> > >var str:String = value_which_may_be_a_number;
> >
> > What error are you getting?  I thought the auto-conversion worked for
> both
> > JS and AS.
> >
> > -Alex
> >
> >
> Auto-conversion is currently not done for function parameters or variable
> assignment.
>
> AS input:
>     public function testfunc(a:String, b:String):Array {
>         var c:String = a;
>         var d:String = b;
>         return [typeof a, typeof b, typeof c, typeof d];
>     }
>
> JS output:
>     testfunc = function(a, b) {
>         var /** @type {string} */ c = a;
>         var /** @type {string} */ d = b;
>         return [typeof(a), typeof(b), typeof(c), typeof(d)];
>     };
>
> This code:
>     var foo = testfunc;
>     return foo(1,2)
> will return ['string', 'string', 'string', 'string'] in ActionScript, but
> ['number', 'number', 'number', 'number'] in JavaScript.
>

Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Andy Dufilie <an...@gmail.com>.
On Thu, Jan 7, 2016 at 8:27 PM, Alex Harui <ah...@adobe.com> wrote:

> If "SomeType(somevar)" is not in a try/catch it will throw an exception.
> How often are you relying on that vs just trying to make the compiler
> happy?
>

"function" casting is slower than "as" in ActionScript, so I have stayed
away from it.  When I do use it, there are two cases:

1. If coercing to a primitive type, it actually tries to convert the value
to that type. With String(value) I expect it to give me a String via
toString().  With Number(value) I expect it to converting Strings to
Numbers and undefined -> NaN. I expect it to throw an error if the value
cannot be converted to a Number. Really I would rather have it return NaN
instead of throwing an error, but we can't change that behavior because
that's part of ECMAScript.

2. When coercing to a non-primitive, I mostly use it to get compiler
checking for the member variables or functions I access, but I would still
want it to throw an error even in JavaScript if it is not of the correct
type, because that's what it does in ActionScript and I expect the
cross-compiler to faithfully preserve the behavior.


On Thu, Jan 7, 2016 at 8:32 PM, Alex Harui <ah...@adobe.com> wrote:

>
> On 1/7/16, 5:24 PM, "Andy Dufilie" <an...@gmail.com> wrote:
> >if (obj is Thing1)
> >    (obj as Thing1).foo(a,b);
> >else if (obj is Thing2)
> >    (obj as Thing2).bar(x,y);
>
> There are no plans to change "is", just "as".  Are you using "as" as a
> test or just "is".  In the example above, you are using "as" just to make
> the compiler happy.
>
>
It's used above to get compiler checking in case I misspelled foo() or
bar(), or if I pass in bad variable types to either function. In the next
example, I'm relying on "as" to change the value to null without throwing
an exception if it is not of the correct type. The code will break if that
behavior is not preserved:

var thing1:Thing1 = obj as Thing1;
var thing2:Thing2 = obj as Thing2;
if (thing1)
    thing1.foo(a,b);
if (thing2)
    thing2.bar(x,y);

Here is similar real-world code relying on this behavior and it will break
if "as" is removed by the cross-compiler:

https://github.com/WeaveTeam/Weave/blob/13f98136a8cfd8dc4662f6014abcd5aa87baa56d/WeaveJS/src/weavejs/core/SessionManager.as#L335



> >I see "is" and "as" as highly useful features, and I think it would be a
> >mistake to make the code cross-compile into something that behaves
> >differently by default.  IMO if cross-compiled code behaves differently
> >than the original then it's being mangled and can't be trusted.
>
> That's the root of my question: how many folks us "as" to actually convert
> data vs just make the compiler happy.  Again, no plans to change "is".
>


This is not just about making the compiler "happy." It's about getting the
benefit of compiler checking to alert you when you've typed the wrong
member variable / function name, or giving the wrong parameter types. If I
was only concerned about making the compiler happy (preventing it from
yelling at me), I could just use Object(value).whatever() or use untyped
variables everywhere. I may as well use plain JavaScript at that point.

We shouldn't be planning to change anything that would cause the
cross-compiled to code to behave differently than the original source.
This is not something that should require a vote - it is an error to change
the behavior of code during cross-compilation.  If such an option is added
to omit portions of code by default, then the compiler should give you a
warning for every place that occurs so the user knows exactly what is
happening.  Otherwise the cross-compiler cannot be trusted.



> >
> >A related issue is when setting a typed variable or passing in a parameter
> >to a function, it will do type coercion automatically in AS but that
> >behavior is lost when cross-compiling to JS.  For example, I have
> >situations like this where I now have to add manual type casting, and I
> >wish the compiler would do that automatically:
> >
> >var str:String = value_which_may_be_a_number;
>
> What error are you getting?  I thought the auto-conversion worked for both
> JS and AS.
>
> -Alex
>
>
Auto-conversion is currently not done for function parameters or variable
assignment.

AS input:
    public function testfunc(a:String, b:String):Array {
        var c:String = a;
        var d:String = b;
        return [typeof a, typeof b, typeof c, typeof d];
    }

JS output:
    testfunc = function(a, b) {
        var /** @type {string} */ c = a;
        var /** @type {string} */ d = b;
        return [typeof(a), typeof(b), typeof(c), typeof(d)];
    };

This code:
    var foo = testfunc;
    return foo(1,2)
will return ['string', 'string', 'string', 'string'] in ActionScript, but
['number', 'number', 'number', 'number'] in JavaScript.

Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Alex Harui <ah...@adobe.com>.

On 1/7/16, 5:24 PM, "Andy Dufilie" <an...@gmail.com> wrote:

>On Thu, Jan 7, 2016 at 4:55 PM, Alex Harui <ah...@adobe.com> wrote:
>
>> How many of you use the "as" keyword as part of a test?
>
>
>I have a huge code base and I use "as" / "is" everywhere (
>https://github.com/WeaveTeam/Weave). My code depends on it behaving the
>same way it does in ActionScript.  IMO, being able to easily check if an
>object extends or implements a class/interface is a huge advantage AS has
>over JS.
>
>
>> The reason I'm asking is because the use of "as" as become a negative
>> factor in several cases:
>> 1) In JS, it results in a function call
>>
>
>Yes. In ActionScript, using "as" actually sped up the code in certain
>situations, but in JS it is a performance hit.  This is a very common
>pattern in my code:
>
>if (obj is Thing1)
>    (obj as Thing1).foo(a,b);
>else if (obj is Thing2)
>    (obj as Thing2).bar(x,y);


There are no plans to change "is", just "as".  Are you using "as" as a
test or just "is".  In the example above, you are using "as" just to make
the compiler happy.


>I see "is" and "as" as highly useful features, and I think it would be a
>mistake to make the code cross-compile into something that behaves
>differently by default.  IMO if cross-compiled code behaves differently
>than the original then it's being mangled and can't be trusted.

That's the root of my question: how many folks us "as" to actually convert
data vs just make the compiler happy.  Again, no plans to change "is".

>
>A related issue is when setting a typed variable or passing in a parameter
>to a function, it will do type coercion automatically in AS but that
>behavior is lost when cross-compiling to JS.  For example, I have
>situations like this where I now have to add manual type casting, and I
>wish the compiler would do that automatically:
>
>var str:String = value_which_may_be_a_number;

What error are you getting?  I thought the auto-conversion worked for both
JS and AS.

-Alex


Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Andy Dufilie <an...@gmail.com>.
On Thu, Jan 7, 2016 at 4:55 PM, Alex Harui <ah...@adobe.com> wrote:

> How many of you use the "as" keyword as part of a test?


I have a huge code base and I use "as" / "is" everywhere (
https://github.com/WeaveTeam/Weave). My code depends on it behaving the
same way it does in ActionScript.  IMO, being able to easily check if an
object extends or implements a class/interface is a huge advantage AS has
over JS.


> The reason I'm asking is because the use of "as" as become a negative
> factor in several cases:
> 1) In JS, it results in a function call
>

Yes. In ActionScript, using "as" actually sped up the code in certain
situations, but in JS it is a performance hit.  This is a very common
pattern in my code:

if (obj is Thing1)
    (obj as Thing1).foo(a,b);
else if (obj is Thing2)
    (obj as Thing2).bar(x,y);

Each pair of is/as results in redundant processing since Language.as()
calls Language.is() internally, so I've been changing my code like this to
improve performance:

var thing1:Thing1 = obj as Thing1;
var thing2:Thing2 = obj as Thing2;
if (thing1)
    thing1.foo(a,b);
else if (thing2)
    thing2.bar(x,y);


> 2) As Om noted yesterday, it doesn't work for Native JS types
>

It does work with native types:

org.apache.flex.utils.Language.is(document.createElement('button'),
HTMLButtonElement)
-> true


> 3) It causes unnecessary class dependencies which complicates the
> goog.requires list
>

The class dependency is necessary if you need the "as" keyword to behave
the same way it does in ActionScript (like I do).


>
> Currently there is an @flexjsignorecoercion hack you can use to tell
> FalconJX to skip code-generation for an "as" operation.  However, we are
> adding more and more of these, and they are more frequently the cause of
> something not working, so I am thinking about flipping the logic and not
> generating code for any "as" operation unless you specifically ask for it
> via @flexjsgeneratecoercion or something like that.
>
> Thoughts?
> -Alex
>
>
I see "is" and "as" as highly useful features, and I think it would be a
mistake to make the code cross-compile into something that behaves
differently by default.  IMO if cross-compiled code behaves differently
than the original then it's being mangled and can't be trusted.

A related issue is when setting a typed variable or passing in a parameter
to a function, it will do type coercion automatically in AS but that
behavior is lost when cross-compiling to JS.  For example, I have
situations like this where I now have to add manual type casting, and I
wish the compiler would do that automatically:

var str:String = value_which_may_be_a_number;

Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Josh Tynjala <jo...@gmail.com>.
I was referring function casting when I talked about the runtime error that
occurs when it fails. I use that type of casting very frequently.

- Josh
On Jan 7, 2016 5:27 PM, "Alex Harui" <ah...@adobe.com> wrote:

>
>
> On 1/7/16, 2:11 PM, "Josh Tynjala" <jo...@gmail.com> wrote:
>
> >There are times when I consider it convenient to use "as" for casting and
> >check for null, but it's not frequently. Usually, I use "is" instead. Most
> >of the time, I use the other form of casting that results in a runtime
> >error when the cast fails. I hope that runtime error won't be removed. Or
> >at least could be turned on globally during debugging.
>
> Not sure which runtime error you are referring to.
>
> >
> >In regards to 2, is it not possible to walk the prototype chain of any
> >JavaScript object? Or am I misunderstanding?
>
> IIRC, instanceof was recently added to Language.is/as, but I think it
> won't work for interfaces.
>
> Another related question:  How many of you use "function" casting and
> expect it to fail?  As in:
>
>   var foo:SomeType = SomeType(somevar);
>
> Or
>
>   var bar:String = SomeType(somevar).someStringProperty;
>
> This also gets used to make the compiler happy and seems more readable
> than:
>
>   var bar:String = (somevar as SomeType).someStringProperty;
>
> If "SomeType(somevar)" is not in a try/catch it will throw an exception.
> How often are you relying on that vs just trying to make the compiler
> happy?
>
>
> -Alex
>
>

Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Alex Harui <ah...@adobe.com>.

On 1/7/16, 2:11 PM, "Josh Tynjala" <jo...@gmail.com> wrote:

>There are times when I consider it convenient to use "as" for casting and
>check for null, but it's not frequently. Usually, I use "is" instead. Most
>of the time, I use the other form of casting that results in a runtime
>error when the cast fails. I hope that runtime error won't be removed. Or
>at least could be turned on globally during debugging.

Not sure which runtime error you are referring to.

>
>In regards to 2, is it not possible to walk the prototype chain of any
>JavaScript object? Or am I misunderstanding?

IIRC, instanceof was recently added to Language.is/as, but I think it
won't work for interfaces.

Another related question:  How many of you use "function" casting and
expect it to fail?  As in:

  var foo:SomeType = SomeType(somevar);

Or
 
  var bar:String = SomeType(somevar).someStringProperty;

This also gets used to make the compiler happy and seems more readable
than:

  var bar:String = (somevar as SomeType).someStringProperty;

If "SomeType(somevar)" is not in a try/catch it will throw an exception.
How often are you relying on that vs just trying to make the compiler
happy?


-Alex


Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Josh Tynjala <jo...@gmail.com>.
There are times when I consider it convenient to use "as" for casting and
check for null, but it's not frequently. Usually, I use "is" instead. Most
of the time, I use the other form of casting that results in a runtime
error when the cast fails. I hope that runtime error won't be removed. Or
at least could be turned on globally during debugging.

In regards to 2, is it not possible to walk the prototype chain of any
JavaScript object? Or am I misunderstanding?

- Josh

On Thu, Jan 7, 2016 at 1:55 PM, Alex Harui <ah...@adobe.com> wrote:

> How many of you use the "as" keyword as part of a test?  IOW things like:
>
>  var foo:SomeType = someVar as SomeType;
>  if (foo == null)
>
> IMO, I have yet to use "as" in this way in the FlexJS framework. I just
> use it to make the compiler happy.  IOW things like:
>
>  var foo:SomeType = someVar as SomeType;
>  foo.someProp
>
> If foo really isn't of SomeType, I am going to get an NPE, but I know it
> will never be null, I am just casting/coercing so the compiler will check
> that someProp really exists on SomeType.
>
> The reason I'm asking is because the use of "as" as become a negative
> factor in several cases:
> 1) In JS, it results in a function call
> 2) As Om noted yesterday, it doesn't work for Native JS types
> 3) It causes unnecessary class dependencies which complicates the
> goog.requires list
>
> Currently there is an @flexjsignorecoercion hack you can use to tell
> FalconJX to skip code-generation for an "as" operation.  However, we are
> adding more and more of these, and they are more frequently the cause of
> something not working, so I am thinking about flipping the logic and not
> generating code for any "as" operation unless you specifically ask for it
> via @flexjsgeneratecoercion or something like that.
>
> Thoughts?
> -Alex
>
>

Re: [FALCONJX][FLEXJS] "as" keyword handling

Posted by Harbs <ha...@gmail.com>.
I personally always use “is” for type-testing. I’ve always considered using “as” and null testing as counter-intuitive.

I only use “as” for type casting to make the compiler happy.

I’m fine with switching it if there’s reason to do so.

On Jan 7, 2016, at 11:55 PM, Alex Harui <ah...@adobe.com> wrote:

> How many of you use the "as" keyword as part of a test?  IOW things like:
> 
> var foo:SomeType = someVar as SomeType;
> if (foo == null)
> 
> IMO, I have yet to use "as" in this way in the FlexJS framework. I just
> use it to make the compiler happy.  IOW things like:
> 
> var foo:SomeType = someVar as SomeType;
> foo.someProp
> 
> If foo really isn't of SomeType, I am going to get an NPE, but I know it
> will never be null, I am just casting/coercing so the compiler will check
> that someProp really exists on SomeType.
> 
> The reason I'm asking is because the use of "as" as become a negative
> factor in several cases:
> 1) In JS, it results in a function call
> 2) As Om noted yesterday, it doesn't work for Native JS types
> 3) It causes unnecessary class dependencies which complicates the
> goog.requires list
> 
> Currently there is an @flexjsignorecoercion hack you can use to tell
> FalconJX to skip code-generation for an "as" operation.  However, we are
> adding more and more of these, and they are more frequently the cause of
> something not working, so I am thinking about flipping the logic and not
> generating code for any "as" operation unless you specifically ask for it
> via @flexjsgeneratecoercion or something like that.
> 
> Thoughts?
> -Alex
>