Proposal: Optional Static Typing (Part 3)

# Brandon Andrews (6 years ago)

It's been a year and a half since my last post and I've made a number of small changes and corrections over 2.5 years. The proposal is still on my github at:

sirisian/ecmascript-types

I've talked to a lot of people about it, but I haven't gotten much criticism or suggested improvements. I'm a bit in over my head in trying to flesh out all the details or all the nuanced syntax changes that a championed proposal would be expected to do. That said I've been making more changes lately to try to find edge cases and potential problems.

I've been jotting down issues here: sirisian/ecmascript-types/issues I closed a number of them recently as I made changes.

If anyone has any comments on what I should expand, look into more, or change I'm open to discussing them here or on github.

One issue in particular is this: sirisian/ecmascript-types#15 It covers whether I should introduce a new assignment operator to my proposal. Maybe there's another way to look at it or a different solution. I need fresh eyes on the whole proposal really to get a list of new issues to tackle this year.

I'm also not against having one or multiple people champion it and working on it without me. (I haven't been able to dedicate time to read the ECMAScript spec and really understanding the grammar fully so having someone qualified to take over would help the proposal a lot).

Thanks for reading the proposal for anyone that has the time.

# Pranay Prakash (6 years ago)

I'm still yet to read the entire proposal, but with a quick skim, it seems to me like this is essentially what Typescript or Flow offers you: i.e. an opt-in type system?

I'm wondering if you have any good reasons to want there to be a standardised static type annotation syntax within ECMAScript instead of a "Bring Your Own Type Checker" system. If you do have some thoughts on this, you might also want to include that as a preface on your Github's README.You have a "Rationale" bit that seems to ignore the existence of these existing systems.

Waiting to hear more thoughts on this :)

# Isiah Meadows (6 years ago)

From a quick read, I'm more in favor of something that's a little more

restricted to start, something like what Python has. Python has optional static type annotations, but the Python interpreter just ignores them. They are present purely for the purposes of tooling, and are silently ignored at runtime.

Conversely, PHP took a similar approach and initially also made it cosmetic to start, only later taking advantage of some type annotations by adding runtime behavior to some of the simpler ones (like primitives).

