This feels very wrong to me.

Having to implement an interface or create a conversion function to pass 
parameters to native JS APIs from ActionScript is going to be a massively, 
enormously, gigantic headache for everyone. Developers aren't going to want to 
write boilerplate to use native APIs. Especially when they're looking at a 
library's example code written in JavaScript and seeing how much simpler it is 
than what they need to do in ActionScript.

Even if the Royale team proposes to provide all of the classes/functions for 
the community, that's still a pretty big headache for whoever has to do it and 
keep everything up to date... assuming that it can be done in an automated way. 
There's quite a lot of interfaces that need to be accounted for.

One of the most frustrating things to me is looking at this code, which would 
be accepted by Closure compiler, if written in pure JS:

> var blob = new Blob([text], { type: 'text/plain' });
> customEvent = new window.Event(type, {bubbles: bubbles, cancelable: 
> cancelable});

Closure compiler is able to take an object literal and verify that it meets the 
requirements of an interface, but ActionScript cannot. ActionScript needs a 
real implementation... or a conversion function that tricks the typing system, 
which isn't ideal.

I think that there should be a certain philosophy to exposing native platform 
APIs to ActionScript:

If the platform is already strongly typed, similarly to ActionScript, keep the 
strong types. The APIs are probably designed to make providing an 
implementation for a parameter typed as an interface relatively easy. Either 
that, or the native language requires the same amount of boilerplate that we'll 
need in ActionScript, so there's no added disadvantage to choosing ActionScript.

If the platform is dynamic, expose the APIs in ActionScript as dynamic. In 
other words, a function parameter typed as an "interface" in Closure's externs 
should be typed as Object in ActionScript because interfaces don't actually 
exist in JavaScript. Closure may add the concept of interfaces, but as I 
mentioned, they don't behave the same way as ActionScript's, so trying to 
replace them with ActionScript interfaces makes those APIs much more difficult 
to use.

- Josh

