<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Hi Brandon,<div class=""><br class=""></div><div class="">Thanks for writing this up!</div><div class=""><br class=""></div><div class="">My personal feeling is that I’d rather ES not have static typing of this form.  I believe it makes the language substantially more complex, and to me it feels best to try to minimize the growth of the language in order to ensure that those things that we do add are added in a compatible and sound way.  Also, I wonder if static typing wouldn’t work out better if instead of extending ES, you found a way to instead make wasm (<a href="https://www.w3.org/community/webassembly/" class="">https://www.w3.org/community/webassembly/</a>) powerful enough to handle the language that you want.  The benefit of that route is that (1) there is already support behind wasm and what I see as a broad desire to enable wasm to handle statically-typed object-oriented/functional languages, and (2) it’s a clean slate, so a proposal doesn’t have to worry about the compatibility issues.</div><div class=""><br class=""></div><div class="">Personal feelings aside, I’ve got questions/comments:</div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jul 18, 2015, at 12:35 PM, Brandon Andrews <<a href="mailto:warcraftthreeft@sbcglobal.net" class="">warcraftthreeft@sbcglobal.net</a>> wrote:</div><br class="Apple-interchange-newline"><div class="">ES8 Proposal: Optional Static Typing<br class=""><br class="">It was once said by Brendan Eich that 'Types are hard. This doesn't mean "no, never".' It's been a while since ES4. With ES6's TypedArrays and classes finalized and ES7 SIMD getting experimental tests, ECMAScript is in a good place to finally discuss types again. The demand for types as a different approach to code has been so strong in the past few years that separate languages have been created to deal with the perceived shortcomings. Types won't be an easy discussion, nor an easy addition, since they touch a large amount of the language; however, they are something that needs rigorous discussion. I'm hoping this initial proposal can be a way of pushing the ball forward. Turning this into an official proposal discussed by TC39 is the goal. This could very well be most of ES8 due to the complexity.<br class=""><br class="">Since it would be potentially years before this would be implemented this proposal includes a new keyword "enum" for enumerated types and the following types:<br class=""><br class="">number<br class="">bool<br class="">string<br class="">object<br class="">int8/16/32/64<br class="">uint8/16/32/64<br class=""></div></blockquote><div><br class=""></div><div>I agree that these types are fundamental.</div><br class=""><blockquote type="cite" class=""><div class="">bignum</div></blockquote><blockquote type="cite" class=""><div class="">float16/32/64/80/128<br class="">decimal32/64/128<br class="">int8x16/16x8/32x4/64x2/8x32/16x16/32x8/64x4<br class="">uint8x16/16x8/32x4/64x2/8x32/16x16/32x8/64x4<br class="">float32x4/64x2/32x8/64x4<br class="">rational<br class="">complex<br class=""></div></blockquote><div><br class=""></div><div>Are these types baked into the language, or can these types be user-defined?  It’s fine if they are user-definable but present in the standard library, but it seems weird if these were baked in at the language level.</div><br class=""><blockquote type="cite" class=""><div class="">any<br class="">void<br class=""><br class="">These types bring ECMAScript in line or surpasses the type systems in most languages. For developers it cleans up a lot of the syntax, as described later, for TypedArrays, SIMD, and working with number types (floats vs signed and unsigned integers). It also allows for new language features like function overloading and a clean syntax for operator overloading. For implementors, added types offer a way to better optimize the JIT when specific types are used. For languages built on top of Javascript this allows more explicit type usage and closer matching to hardware.<br class=""><br class="">In theory the following current keywords could be deprecated in the long-term: Boolean, Number, String, Object, and the TypedArray objects. Their methods and features would be rolled into the new type system.<br class=""></div></blockquote><div><br class=""></div><div>Deprecating these would be almost impossible given how widely used they are.  We still have to support JS idioms from before ES1 standardization (like function.arguments).</div><br class=""><blockquote type="cite" class=""><div class=""><br class="">One of the first complications with types is typeof's behavior. All of the above types would return their string conversion including bool. (In my experience "boolean" is seen as verbose among C++ and C# developers. Breaking this part of Java's influence probably wouldn't hurt to preserve consistency for the future).<br class=""><br class="">The next few parts cover type features that should be supported. The examples aren't meant to be exhaustive but rather show parts of the language that require new grammar and discussion.<br class=""><br class="">Support for nullable types.<br class=""><br class="">var foo:uint8? = null;<br class=""><br class="">Support for resizable typed arrays.<br class=""><br class="">var foo:uint8[];<br class="">foo.push(1);<br class="">var bar:uint8[] = [1, 2, 3, 4];<br class=""></div></blockquote><div><br class=""></div><div>Currently, typed arrays are not resizable.  Are you suggesting that this is a separate type from the existing typed array types?</div><br class=""><blockquote type="cite" class=""><div class=""><br class="">Support for fixed-length typed arrays:<br class=""><br class="">var foo:uint8[4];<br class="">foo.push(0); // invalid<br class="">foo.pop(); // invalid<br class="">var bar:uint8[4] = [1, 2, 3, 4];<br class=""></div></blockquote><div><br class=""></div><div>How do you propose to handle:</div><div><br class=""></div><div>var foo:uint8[4] = …;</div><div>var bar:uint8[8] = …;</div><div>if (p) return foo; else return bar;</div><div><br class=""></div><div>Is this a type error, or does the function have some type?  This is an important question.  Usually, non-resizable arrays do not store the length as part of the type, since preserving a relationship between length and type is generally a hard problem.  The trivial approach - making the above be a type error - was done in Pascal and it was very restrictive.  For example, it makes it hard to write a reusable function over non-resizable arrays, since every user will have to agree on the length.</div><br class=""><blockquote type="cite" class=""><div class=""><br class="">The ability to type any variable including arrow functions.<br class=""><br class="">var foo:uint8 = 0;<br class="">var foo = uint8(0); // Cast<br class=""><br class="">var foo:(int32, string):string; // hold a reference to a signature of this type<br class="">var foo = (s:string, x:int32) => s + x; // implicit return type of string<br class="">var foo = (x:uint8, y:uint8):uint16 => x + y; // explicit return type<br class=""><br class="">Function signatures with constraints.<br class=""><br class="">function Foo(a:int32, b:string, c:bignum[], callback:(bool, string) = (b, s = 'none') => b ? s : ''):int32 { }<br class=""><br class="">Simplified binary shifts for integers:<br class=""><br class="">var a:int8 = -128;<br class="">a >> 1; // -64, sign extension<br class="">var b:uint8 = 128;<br class="">b >> 1; // 64, no sign extension as would be expected with an unsigned type<br class=""><br class="">Destructing assignment casting:<br class=""><br class="">[a:uint32, b:float32] = Foo();<br class=""></div></blockquote><div><br class=""></div><div>What do you propose should happen if Foo does not return these types?</div><br class=""><blockquote type="cite" class=""><div class=""><br class="">Function overloading:<br class=""><br class="">function Foo(x:int32[]) { return "int32"; }<br class="">function Foo(s:string[]) { return "string"; }<br class="">Foo(["test"]); // “string"<br class=""></div></blockquote><div><br class=""></div><div>Currently, a function declaration causes the creation of a variable that points to that function.  What would the Foo variable point to in this case?</div><br class=""><blockquote type="cite" class=""><div class=""><br class="">Constructor overloading:<br class=""><br class="">// 4 byte object<br class="">value class MyType<br class="">{<br class="">    x:float32; // Able to define members outside of the constructor<br class="">    constructor(x:float32)<br class="">    {<br class="">        this.x = x;<br class="">    }<br class="">    constructor(y:uint32)<br class="">    {<br class="">        this.x = float32(y) * 2;<br class="">    }<br class="">}<br class=""></div></blockquote><div><br class=""></div><div>Similar issue here.</div><br class=""><blockquote type="cite" class=""><div class=""><br class="">Number would convert implicitly with precedence given to decimal, float128/80/64/32/16, uint64/32/16/8, int64/32/16/8. (Or whichever order makes the most sense). As an example using the MyType class:<br class=""><br class="">var t:MyType = 1; // float32 constructor call<br class="">var t:MyType = uint32(1); // uint32 constructor called<br class=""><br class="">Implicit constructors could also be added to the proposed SIMD classes to go from a scalar to a vector.<br class=""><br class="">var v:float32x4 = 1; // Equivalent to an ES7 SIMD splat, so var v = float32x4(1, 1, 1, 1);<br class=""><br class="">Implicit array conversion would also exist:<br class=""><br class="">var t:MyType[] = [1, 2, 3, uint32(1)];<br class=""><br class="">Types would function exactly like you'd expect with decorators in ES7, but with the addition that they can be overloaded:<br class=""><br class="">function AlwaysReturnValue(value:uint32)<br class="">{<br class="">    return function (target, name, descriptor)<br class="">    {<br class="">        descriptor.get = () => value;<br class="">        return descriptor;<br class="">    }<br class="">}<br class="">function AlwaysReturnValue(value:float32) { /* ... */ }<br class=""><br class="">Class example and operator overloading:<br class=""><br class="">class Vector2d<br class="">{<br class="">    x: float32;<br class="">    y: float32;<br class="">    constructor(x:float32 = 0, y:float32 = 0)<br class="">    {<br class="">        this.x = x;<br class="">        this.y = y;<br class="">    }<br class="">    Length():float32<br class="">    {<br class="">        return Math.sqrt(x * x + y * y); // uses Math.sqrt(v:float32):float32 due to input and return type<br class="">    }<br class="">    get X():float64 // return implicit cast<br class="">    {<br class="">        return this.x;<br class="">    }<br class="">    set X(x:float64)<br class="">    {<br class="">        this.x = x / 2;<br class="">    }<br class="">    operator +(v:vector2d)<br class="">    {<br class="">        return new vector2d(this.x + v.x, this.y + v.y);<br class="">    }<br class="">    operator ==(v:vector2d)<br class="">    {<br class="">        // equality check between this and v<br class="">    }<br class="">}<br class=""><br class="">Partial class in MyClass.js defining extensions to Vector2d:<br class=""><br class="">class Vector2d<br class="">{<br class="">    operator ==(v:MyClass)<br class="">    {<br class="">        // equality check between this and MyClass<br class="">    }<br class="">    operator +(v:MyClass)<br class="">    {<br class="">        return v + this; // defined in terms of the MyClass operator<br class="">    }<br class="">}<br class=""><br class="">Enumerations with enum that support any type except function signatures.<br class=""><br class="">enum Count { Zero, One, Two }; // Starts at 0<br class="">var c:Count = Count.Zero;<br class=""><br class="">enum Count { One = 1, Two, Three }; // Two is 2 since these are sequential<br class="">var c:Count = Count.One;<br class=""><br class="">enum Count:float32 { Zero, One, Two };<br class=""><br class="">Custom sequential function (these aren't closures):<br class=""><br class="">enum Count:float32 { Zero = (index, name) => index * 100, One, Two }; // 0, 100, 200<br class="">enum Count:string { Zero = (index, name) => name, One, Two = (index, name) => name.toLowerCase(), Three }; // "Zero", "One", "two", "three"<br class=""><br class="">Index operator:<br class=""><br class="">enum Count { Zero, One, Two };<br class="">Count[0];<br class=""><br class="">Get enum value as string:<br class=""><br class="">// Not sure what the syntax for this would be.<br class=""><br class="">Generic functions:<br class=""><br class="">function Foo<T>(foo:T):T<br class="">{<br class="">    var bar:T;<br class="">}<br class=""><br class="">Generic classes:<br class=""><br class="">class Vector2d<T><br class="">{<br class="">    x: T;<br class="">    y: T;<br class="">    constructor(x:T = 0, y:T = 0) // T could be inferred, but that might be asking too much. In any case T must have a constructor supporting a parameter 0 if this is a class.<br class="">    {<br class="">        this.x = x;<br class="">        this.y = y;<br class="">    }<br class="">}<br class=""><br class="">Generic constraints aren't defined here but would need to be. TypeScript has their extends type syntax. Being able to constrain T to an interface seems like an obvious requirement. Also being able to constrain to a list of specific types or specifically to numeric, floating point, or integer types. Another consideration is being able to support a default type. Also generic specialization for specific types that require custom definitions. There's probably more to consider, but those are the big ideas for generics.<br class=""></div></blockquote><div><br class=""></div><div>Do you propose that generics behave as if there was type erasure under the hood, or as if every instantiation splats out a new class?  If the latter, what does the expression “Vector2d” without any instantiation give?  The challenge here is that your proposal in general, and generics in particular, seem like they would have trouble interoperating with old ES code that does not have types.  I think the big problem to solve here is how to make generics work properly while still being optional.</div><br class=""><blockquote type="cite" class=""><div class=""><br class="">Typedefs or aliases for types are a requirement. Not sure what the best syntax is for proposing these. There's a lot of ways to approach them. TypeScript has a system, but I haven't see alternatives so it's hard for me to judge if it's the best or most ideal syntax.<br class=""><br class="">Undecided Topics:<br class=""><br class="">I left value type classes out of this discussion since I'm still not sure how they'll be proposed. Doesn't sound like they have a strong proposal still or syntax.<br class=""><br class="">Unions are another topic not covered mostly because the syntax is very subjective. Without an added keyword the following might work in the grammar. The example uses an anonymous group unioned with an array of 3 elements. Using a class with x, y, and z members would also work. (Or using an interface syntax if one is added could work).<br class=""><br class="">class Vector3d<br class="">{<br class="">    {<br class="">        {<br class="">            x: float32;<br class="">            y: float32;<br class="">            z: float32;<br class="">        }<br class="">        a: float32[3];<br class="">    }<br class="">}<br class=""><br class="">Another example would be:<br class=""><br class="">class Color<br class="">{<br class="">    {<br class="">        {<br class="">            Red: float32;<br class="">            Green: float32;<br class="">            Blue: float32;<br class="">            Alpha: float32;<br class="">        }<br class="">        Vector: float32x4;<br class="">    }<br class="">}<br class=""><br class="">The last topic not covered is if there should be new syntax for TypedArray views.<br class=""><br class="">var a1:uint32[] = [2, 0, 1, 3];<br class="">var a2:uint64[] = a1(1, 2); // Creates a view of a1 at offset 1 with 2 elements. So [0, 1].<br class=""><br class="">That might be asking too much though. In a very compact form:<br class=""><br class="">var foo = ((uint64[])a1(1, 2))[0]; // foo would be 1<br class=""><br class="">This has been brought up before, but possible solutions due to compatability issues would be to introduce "use types"; or since ES6 has them Brenden once suggested something like:<br class=""><br class=""><blockquote type="cite" class="">import {int8, int16, int32, int64} from "@valueobjects";<br class=""></blockquote><br class="">This concludes my proposal on types and the many facets of the language that would be potentially touched. The goal is essentially to turn this, or something similar, into a rough draft. Essentially build a foundation to start from expanding on edge cases and changes required in each part of the language. I'm sure with enough minds looking at each section this could be very well defined by the time ES8 is being considered.<br class=""><br class="">Previous discussions:<br class="">This one contains a lot of my old thoughts (at least the stuff from 8 months ago). <a href="https://esdiscuss.org/topic/proposal-for-new-floating-point-and-integer-data-types" class="">https://esdiscuss.org/topic/proposal-for-new-floating-point-and-integer-data-types</a><br class=""><a href="https://esdiscuss.org/topic/optional-strong-typing" class="">https://esdiscuss.org/topic/optional-strong-typing</a><br class=""><br class="">https://esdiscuss.org/topic/optional-argument-types<br class="">_______________________________________________<br class="">es-discuss mailing list<br class="">es-discuss@mozilla.org<br class="">https://mail.mozilla.org/listinfo/es-discuss<br class=""></div></blockquote></div><br class=""></div></body></html>