One of the reasons why I'd prefer a simpler approach to start is that TypeScript and Flow, the two main implementations that add syntax, have a very similar syntax, but have several nuances that would make a heavier proposal much harder to accomplish:

  • Flow has ?Foo for optional types, TypeScript just uses unions.
  • TypeScript has mapped/index types, where Flow uses special named types.
  • Flow allows omitted parameter names in function types, TypeScript only allows named parameters with implicit any types.
  • Flow has exact types, TypeScript doesn't.
  • Flow has opaque type, TypeScript only has type.
  • Flow constrains with T: Super, TypeScript uses T extends Super.
  • Flow has 3 different ways of importing bindings a module (depending on what's being imported), TypeScript only has one.
  • Flow has existential types, TypeScript doesn't.

Also, both TypeScript and Flow are still working out how to properly type some of the more advanced JS (like variadic functions and auto-curried functions), so their syntax is still not exactly stable enough I'd feel comfortable encoding much into the spec. (They do have a stable core, though.)

One other thing is that multiple active proposals could end up requiring TS and/or Flow to substantially change parts of their syntax, including:


Isiah Meadows me at isiahmeadows.com

Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com

# Brandon Andrews (6 years ago)

I'm still yet to read the entire proposal, but with a quick skim, it seems to me like this is essentially what Typescript or Flow offers you: i.e. an opt-in type system?

This is in the core of ECMAScript, so the types would be real. The implementers would be encouraged to use native hardware types. But yes, outside of that it is an opt-in type system. Language built on top of it would then benefit from this. I often wonder if languages built on top of ES6 haven't limited themselves because types don't exist. That is they'd do more, but didn't because the complexity of transpiling. Stuff like this: Microsoft/TypeScript#4639 Imagine if ECMAScript already had all those types and support function overloading. TypeScript could move on and implement more experimental ideas.

I'm wondering if you have any good reasons to want there to be a standardised static type annotation syntax within ECMAScript instead of a "Bring Your Own Type Checker" system. If you do have some thoughts on this, you might also want to include that as a preface on your Github's README.You have a "Rationale" bit that seems to ignore the existence of these existing systems.

Did you read the rationale? It specifically says:

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.

More of the rationale was below the types proposed. I've moved it up into the rationale since it fits better there. If there's more you think should be added I'll include it. I'm trying to keep things concise since it's a long proposal. I could go into an explanation that TypeScript and other languages are generally just a superset of Javascript and benefit from bringing their features closer to the base language and possibly the hardware? It seems too obvious to me to write something like that.

From a quick read, I'm more in favor of something that's a little more restricted to start, something like what Python has. Python has optional static type annotations, but the Python interpreter just ignores them. They are present purely for the purposes of tooling, and are silently ignored at runtime.

The goal with this proposal is to get essentially native hardware types where applicable. All the proposed types have special operator rules, value ranges (overflow behavior), and in the case of SIMD very real performance impact behind them. While documentation hints are a side-effect, I'm more focused instead for pushing ECMAScript toward being a more powerful language. Python is a classic example of where data type shortcomings lead to unintuitiveness or weird design like: docs.python.org/2/library/array.html I'm trying to avoid such things.

One of the reasons why I'd prefer a simpler approach to start is that TypeScript and Flow, the two main implementations that add syntax, have a very similar syntax, but have several nuances that would make a heavier proposal much harder to accomplish:

  • Flow has ?Foo for optional types, TypeScript just uses unions.

I have a section on unions with a small explanation on why I left it out. I kept it simple by only adding nullable types. Right now someone would overload or use 'any'.

  • TypeScript has mapped/index types, where Flow uses special named types.

I didn't include these.

  • Flow allows omitted parameter names in function types, TypeScript only allows named parameters with implicit any types.

I created an issue to be more explicit about optional and default typed parameters and the behavior.

  • Flow has exact types, TypeScript doesn't.

I hadn't even considered something like this. It sounds interesting for configuration options. They introduce new tokens. Something I'm very much avoiding for this initial proposal.

  • Flow has opaque type, TypeScript only has type.

Something to be decided later. Doesn't create breaking changes to add later.

  • Flow constrains with T: Super, TypeScript uses T extends Super.

There's a section on generics and why it isn't included already. I'm with you that it's far too complex to add in with initial types. There's no breaking changes introduced by adding it later. (Mostly because it introduces new tokens which would be a huge deal).

  • Flow has existential types, TypeScript doesn't.

I definitely haven't included this. Flow is a few steps ahead of this proposal.

It seems like a lot of these features already aren't included in the proposal. I definitely hold your view that the proposal has to be minimal, but I think my minimal is functionally minimal. Something that when implemented allows developers to experiment and then discussion can progress from there to how more features can be added. I'm trying to be thourough though as to not harm a future proposal so if any of my decisions block something I'm open to changes.

Most of my thoughts and focus have been on what I think of as the basics. How types interact with declarations, functions, classes, destructuring, allocation, and control structures. The future consideration sections are mostly a catalogue of ensuring that these basic initial features and designs will work as the language incorporates other proposals.

# Jordan Harband (6 years ago)

(btw the SIMD proposal has been dropped to stage 1, and implementations are not pursuing implementing it in JS for now tc39/proposals/blob/master/inactive-proposals.md)

# kai zhu (6 years ago)

rant warning

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.

where is this demand coming from? newcomers from c# / java who don't know anything about how javascript is used to ship end-user-features and web-products? or those who do and accept the reality that there's always lots of ugly corner-cutting involved with javascript to push a product out the door?

static-typing, like classes, makes frontend developers' lives harder; it introduce non-essential, rigid structures, making it difficult to cut the necessary corners (and the inevitable ugly-hacks needed) during integration to ship a web-product. its usually easier for javascript-programmers to ship products if the code and async-logic they have to rewrite during integration and qa were mostly throwaway static-functions (with the assumption they WILL be rewritten during integration). versus classes with static-typing (that are more difficult to rewrite at the late-stage in web-development when it matters the most and have a higher tech-debt penalty).

maybe its different @ the large companies / orgs tc39 represents who can hire better-than-average programmers that can magically ship products with correct javascript code right-off-the-bat. but not so for most of the web-industry that can only afford mediocre javascript-programmers whose code-designs and architectures rarely survive integration / productization intact.

# Isiah Meadows (6 years ago)

Inline. Also, in summary, types just get in your way at times, but in others, it's the best thing you could ever have.


Isiah Meadows me at isiahmeadows.com

Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com

On Sat, Jan 13, 2018 at 1:59 AM, kai zhu <kaizhu256 at gmail.com> wrote:

rant warning

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.

where is this demand coming from? newcomers from c# / java who don't know anything about how javascript is used to ship end-user-features and web-products? or those who do and accept the reality that there's always lots of ugly corner-cutting involved with javascript to push a product out the door?

Generally, the latter. C#/Java people tend to want static types, then they wind up writing unidiomatic TypeScript, wondering why it won't work even there. But most users who are actually active in wanting types tend to come from the JS community (there's a reason TS and Flow are both incredibly expressive - they have to be to address the average JS developer's needs).

static-typing, like classes, makes frontend developers' lives harder; it introduce non-essential, rigid structures, making it difficult to cut the necessary corners (and the inevitable ugly-hacks needed) during integration to ship a web-product.

Yeah, if your project happens to be less than about 30K lines of code. I've got a personal pet project that's just above that, and I'm already feeling the pains of the lack of type checking (I'm doing type and value assertions all over the place). However, a 10K line of code project with reasonable consistency within would fare better, since it's much easier to keep in your head.

