Two things:

I heard Gilad Bracha in ECOOP to say [paraphrase] "optional typing is great to help with documentation, and to help the tools; but it should not touch the runtime". This is what I take for my own as well, nicely said. Your overload proposition, though, changes the language so that this would need to touch the runtime. It seems there are two distinct view on bringing static typing in to dynamically-typed languages: one of them in line with the aformentioned, the other taking over the semantic and runtime as well. There are also two terms: "optional typing" and "gradual typing". I really don't know if those are defined precisely, but there seemed to be a sentiment that "optional typing" is the Gilad-Brachaish Strongtalk-like view, and "gradual typing" is the view that actually changes the semantics of the language and the runtime. What I wanted to say, is, that maybe this thread should be called "ES8 Proposal: Gradual Static Typing".

And I forgot the second one. Though I personally think changing the semantics (do gradual typing) would change the language to something very different and may complicate the good old duck-typing way of doing things. Truly optional typing, in the sense of "help the tools and document" is good, though. But it is completely different debate (some foods for though: 1. We have JSDoc which already does that - we can type-annotate and tools do the work; 2. An eye-opener is to learn that there is distinction between nominal types and structural types. Does it not suit ES, as a duck-typing language, to have optional structural typing instead of optional nominal typing?).

Herby


Brandon Andrews wrote:
ES8 Proposal: Optional Static Typing

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.

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:

number
bool
string
object
int8/16/32/64
uint8/16/32/64
bignum
float16/32/64/80/128
decimal32/64/128
int8x16/16x8/32x4/64x2/8x32/16x16/32x8/64x4
uint8x16/16x8/32x4/64x2/8x32/16x16/32x8/64x4
float32x4/64x2/32x8/64x4
rational
complex
any
void

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.

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.

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).

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.

Support for nullable types.

var foo:uint8? = null;

Support for resizable typed arrays.

var foo:uint8[];
foo.push(1);
var bar:uint8[] = [1, 2, 3, 4];

Support for fixed-length typed arrays:

var foo:uint8[4];
foo.push(0); // invalid
foo.pop(); // invalid
var bar:uint8[4] = [1, 2, 3, 4];

The ability to type any variable including arrow functions.

var foo:uint8 = 0;
var foo = uint8(0); // Cast

var foo:(int32, string):string; // hold a reference to a signature of this type
var foo = (s:string, x:int32) =>  s + x; // implicit return type of string
var foo = (x:uint8, y:uint8):uint16 =>  x + y; // explicit return type

Function signatures with constraints.

function Foo(a:int32, b:string, c:bignum[], callback:(bool, string) = (b, s = 
'none') =>  b ? s : ''):int32 { }

Simplified binary shifts for integers:

var a:int8 = -128;
a>>  1; // -64, sign extension
var b:uint8 = 128;
b>>  1; // 64, no sign extension as would be expected with an unsigned type

Destructing assignment casting:

[a:uint32, b:float32] = Foo();

Function overloading:

function Foo(x:int32[]) { return "int32"; }
function Foo(s:string[]) { return "string"; }
Foo(["test"]); // "string"

Constructor overloading:

// 4 byte object
value class MyType
{
     x:float32; // Able to define members outside of the constructor
     constructor(x:float32)
     {
         this.x = x;
     }
     constructor(y:uint32)
     {
         this.x = float32(y) * 2;
     }
}

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:

var t:MyType = 1; // float32 constructor call
var t:MyType = uint32(1); // uint32 constructor called

Implicit constructors could also be added to the proposed SIMD classes to go 
from a scalar to a vector.

var v:float32x4 = 1; // Equivalent to an ES7 SIMD splat, so var v = 
float32x4(1, 1, 1, 1);

Implicit array conversion would also exist:

var t:MyType[] = [1, 2, 3, uint32(1)];

Types would function exactly like you'd expect with decorators in ES7, but with 
the addition that they can be overloaded:

function AlwaysReturnValue(value:uint32)
{
     return function (target, name, descriptor)
     {
         descriptor.get = () =>  value;
         return descriptor;
     }
}
function AlwaysReturnValue(value:float32) { /* ... */ }

Class example and operator overloading:

class Vector2d
{
     x: float32;
     y: float32;
     constructor(x:float32 = 0, y:float32 = 0)
     {
         this.x = x;
         this.y = y;
     }
     Length():float32
     {
         return Math.sqrt(x * x + y * y); // uses Math.sqrt(v:float32):float32 
due to input and return type
     }
     get X():float64 // return implicit cast
     {
         return this.x;
     }
     set X(x:float64)
     {
         this.x = x / 2;
     }
     operator +(v:vector2d)
     {
         return new vector2d(this.x + v.x, this.y + v.y);
     }
     operator ==(v:vector2d)
     {
         // equality check between this and v
     }
}

Partial class in MyClass.js defining extensions to Vector2d:

class Vector2d
{
     operator ==(v:MyClass)
     {
         // equality check between this and MyClass
     }
     operator +(v:MyClass)
     {
         return v + this; // defined in terms of the MyClass operator
     }
}

Enumerations with enum that support any type except function signatures.

enum Count { Zero, One, Two }; // Starts at 0
var c:Count = Count.Zero;

enum Count { One = 1, Two, Three }; // Two is 2 since these are sequential
var c:Count = Count.One;

enum Count:float32 { Zero, One, Two };

Custom sequential function (these aren't closures):

enum Count:float32 { Zero = (index, name) =>  index * 100, One, Two }; // 0, 
100, 200
enum Count:string { Zero = (index, name) =>  name, One, Two = (index, name) =>  name.toLowerCase(), Three }; // 
"Zero", "One", "two", "three"

Index operator:

enum Count { Zero, One, Two };
Count[0];

Get enum value as string:

// Not sure what the syntax for this would be.

Generic functions:

function Foo<T>(foo:T):T
{
     var bar:T;
}

Generic classes:

class Vector2d<T>
{
     x: T;
     y: T;
     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.
     {
         this.x = x;
         this.y = y;
     }
}

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.

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.

Undecided Topics:

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.

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).

class Vector3d
{
     {
         {
             x: float32;
             y: float32;
             z: float32;
         }
         a: float32[3];
     }
}

Another example would be:

class Color
{
     {
         {
             Red: float32;
             Green: float32;
             Blue: float32;
             Alpha: float32;
         }
         Vector: float32x4;
     }
}

The last topic not covered is if there should be new syntax for TypedArray 
views.

var a1:uint32[] = [2, 0, 1, 3];
var a2:uint64[] = a1(1, 2); // Creates a view of a1 at offset 1 with 2 
elements. So [0, 1].

That might be asking too much though. In a very compact form:

var foo = ((uint64[])a1(1, 2))[0]; // foo would be 1

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:

import {int8, int16, int32, int64} from "@valueobjects";

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.

Previous discussions:
This one contains a lot of my old thoughts (at least the stuff from 8 months 
ago). 
https://esdiscuss.org/topic/proposal-for-new-floating-point-and-integer-data-types
https://esdiscuss.org/topic/optional-strong-typing

https://esdiscuss.org/topic/optional-argument-types
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to