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&data=02%7C01%7Caharui%40adobe.com%7C171969f4b3d545dd34f408d67472ed99%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C636824434318742933&sdata=sSZMOAaiWiux5KcvkOCQn3oYc4Xl1970UsFxSlCLNsw%3D&reserved=0 >> >> <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.typescriptlang.org%2Fdocs%2Fhandbook%2Finterfaces.html&data=02%7C01%7Caharui%40adobe.com%7C171969f4b3d545dd34f408d67472ed99%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C636824434318742933&sdata=sSZMOAaiWiux5KcvkOCQn3oYc4Xl1970UsFxSlCLNsw%3D&reserved=0> >> >> <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.typescriptlang.org%2Fdocs%2Fhandbook%2Finterfaces.html&data=02%7C01%7Caharui%40adobe.com%7C171969f4b3d545dd34f408d67472ed99%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C636824434318742933&sdata=sSZMOAaiWiux5KcvkOCQn3oYc4Xl1970UsFxSlCLNsw%3D&reserved=0 >> >> <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.typescriptlang.org%2Fdocs%2Fhandbook%2Finterfaces.html&data=02%7C01%7Caharui%40adobe.com%7C171969f4b3d545dd34f408d67472ed99%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C636824434318742933&sdata=sSZMOAaiWiux5KcvkOCQn3oYc4Xl1970UsFxSlCLNsw%3D&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&data=02%7C01%7Caharui%40adobe.com%7C171969f4b3d545dd34f408d67472ed99%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C636824434318752951&sdata=m9McisyKOiiy7%2B4fvcLTy965pevXn5RwKJ8C0b2T2EI%3D&reserved=0 >>> >>> <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitbox.apache.org%2Frepos%2Fasf%2Froyale-asjs.git&data=02%7C01%7Caharui%40adobe.com%7C171969f4b3d545dd34f408d67472ed99%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C636824434318752951&sdata=m9McisyKOiiy7%2B4fvcLTy965pevXn5RwKJ8C0b2T2EI%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");