On 2019/01/07 04:03:37, Alex Harui <aha...@adobe.com.INVALID> wrote: 
> I just fixed a bug in the compiler, and now we are getting more of these 
> implicit coercion errors because the recent Google Closure Typedefs now 
> specify interfaces as parameters to certain contructors (or maybe they always 
> did and the compiler is now getting better at catching these errors).
> 
> Code that looked like:
> 
>     var blob:Blob = new Blob([text], { type: 'text/plain' });
> 
> or
> 
>     customEvent = new window.Event(type, {bubbles: bubbles, cancelable: 
> cancelable});
> 
> now results in a compiler error because the plain objects don't implement 
> whatever interface of properties the constructor expects.  I think Google 
> Closure did this so that the properties in the plain object don't get renamed 
> by the minifier.
> 
> One solution, that Yishay tried in this commit was simply to lie to the 
> compiler and tell it that the plain object was a BlobPropertyBag.  And while 
> that is the "least amount of code" solution, I didn’t like that solution 
> because it looks funny to have lots of places in our code where a plain 
> object is coerced to a type.
> 
> So, I went and created classes that implement BlobPropertyBag and other 
> interfaces.  I didn't like adding the weight of additional class definitions 
> but the classes I did were small, just a couple of properties.  However, for 
> Event,there is a pretty big list of properties just to specify bubbles and 
> cancelable.  The compiler was not catching that plain object before, but now 
> with the fix I just made it will.  And I’m not sure it is worth adding a 
> large class with lots of properties.
> 
> So, I thought of a third idea which is a hack between what Yishay tried and 
> the interface implementations I did, which is to have a factory that returns 
> an instance of the interface, but actually returns a plain object.  As long 
> as no code actually tests that the instance implements the interface, it 
> should work.  And that would localize the coercion of a plain object to an 
> interface in relatively few known places in our code.
> 
> The pattern would be to create a top-level factory function() unless it makes 
> sense to add it to a class so for Blob it might look like:
> 
> /**
>  * @royaleignorecoercion BlobPropertyBag
>  */
> public function createBlobPropertyBag():BlobPropertyBag
> {
>     // return a plain object but fool the compiler into thinking it is an 
> implementation of the interface
>     return {} as BlobPropertyBag;
> }
> 
> IMO, this also future-proofs the code in case we ever run where there is 
> runtime type-checking and need to someday return a real concrete instance 
> that implements the interface.
> 
> Thoughts?
> -Alex
> 
> 
> On 12/26/18, 11:02 PM, "Yishay Weiss" <yishayj...@hotmail.com> wrote:
> 
>     Sounds good, feel free to revert.
>     
>     
>     
>     ________________________________
>     From: Alex Harui <aha...@adobe.com.INVALID>
>     Sent: Thursday, December 27, 2018 3:43:45 AM
>     To: dev@royale.apache.org; comm...@royale.apache.org
>     Subject: Re: [royale-asjs] branch develop updated: Fix implicit coercion 
> error
>     
>     I don't think we should hack it like this.  Casting a plain object to a 
> type makes the code look strange, and it might not minify correctly.  I have 
> a different fix I hope to put in shortly where we actually pass in an 
> instance of the BlogPropertyBag.
>     
>     -Alex
>     
>     On 12/26/18, 6:57 AM, "yish...@apache.org" <yish...@apache.org> wrote:
>     
>         This is an automated email from the ASF dual-hosted git repository.
>     
>         yishayw pushed a commit to branch develop
>         in repository 
> https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitbox.apache.org%2Frepos%2Fasf%2Froyale-asjs.git&data=02%7C01%7Caharui%40adobe.com%7C00f548a683d34a9c88b508d66bc93265%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C636814909228765885&sdata=5DaM3aljpj1rk4FD0KBSzLWrfi9jzCOmbnAvfy2me8o%3D&reserved=0
>     
>     
>         The following commit(s) were added to refs/heads/develop by this push:
>              new 2f127d4  Fix implicit coercion error
>         2f127d4 is described below
>     
>         commit 2f127d459ee807f197950e11af947c623c270369
>         Author: DESKTOP-RH4S838\Yishay <yishayj...@hotmail.com>
>         AuthorDate: Wed Dec 26 16:57:33 2018 +0200
>     
>             Fix implicit coercion error
>         ---
>          
> .../src/main/royale/org/apache/royale/storage/file/DataOutputStream.as  | 2 +-
>          
> .../apache/royale/storage/providers/AndroidExternalStorageProvider.as   | 2 +-
>          .../royale/org/apache/royale/storage/providers/WebStorageProvider.as 
>    | 2 +-
>          3 files changed, 3 insertions(+), 3 deletions(-)
>     
>         diff --git 
> a/frameworks/projects/Storage/src/main/royale/org/apache/royale/storage/file/DataOutputStream.as
>  
> b/frameworks/projects/Storage/src/main/royale/org/apache/royale/storage/file/DataOutputStream.as
>         index cff76eb..55eab71 100644
>         --- 
> a/frameworks/projects/Storage/src/main/royale/org/apache/royale/storage/file/DataOutputStream.as
>         +++ 
> b/frameworks/projects/Storage/src/main/royale/org/apache/royale/storage/file/DataOutputStream.as
>         @@ -117,7 +117,7 @@ public class DataOutputStream extends 
> EventDispatcher implements IDataOutput
>              public function writeText(text:String):void
>              {
>                      COMPILE::JS {
>         -                   var blob:Blob = new Blob([text], { type: 
> 'text/plain' });
>         +                   var blob:Blob = new Blob([text], { type: 
> 'text/plain' } as BlobPropertyBag);
>                              _fileWriter.write(blob);
>                      }
>                      COMPILE::SWF {
>         diff --git 
> a/frameworks/projects/Storage/src/main/royale/org/apache/royale/storage/providers/AndroidExternalStorageProvider.as
>  
> b/frameworks/projects/Storage/src/main/royale/org/apache/royale/storage/providers/AndroidExternalStorageProvider.as
>         index ea79a5b..cf05a73 100644
>         --- 
> a/frameworks/projects/Storage/src/main/royale/org/apache/royale/storage/providers/AndroidExternalStorageProvider.as
>         +++ 
> b/frameworks/projects/Storage/src/main/royale/org/apache/royale/storage/providers/AndroidExternalStorageProvider.as
>         @@ -199,7 +199,7 @@ package org.apache.royale.storage.providers
>                                                                      
> _target.dispatchEvent(newEvent);
>                                                              };
>     
>         -                                                   var blob:Blob = 
> new Blob([text], { type: 'text/plain' });
>         +                                                   var blob:Blob = 
> new Blob([text], { type: 'text/plain' } as BlobPropertyBag);
>                                                              
> fileWriter.write(blob);
>                                                      }, function(e):void {
>                                                              var 
> errEvent:FileErrorEvent = new FileErrorEvent("ERROR");
>         diff --git 
> a/frameworks/projects/Storage/src/main/royale/org/apache/royale/storage/providers/WebStorageProvider.as
>  
> b/frameworks/projects/Storage/src/main/royale/org/apache/royale/storage/providers/WebStorageProvider.as
>         index 1632bfa..dd9c84c 100644
>         --- 
> a/frameworks/projects/Storage/src/main/royale/org/apache/royale/storage/providers/WebStorageProvider.as
>         +++ 
> b/frameworks/projects/Storage/src/main/royale/org/apache/royale/storage/providers/WebStorageProvider.as
>         @@ -199,7 +199,7 @@ package org.apache.royale.storage.providers
>                                                                      
> _target.dispatchEvent(newEvent);
>                                                              };
>     
>         -                                                   var blob:Blob = 
> new Blob([text], { type: 'text/plain' });
>         +                                                   var blob:Blob = 
> new Blob([text], { type: 'text/plain' } as BlobPropertyBag);
>                                                              
> fileWriter.write(blob);
>                                                      }, function(e):void {
>                                                              var 
> errEvent:FileErrorEvent = new FileErrorEvent("ERROR");
>     
>     
>     
>     
> 
> 
> 

Reply via email to