Google Closure Library wants a typed init object, not an untyped event object.  
So it is opposite of what you say.  We are forced to use a typed object.  If I 
understand your recommendation, you are proposing to use untyped objects as 
passing them in as typed objects.  The more we encourage folks to type "{" in 
their code, the less portable their code will be to other platforms, and the 
IDEs will not be able to help without upgrades to the IDEs.

If you want to add checking to places that require passing in a plain object, 
you can use the "middle-ground" idea of using metadata, or you can do what 
Google Closure did and define an interface with the properties that should go 
in the object.  The latter is more portable to future runtimes and the IDEs can 
help catch mistakes.

My 2 cents,
-Alex

On 1/7/19, 1:07 AM, "Harbs" <harbs.li...@gmail.com> wrote:

    I don’t think I’m proposing defeating types.
    
    I’m suggesting we should have compile time type checking in cases where 
we’re forced to use untyped objects. This will *improve* type checking.
    
    In cases where it’s practical to have strongly typed runtime instances, I’m 
all for the runtime improvements.
    
    My $0.02,
    Harbs
    
    > On Jan 7, 2019, at 10:37 AM, Alex Harui <aha...@adobe.com.INVALID> wrote:
    > 
    > Some runtimes understand types.  We should not defeat that.  The runtime 
optimization of types is usually better than untyped stuff.  JS in the browser 
is an exception and may be only a temporary popular runtime in the long term.
    > 
    > The pattern I proposed (createBlobPropertyBag) is a platform-independent 
abstraction that allows SWF and future platform code  to actually generate a 
type where the JS code could get away with a plain object.  But maybe we should 
modify that proposal a bit so that the factory function takes optional 
initialization parameters as well.
    > 
    > Type-safety has some development-time overhead.  That's why folks like AS 
over Java.  You don't have to strongly-type everything.  Unfortunately, it 
isn't our call that Google has decided to strongly type the init objects in the 
browser.  Well, it is our call in that we can change the interfaces we 
generate, but I'm not sure we should.  We want to have folks write code that 
can work on other runtimes, and future runtimes are likely to understand types. 
 Using plain objects might seem easy/fast now, but it is likely to be a problem 
in the future.
    > 
    > I believe if we use this factory pattern, you should also never waste 