Also, cutting corners and dropping ugly hacks is possible in both TypeScript and Flow, as they both have an any type which effectively disables type checking. It's useful for unsafe casts that you know are correct. Oh, and TS is technically a superset of JS, so any is the default, absent any other type declarations.

As for classes, I'll agree they're overused, but there are times when they're useful - they make for great DSLs and easier-to-use APIs, and there are rare occasions where you actually need inheritance (they make certain forms of extensibility easier, and they take less memory than copying).

its usually easier for javascript-programmers to ship products if the code and async-logic they have to rewrite during integration and qa were mostly throwaway static-functions (with the assumption they WILL be rewritten during integration). versus classes with static-typing (that are more difficult to rewrite at the late-stage in web-development when it matters the most and have a higher tech-debt penalty).

Actually, it's the other way around: static typing has a higher up-front cost, because it's much more rigid to start. It's harder to write the initial prototype when you're simultaneously verifying it, but it's easier to make late-stage changes without introducing new bugs*. Trust me: I have first-hand experience with both approaches.

* Unless, of course, you have a very annoying client/customer/manager/etc. who decided to ask for you to change half of the project entirely for whatever reason, in which it's a people problem, not a technical problem.

maybe its different @ the large companies / orgs tc39 represents who can hire better-than-average programmers that can magically ship products with correct javascript code right-off-the-bat. but not so for most of the web-industry that can only afford mediocre javascript-programmers whose code-designs and architectures rarely survive integration / productization intact.

Note that in no place did anyone request that static types be mandatory, and most of us had responded to suggest reducing the scope of the proposal, not broaden it. Also, your premise of "can magically ship ... with correct JS code right off the bat" is a straw man based on the opposite of what static types are for. The whole point of static types (and type checking in general) is founded on the assumption you can't trust people to not make mistakes. If you can use a program to help check those mistakes for you and alert you of them, you're more likely to correct those mistakes before sending them to production.

# Pier Bover (6 years ago)

I strongly disagree with kai zhu.

where is this demand coming from? newcomers from c# / java

who don't know anything about how javascript is used to ship end-user-features and web-products?

The idea that optional static typings (OST from now on) are some "contamination" from other languages is naive. Programmers are not asking for OST because they lack perspective, quite the contrary, it's simple common sense. Types make code more obvious and deliberate. The importance of obviousness in code cannot be overstated.

I'm not a guy coming from C# or Java. In my 20+ years of professional web dev I've spent 80% of my time writing ES languages. I wrote with ES4 extensively (AS3) and I experienced OST myself for years. In fact AS3 was 11 years ago a better language than JS is today and one of the biggest reasons for that were OST.

static-typing, like classes, makes frontend developers' lives harder;

it introduce non-essential, rigid structures, making it difficult to cut the necessary corners (and the inevitable ugly-hacks needed) during integration to ship a web-product.

It seems you are missing the word "optional". Current optional ES classes are nothing more than syntactic sugar over prototypal inheritance, and since these classes were introduced no flexibility has been lost. With the introduction of OST no flexibility would be lost either and we could happily ship quick and dirty solutions if we needed/wanted to.

maybe its different @ the large companies / orgs tc39 represents who

can hire better-than-average programmers that can magically ship products with correct javascript code right-off-the-bat. but not so for most of the web-industry that can only afford mediocre javascript-programmers whose code-designs and architectures rarely survive integration / productization intact.

You are again ignoring the optional factor. With OST JavaScript could still be used by mediocre programmers, but maybe they could start architecturing their code better and survive integration. That was exactly my experience when I started to write AS3 back in 2007. It made me a better programmer and it was my stepping to stone to C#, C++, Go, Swift, etc.

I really don't understand the irrational aversion to OST or classes in ES. If you don't want to use them, well don't use them. These features makes sense for a lot of programmers and IMO EcmaScript should not be a bastion of resistance against other languages, specially when it's the only language for building front end applications.

# kai zhu (6 years ago)

I really don't understand the irrational aversion to OST or classes in ES. If you don't want to use them, well don't use them. These features makes sense for a lot of programmers and IMO EcmaScript should not be a bastion of resistance against other languages, specially when it's the only language for building front end applications.

then we agree to disagree. perspective-wise, type-related bugs are among the most easy to debug-and-fix things in javascript (or any serious programming language really). OST brings little to the productivity-table in offering to help solve a relatively trivial problem on the javascript bug-spectrum, while distracting us from bigger-picture show-stoppers. like say, integration-level bugs dealing with async-io and timeouts, that can invalidate design-decisions / performance-tradeoffs made at the application-level and require major code rewrites.

for example, did you find out during integration / qa, that mongodb’s scalability claim (using its old mmapv1 storage-engine) is a lie, and even with indexing, its real-world query-performance for your use-case drops dramatically when the db grows past 10gb (to maybe 30-60 seconds / query which is similar to mysql at such scale)? great, now you have to retool the application with a new caching-scheme (or maybe a shudder message-queue) to compensate, and perhaps search-and-replace the timeout value everywhere a request to mongodb is made in your code. these are the kinds of bugs that keep javascript-developers awake at night, not some kiddie string-instead-of-number type-error.

# Pier Bover (6 years ago)

perspective-wise, type-related bugs are among the most easy to debug-and-fix

Eric Elliot has already argued that types do not alleviate bugs, and quite frankly it is irrelevant. The real value of OST is to be able to express structures and write more obvious code.

for example, did you find out during integration / qa, that mongodb’s scalability claim (using its old mmapv1 storage-engine) is a lie, and even with indexing, its real-world query-performance for your use-case drops dramatically when the db grows past 10gb (to maybe 30-60 seconds / query which is similar to mysql at such scale)? great, now you have to retool the application with a new caching-scheme (or maybe a shudder message-queue) to compensate, and perhaps search-and-replace the timeout value everywhere a request to mongodb is made in your code. these are the kinds of bugs that keep javascript-developers awake at night, not some kiddie string-instead-of-number type-error.

So first you used mediocre programmers to argue against OST, and now you are using a (terrible) product that forces you to use workarounds to argue against OST. What's your point really?

# Mark Volkmann (6 years ago)

Not sure if this is the place to debate whether optional type support in JavaScript would be a good thing, but I'll throw in my perspective. I used to be anti-types. Then I decided to give Flow a try. Initially it felt like I was spending a lot of time just learning the syntax and trying to make Flow happy. But after a few weeks I caught on and noticed that every time Flow complained it was actually correct. Then I needed to so some refactoring. That's where the big benefit is for me. I no longer have to manually determine what would break if I want to do things like change a function name, change a property name in an object, and much more. I just make the change and Flow tells me where I need to make adjustments. So whether JavaScript adds types, I don't think I'll go back to not having them. I'd much rather use Flow or TypeScript than not have types at all.

# Michał Wadas (6 years ago)

I have many concerns about typing.

Types are opinionated

Choice of type system significantly affects code that people write. As observed in many codebases, adoption of TypeScript favors object oriented style over functional style.

Choosing type system descending from Java type system is message "creators of language endorse OOP as main JavaScript paradigm". It's fine for TypeScript to take opinionated approach, but it's unlikely with TC39.

If you don't see limitations of eg. TypeScript type system, try to express in its terms: "function takes subclass of Foo as parameter Ctor and returns subclass of Ctor extended by some methods". Not to mention reflection here (think of Bluebird's promisification)...

Functional languages usually provide better type systems, but complexity can be prohibitive. Moreover, I don't know any programming language that combines type system as strong as eg. Idris and object oriented programming.

Runtime type checking

Runtime type checking would incur significant cost on browsers (and JavaScript parse time is already an issue for smartphone CPUs). It's especially important to remember about dynamic nature of JavaScript. TypeScript can rely on assumption that no one creates accessors on Object.prototype or Array prototype, but it's unacceptable for language feature.

Therefore, chance of someone calling Object.defineProperty(Array.prototype, 7,...) requires type checking on every property assignment. There hundreds of ways to screw type system, including changes in inheritance in runtime.

foo instanceof Foo; // true foo instanceof Foo; // false foo instanceof Foo; // true

Ups, someone overwritten Function.prototype[Symbol.hasInstance] with () =>

Math.random() > 0.5.

Compilation time type checking

Compilation time type checking requires tooling. If language relies on external tool to strip type definitions, why whole typing can't be left to external tool? External tools can iterate faster than language and can compete.

People hates writing types

That's why C++ have auto, Kotlin have val, and it's significant reason why dynamically typed languages became popular. Type inference is awesome, but integrating it with existing JavaScript code in backwards compatible way seems to be hard.

# Bruno Jouhier (6 years ago)

I'm coming from a long journey through dynamically typed (mostly LISP and JavaScript) and statically typed (mostly C, C++, Java and C#) languages, I'm now using TypeScript and I really like the mix of power and flexilbility that OST provides.