time spell checking plain objects ever again.  The IDEs already know how to 
code-hint an interface.  They don't know what to do when you type "{".  IOW, if 
you type:
    > 
    >    new window.Event("foo", {
    > 
    > the current Royale  IDEs will not help you, but if you instead use the 
proposed pattern:
    > 
    >    new window.Event("foo", createEventInit(
    > 
    > the IDE will offer the list of init properties.  And your code will work 
on future runtime/platforms.
    > 
    > I think it would be a substantial change to the compiler to allow plain 
objects where an interface is expected.  The parameters are checked in the 
ABCReducer, even for JS output.  The midde-ground would be to say the parameter 
is an Object and use metadata to tell the JS transpiler to check the properties 
against an interface.  I don't think we check the ArrayElementType metadata 
today, but we could someday if we don't fake generics.  But again, that code 
has little chance of working on future platforms without more layering 
underneath.
    > 
    > My 2 cents,
    > -Alex
    > 
    > On 1/6/19, 11:37 PM, "Harbs" <harbs.li...@gmail.com 
<mailto:harbs.li...@gmail.com>> wrote:
    > 
    >    There are three advantages to Typescript-style interfaces:
    > 
    >    1. There’s less typing and passing around objects is easier.
    >    2. Plain objects are actually type checked. Instead of lying to the 
compiler by using “as”, the compiler can check that the required properties 
exist and are spelled correctly.
    >    3. They completely disappear at runtime. “True” interfaces add bulk at 
runtime needed for reflection and the like.
    > 
    >> Why would it be huge?
    > 
    >    From experience, the time spent casting and spellchecking plain 
objects is very time consuming when you have a need for lots of plain objects. 
This happens more often than you’d like in the “real world”…
    > 
    >    I’m envisioning two types of interfaces:
    > 
    >    1. Classic interfaces like we have now. This would offer runtime 
checking and reflection. It would also offer type safety for future strongly 
typed languages.
    >    2. “Dynamic” or “Virtual” interfaces would offer type checking for 
dynamic objects at compile-time only.
    > 
    >    I’m thinking of maybe decorating interfaces with [Dynamic] or 
[Virtual] to tell the compiler that it’s a “fake” interface.
    > 
    >    Maybe we can support these kinds of interfaces in SWF output by simply 
converting the type to “Object”. You wouldn’t get the runtime checking, but 
you’d still get the compile-time checking.
    > 
    >    It might be possible to do something similar in Swift or Java, etc. 
too.
    > 
    >    Thoughts?
    > 
    >    Harbs
    > 
    >> On Jan 7, 2019, at 8:37 AM, Alex Harui <aha...@adobe.com.INVALID> wrote:
    >> 
    >> Feel free to make the changes.  I personally am trying to ensure 
type-safety instead of weaken it.  It is only this case where the cost is 
starting to outweigh the benefits.
    >> 
    >> Why would it be huge?  Why should we encourage the use of plain objects 
intead of classes?  It feels to JS-specific.  Future runtimes might have strict 
type-safety.
    >> 
    >> -Alex
    >> 
    >> On 1/6/19, 10:05 PM, "Harbs" <harbs.li...@gmail.com> wrote:
    >> 
    >>   Personally, I would like to have us support TypeScript-type interfaces 
where plain objects that have the correct properties pass the check.[1]
    >> 
    >>   I have no idea how difficult this would be for SWF-compatible code, 
but even if it’s supported for JS-only code, that would be a huge production 
booster. 
    >> 
    >>   My $0.02,
    >>   Harbs
    >> 
    >>   
[1]https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.typescriptlang.org%2Fdocs%2Fhandbook%2Finterfaces.html&amp;data=02%7C01%7Caharui%40adobe.com%7C9f1a45958c444c8abe8f08d6747f990e%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C636824488728171741&amp;sdata=GaZG%2B6cvLmlan2L8u2Z9x%2BrKLa%2FeX6ROPfTY%2B%2FeebrY%3D&amp;reserved=0
 
<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.typescriptlang.org%2Fdocs%2Fhandbook%2Finterfaces.html&amp;data=02%7C01%7Caharui%40adobe.com%7C9f1a45958c444c8abe8f08d6747f990e%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C636824488728171741&amp;sdata=GaZG%2B6cvLmlan2L8u2Z9x%2BrKLa%2FeX6ROPfTY%2B%2FeebrY%3D&amp;reserved=0>
 
<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.typescriptlang.org%2Fdocs%2Fhandbook%2Finterfaces.html&amp;data=02%7C01%7Caharui%40adobe.com%7C9f1a45958c444c8abe8f08d6747f990e%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C636824488728171741&amp;sdata=GaZG%2B6cvLmlan2L8u2Z9x%2BrKLa%2FeX6ROPfTY%2B%2FeebrY%3D&amp;reserved=0
 
<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.typescriptlang.org%2Fdocs%2Fhandbook%2Finterfaces.html&amp;data=02%7C01%7Caharui%40adobe.com%7C9f1a45958c444c8abe8f08d6747f990e%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C636824488728171741&amp;sdata=GaZG%2B6cvLmlan2L8u2Z9x%2BrKLa%2FeX6ROPfTY%2B%2FeebrY%3D&amp;reserved=0>>
    >> 
    >>> On Jan 7, 2019, at 6:03 AM, Alex Harui <aha...@adobe.com.INVALID 
<mailto: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 
<mailto:yishayj...@hotmail.com>> wrote:
    >>> 
    >>>  Sounds good, feel free to revert.
    >>> 
    >>> 
    >>> 
    >>>  ________________________________
    >>>  From: Alex Harui <aha...@adobe.com.INVALID 
<mailto:aha...@adobe.com.INVALID>>
    >>>  Sent: Thursday, December 27, 2018 3:43:45 AM
    >>>  To: dev@royale.apache.org <mailto:dev@royale.apache.org>; 
comm...@royale.apache.org <mailto: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 <mailto:yish...@apache.org>" 
<yish...@apache.org <mailto: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&amp;data=02%7C01%7Caharui%40adobe.com%7C9f1a45958c444c8abe8f08d6747f990e%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C636824488728171741&amp;sdata=pberSPs1ZHsGN75bYuhi1hEN5hVccvdF2aC9r4K%2F0hI%3D&amp;reserved=0
 
<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitbox.apache.org%2Frepos%2Fasf%2Froyale-asjs.git&amp;data=02%7C01%7Caharui%40adobe.com%7C9f1a45958c444c8abe8f08d6747f990e%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C636824488728171741&amp;sdata=pberSPs1ZHsGN75bYuhi1hEN5hVccvdF2aC9r4K%2F0hI%3D&amp;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