From my experience, the main benefits of OST are the following:

  • self-documentation: I work with a large team and developers often need to explore code or use APIs written by others. Types are very helpful and save a lot of time. Even more with modern code editors thanks to intellisense, jump to definitions, ...
  • code refactoring: I work on prototypes and I do a lot of code refactoring in the early stages of a project. Refactoring is painful without types: you either have to tediously check that you have put all the pieces back together, or accept to run several debugging passes to eliminate all the silly refactoring errors. OST reduces the cognitive load (you don't have to remember all the loose ends) and it saves a lot of time overall.

The pain point is that code needs to be transpiled. There are tools to help (and the TypeScript compiler has a file watch option) but for simple scripts/projects it would be nice to be able to run directly without preprocessing.

I don't mind if type systems remain outside of the ES spec but a nice improvement would be to have a provision for OST syntaxes in ES so that ES engines could load and execute code that contains type annotations, by just treating them as comments. Then, we would not need to transpile during development.

I don't know if there are enough syntax markers to allow this without adding complete type grammars to the language. I imagine that a lookahead that kicks off after certain markers (colon, as/type/interface/declare keywords) and that skips certain token types (identifiers, literals, |, &) and balanced parentheses/curly braces/brackets may be able to do the job. But this might be easier said than done (and ASI might get in the way).

Could this be a viable compromise?

Bruno

# Bruno Jouhier (6 years ago)

@Brandon

There are already two popular OST: TypeScript and Flow. They have tools, large communities, type libraries for a large number of ES modules, etc.

It might be easier to submit your ideas to these communities than to push a third proposal. At least, a gap analysis would help people who already know these systems.

Bruno

# Brandon Andrews (6 years ago)

(btw the SIMD proposal has been dropped to stage 1, and implementations are not pursuing implementing it in JS for now tc39/proposals/blob/master/inactive-proposals.md)

Yeah, that seemed predictable. I wanted the SIMD operations to use operators intuitively. That and all the SIMD core types lacked ECMAScript equivalents. Like one expected to be able to write SIMD code and not lose all the speed-up dealing with Number or casts. Was never really sold on the idea of having a float32x4 when the language can't even represent float32 without a TypedArray. Putting the cart before the horse.

where is this demand coming from?

Wherever TypeScript and Flow are used; so companies like Microsoft and Facebook. I know friends that use TypeScript exclusively for application development with teams of over three people. Personally I've worked on projects over 25K lines of Javascript usually by myself, and while it would have been nice to have types it's not necessary for what I did. I didn't use classes either and relied more on a mix between agile and cowboy programming. Things have changed over the years though.

One of the reasons I started wanting types and created this specification years ago was because I was working on more complex applications. Essentially taking programs that would be written (or were written in my case) in C++ and C#/WPF and writing them for the web for Android, Mac, Linux, and Windows. Part of this involved architecting and designing out ORM systems with database types and schemas. I was also doing a lot of binary WebSocket stuff at the time, some of which was somewhat performance critical with node.js on the backend. So to answer your question the demand would be developers that have transitioned to using HTML5 and Javascript for application development in teams. (In my case programs for all OSes along with web applications and interfaces). There's other reasons. My work projects have spawned off personal projects for myself in networking in databases. I'd like to use Javascript more, but I tend to fallback to C++ or C# simply because of the lack of types.

I find it strange to pretend like the demand isn't there. TypeScript, and Flow have existed for a while now and I hear about them all the time in my circles. OST as described in my mind brings in the core features that people are seeking such that they can use Javascript again by itself in the future. Some people might not use them, but a lot of people would in certain places. It also might open up new features and spin-off languages since types would have already been handled without reinventing the wheel like AS3, TypeScript, and Flow did.

Also realize I never intended this proposal to be implemented right away. It could take years still. Part of my slight worry as things draw on is that with all these proposals floating around that one of them will change the grammar slightly add new tokens, ASI, or other slight changes and make types infeasible or very inconsistent across the language.

Choosing type system descending from Java type system is message "creators of language endorse OOP as main JavaScript paradigm". It's fine for TypeScript to take opinionated approach, but it's unlikely with TC39.

More like descending from Actionscript 3. I wouldn't relate a type system to OOP though. People still write non-OOP TypeScript. If you want to blame the rise of classes in Javascript you'd be looking at the introduction of classes themselves. You give programmers what they want and they'll use them for frameworks and programming. (The old way was just ugly or cumbersome so people avoided it was my experience). In any case classes are already in the spec. Types aren't going to change that.

Runtime type checking would incur significant cost on browsers (and JavaScript parse time is already an issue for smartphone CPUs). It's especially important to remember about dynamic nature of JavaScript. TypeScript can rely on assumption that no one creates accessors on Object.prototype or Array prototype, but it's unacceptable for language feature.

I'm glad you brought that up. I've been thinking about this problem of types changing for a while. Can you write down a bunch of examples and scenarios? It would help to analyze them. (Creating an issue with all of them would be ideal).

Part of this has had me considering if freezing classes (and all recursively referenced types) used in the type system is viable. That is referencing a class in say a variable declaration or function signature would freeze the class. Seems a bit extreme of an option though that would cause problems for certain designs or ideas later where people want to add, remove, or update properties. Is it that important? When would a freeze even happen?

I think having a lot of examples would make this easier to analyze.

People hates writing types That's why C++ have auto, Kotlin have val, and it's significant reason why dynamically typed languages became popular. Type inference is awesome, but integrating it with existing JavaScript code in backwards compatible way seems to be hard.

Part of this is to find out how hard a lot of this stuff is. Speaking of type inference someone opened a ticket that started a small discussion: sirisian/ecmascript-types#27 Basically trying to figure out if larger non-Number literals could even be placed into the language without unforeseen issues.

It might be easier to submit your ideas to these communities than to push a third proposal. At least, a gap analysis would help people who already know these systems.

I've talked to people in the communities in the past. They seem beyond caring about Javascript. I've been told to "just use TypeScript" on a few occasions with little input. I'd probably have to find someone very specific on their team willing to help. That's more or less why I made a comment about looking for a champion or a few to take over. If someone wants to pass this along or link my github I'd appreciate it.

Isiah, I was looking through my original old post. I must have missed the emails a year ago:

First, no type checker (TypeScript, Flow, or any other) can fully check the core language (most notably bind, apply, call, and Object.assign).

Second, they both still are missing some pretty significant features required for typing common JavaScript idioms (higher kinded types for Fantasy Land and Ramda users, variadic generics for bind, call, and apply, n-ary unions for Object.assign and similar, etc.).

I've had a section in my spec for typed rest parameters which I think covers a few cases. sirisian/ecmascript-types#rest-parameters Has anything changed with your view on these topics? Or examples and scenarios I should handle in the initial spec?

# Michał Wadas (6 years ago)

Part of this has had me considering if freezing classes (and all

recursively referenced types) used in the type system is viable.

function foo(bar: Array.<Set>) { //whatever }

[Array, Set] = [Set, Array]; foo(new Array([Set()]));

You can't freeze all builtins for obvious reasons.

You totally omitted point that your type system can't use or describe this function:

function issue(Ctor) { assert(Reflect.isConstructor(Ctor)); // Type system don't provide way to disguintish object with [[Construct]] and [[Call]] methods. assert(Foo.isPrototypeOf(Ctor)); // Type system don't provide way to ensure prototypal inheritance const retClass = class extends Ctor { // Type system don't provide way to describe types being returned from function }; Object.assign(retClass.prototype, mixin); // Object.assign can be overridden to do anything, so actual code execution is required to prove it's valid return retClass; }

TypeScript favors OOP because it supports virtually all OOP idioms, but doesn't support non-basic FPP idioms.

# Brandon Andrews (6 years ago)

Part of this has had me considering if freezing classes (and all recursively referenced types) used in the type system is viable.

function foo(bar: Array.<Set>)
{
// whatever
}
[Array, Set] = [Set, Array];
foo(new Array([Set()]));

You can't freeze all builtins for obvious reasons.

I'm out of ideas. Do you or anyone here see a way to get around such an issue?

You totally omitted point that your type system can't use or describe this function:

function issue(Ctor)
{
    	assert(Reflect.isConstructor(Ctor)); // Type system don't provide way to disguintish object with [[Construct]] and [[Call]] methods.
    	assert(Foo.isPrototypeOf(Ctor)); // Type system don't provide way to ensure prototypal inheritance
     
    	const retClass = class extends Ctor // Type system don't provide way to describe types being returned from function
    	{ 
    	};
    	Object.assign(retClass.prototype, mixin); // Object.assign can be overridden to do anything, so actual code execution is required to prove it's valid
    	return retClass;
}

Just to be clear. Is Ctor a type? Like "class Ctor extends Foo {}" or an instance? If it's a Type it might be better handled with generics later like:

function issue<Ctor extends Foo>(mixin)
{
    	const retClass = class extends Ctor
    	{ 
    	};
    	Object.assign(retClass.prototype, mixin);
    	return retClass; 
}

I hope I understood the requirements. Is it necessary to allow the type system to handle passing types as arguments? Do other languages allow this?

assert(Reflect.isConstructor(Ctor)); // Type system don't provide way to disguintish object with [[Construct]] and [[Call]] methods.

So you'd expect a language feature like an interface that mandates a constructor or something more general like "this object is a class"?

assert(Foo.isPrototypeOf(Ctor)); // Type system don't provide way to ensure prototypal inheritance

So I should explicitly state that derived classes can be passed to parameters typed with their super like most languages allow like:

class A {}
class B extends A {}
function f(a:A) {}
f(new B()); // Valid

In your example:

function issue(Ctor:Foo):Foo
{
}
class A {}
// issue(new A()); // TypeError, A must be type Foo or extended from Foo

Is that sufficient?

const retClass = class extends Ctor // Type system don't provide way to describe types being returned from function
{ 
};

Would this be asking for interfaces and structural matching like in TypeScript? I left it out originally to simplify the proposal with the expectation it would be added in later. Do you see this more as a mandatory feature? "any" can be used in the meantime unless I'm mistaken. (I should probably add a section in the proposal covering this).

# Brandon Andrews (6 years ago)

Some follow-up as I think more about this.

You can't freeze all builtins for obvious reasons.

I'm getting that the reason for not freezing them would be to define extensions? Could they not be defined and then frozen? I get that doesn't stop them from being dynamic still.

The ability to change the built ins like Object causes a number of issues as it makes all classes dynamic and your destructuring swap shows that well. It seems like as long as Object can be modified everything has to use run-time checking.

If Object could be made non-dynamic - froze it and made it const (or equivalent) - then one could write:

const f = function(a:A)
{
        a.x = 0;
}
const A = new class
{
        x:uint8 = 5; // Object.defineProperty(A.prototype, 'x', { type: uint8, writable: true, value: 5 }); (I think, might have to think about this again, been a while).
}
f(new A()); // A is dynamic and the interpreter is forced to use a run-time check.

Object.freeze(A); // A is both const and frozen making it no longer dynamic? If the dynamicness was removed then the engine could search the code/AST and optimize f doing essentially a compile-time check at that point

f(new A()); // Compile-time verification for all instances of f where the argument is typed or the type can be inferred.

This usage of const works at global scope, but I feel like I'm missing something that would undermine this. Like without real namespace support this won't work well for some libraries. The syntax is also wordy and confusing. One could add const class A {} modifiers, but that's still confusing since codebases would be filled with it.

Also expecting users to freeze their classes to allow the interpreter and JIT to function sanely is asking a lot.

One problem that keeps bothering me is this delayed freezing doesn't help tooling. A class could be created, properties added in a complex operation, then the class frozen later. The tooling would be blind to all these changes.

I'm probably just barely touching the surface of issues. Anything I'm overlooking?

# kai zhu (6 years ago)

more ranting. tldr - javascript-programmers are more productive spending their limited-time documenting and writing validation-code for endpoint-level rest-apis instead of for code-level business-logic (swagger/openapi is more useful than OST/flow/typescript).

i'm generally a javascript-architecture skeptic. from my experience in industry, there is zero-correlation between careful architecting (cough bikeshedding) and successfully getting over the javascript-integration hump to ship a product. the “best" architecture/design for any given web-project is whatever ad-hoc hacks/rewrites/fire-fighting it takes to get you past the integration-stage (and javascript-fatigue is partly the realization from naive newcomers that you almost always end up with spaghetti-code after integration, no matter how hard you fight it). it might be different at microsoft/facebook/google, but their abnormal tooling environments (and resulting skewed world-view of javascript) are hardly representative of the industry as a whole.

what does correlate with successfully shipping a product, is having well-documented endpoint rest-apis, so the frontend-folks aren’t completely clueless during integration when they try talking to the backend, and it doesn’t respond or timeout for some reason. a web-project has a higher chance of shipping successfully if you spend your limited engineering-time doing integration-level documentation and validation-checking (using swagger as shown in following screenshots) instead of code-level OST which nobody talking to your server during integration cares about:

(these screenshots are from real-world endpoint rest-apis that have been documented with integration-level type-checking using swagger - kaizhu256.github.io/node-swgg-google-maps/build..beta..travis-ci.org/app, kaizhu256.github.io/node-swgg-google-maps/build..beta..travis-ci.org/app)

# Pier Bover (6 years ago)

javascript-fatigue is partly the realization from naive newcomers that

you almost always end up with spaghetti-code after integration, no matter how hard you fight it

And don't you think the lack of OST is in part fueling this situation?

# Brian Barnes (6 years ago)

My 2 cents from a pure developer (not js engine implementer.) I've been developing for decades, started with assembly, to C, to C++ and Java, and lately have been fascinated with javascript, especially as it's run anywhere.

I'm developing both a 3D shooter where every bit of content (maps, models, bitmaps, sounds) are randomly generated from scratch, and just started working on a 2D game engine with a game. Doing this because I enjoy doing it (all open source if anybody cares.)

I do very rapid development. I code what I need, and when my need changes, I rework all the code. Some of these engines have gone through multiple iterations. All class based, BTW.

Nothing has caused me more trouble than types. Massive changes up and down a chain of code almost always create very hard to track errors. Adding things to signatures can be a nightmare because you have to retrack all that through the code and nothing tells you if you've messed up one somewhere. It wastes more time than I can count.

From my personal experience, which might not be universal -- but this is a real world example, types would be a great help. If only pre-compile hints, that's still a step forward. If something the engine can use, that's even better.

One other benefit -- if I decide to shift my code back to C++ and do web assembly (waiting for the tools to mature and become more turn-key) this makes it much easier to translate code, either way.

[>] Brian

# Pier Bover (6 years ago)

One other benefit -- if I decide to shift my code back to C++ and do web

assembly (waiting for the tools to mature and become more turn-key) this makes it much easier to translate code, either way.

I think this is what a lot of people in the front end space are going to do once WA is widespread and has access to the DOM and browser functions. Probably not C++ but any other language they prefer (C#, Go, Rust, Crystal, Haxe, etc).

In our team we are replacing Node for Go and the lack of types is a big reason for that. Sure we could use TypeScript or Flow but why add more acrobatics to an already complicated show?

# Naveen Chawla (6 years ago)

This was a nice post but it confused me! You said "Nothing has caused me more trouble than types", then you said " types would be a great help". I'm sure I just misunderstood what you meant.

Anyway, I think types are a great help in many cases and wouldn't compromise the dynamic-ness of JavaScript whenever required!

# Brian Barnes (6 years ago)

My bad, sorry, meant "nothing has caused me more trouble than the LACK of types." And I re-read it 3 times before I sent it and missed that!

[>] Brian

# Isiah Meadows (6 years ago)

Inline.


Isiah Meadows me at isiahmeadows.com

Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com

On Tue, Jan 16, 2018 at 7:44 AM, kai zhu <kaizhu256 at gmail.com> wrote:

more ranting. tldr - javascript-programmers are more productive spending their limited-time documenting and writing validation-code for endpoint-level rest-apis instead of for code-level business-logic (swagger/openapi is more useful than OST/flow/typescript).

i'm generally a javascript-architecture skeptic. from my experience in industry, there is zero-correlation between careful architecting (cough bikeshedding) and successfully getting over the javascript-integration hump to ship a product

I only partially agree. For most smaller things, and even some mid-sized projects (e.g. simple DB servers with REST APIs), all you really need to architect is your API, and the rest will largely fall out naturally. The front and back end are probably equal in this.

the “best" architecture/design for any given web-project is whatever ad-hoc hacks/rewrites/fire-fighting it takes to get you past the integration-stage [...]

If it doesn't include a lot of business logic in JS, then sure. I can tell you my blog, which includes mostly hand-written JS, is a big ball of mud on the front end. But it works.

[...] (and javascript-fatigue is partly the realization from naive newcomers that you almost always end up with spaghetti-code after integration, no matter how hard you fight it).

Disagree here, particularly on the meaning of "JavaScript fatigue". That phrase came to be not because of anything about what frameworks do to your code, but from:

  1. The fact that build systems are/were getting unnecessarily complex. For some communities (React in particular was notorious), it may take setting up 10+ modules independently, each with non-trivial configuration, just to get started on the simple stuff.
  2. The ecosystem at large was, and still is, churning at such a fast rate that people were struggling to keep track of it all, and consequently had issues adjusting to it. React's community was also a notorious offender for iterating too quickly, but that is at least starting to settle down.

Neither of these actually directly relate to the code quality underneath, and even those who enjoyed the frameworks/libraries themselves were getting tired and stressed over trying to keep up with everything.

it might be different at microsoft/facebook/google, but their abnormal tooling environments (and resulting skewed world-view of javascript) are hardly representative of the industry as a whole.

First, could you please quit assuming that those companies are the primary users of things like TypeScript/etc.? I could understand Flow being very specific to Facebook (it's rarely used outside of Facebook and React apps), but TypeScript, not so much - it's the 9th most popular language according to Stack Overflow's most recent Developer Survey. 1 At this point, it's about as popular as Ruby, according to the survey's participants, and there's no way that the combination of the three could account for any more than a small minority of the participants:

  • Microsoft developed TypeScript, and has been using it for a while - this is probably a given.
  • Facebook almost exclusively uses Flow - you could've probably guessed this.
  • Google internally relies primarily on either GWT (Java to JS) or the Closure Compiler (uses JSDoc for types) for type checking, and only last year started allowing unrestricted development using TypeScript. 2

So the only corporation that could substantially contribute directly to TypeScript's dominance would be Microsoft, and Google's influence is more indirect (they use Angular, which bases its entire ecosystem on TypeScript, but they aren't one of Angular's primary users).

Second, those three aren't even primary users of even Webpack. In fact, two of Webpack's biggest backers are Adobe and Capital One (yes, that financial company), each having given $12K to that OSS project. 3

what does correlate with successfully shipping a product, is having well-documented endpoint rest-apis, so the frontend-folks aren’t completely clueless during integration when they try talking to the backend, and it doesn’t respond or timeout for some reason. a web-project has a higher chance of shipping successfully if you spend your limited engineering-time doing integration-level documentation and validation-checking (using swagger as shown in following screenshots) instead of code-level OST which nobody talking to your server during integration cares about:

Yes, if you're dealing mostly with clients as a freelancer or small-time developer. If you're rolling your own data-driven business or complex web app, types become invaluable. There's a key difference between doing things for clients with much smaller needs, and doing things for your own high-tech business. I have experience in both, and I can assure you, there's a whole world of difference between the two. For one, ugly hacks work in one-off projects, but not for anything you have to sustain and put substantial amounts of time to maintain.

# Brandon Andrews (6 years ago)

I moved some more thoughts to an issue. I'm finding this discussion is helping me a lot to see potential problems and what syntax might need to be included for everyday use.

sirisian/ecmascript-types#29

I included code to const/freeze Object also to continue the ideas presented earlier. At the bottom of the issue is my concerns and also some possible syntax proposals for essentially what other languages would call a sealed class.