Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What if someday we want runtime enforced type checking? #45

Closed
jamiebuilds opened this issue Mar 9, 2022 · 31 comments
Closed

What if someday we want runtime enforced type checking? #45

jamiebuilds opened this issue Mar 9, 2022 · 31 comments

Comments

@jamiebuilds
Copy link
Member

jamiebuilds commented Mar 9, 2022

Update: Please read these added sections in the README before commenting:

I'm super strongly in favor of this step forward with types being ignored at runtime. However, I'm concerned what this might lock us out of in the future.

There has been a lot of interest in the past in performing runtime checks of types. Google, Mozilla, and others have experimented with several different approaches that I'm aware of (i.e. "use strong"). And it's possible that we may we want to revisit that in the future. It would be a real shame (please imagine the crime boss voice) if we couldn't do that because there's all this syntax that was written to do nothing at runtime.

One possible solution to that is a new directive:

"use types-as-comments directive (insert name bikeshed here)";

function fn(a: boolean) {
  // ...
}

Of note, in a future where we get static checking at runtime, it wouldn't be a simple matter of removing this directive to turn it on because there's no guarantees the syntax matches. Its only purpose (that I can see) would be to reserve the syntax space for future use.

@lhorie
Copy link

lhorie commented Mar 9, 2022

This is a good point. Once you open the floodgates of allowing such syntax, it's entirely possible that there may be interest in semantics similar to PHP, for example. This sort of interest already exists today, e.g. ts-runtime.

@giltayar
Copy link
Collaborator

giltayar commented Mar 9, 2022

In the future, we may want an "official" type system that will also have runtime checks. If you look at the history of types in Python, they did a two step approach: first they enabled "types as comments" like we do here. Then, when the ecosystem experimented with it enough, they added an official type system (caveat: I haven't followed Python closely enough, so I may be way off in how this happened).

@jamiebuilds
Copy link
Member Author

The key difference with Python is that they can make breaking changes (infamously so). If my website has static types as comments, you can't just suddenly turn type checking on at runtime without potentially taking my site down.

@fabiospampinato
Copy link

Better performance seems like the obvious potential benefit of having types, this proposal doesn't seem to have taken performance into consideration much, nor it seems to suggest that these type annotations may lead to better performance in the future.

IMO if better performance is one of the major goals that are supposed to be arising from this in the future it's better not to overcommit to something potentially unsuitable that we can't fix in the future for backwards compatibility reasons. A "just spec TS" approach may lead us the wrong way.

@RyanCavanaugh
Copy link
Collaborator

People should be sure to clearly distinguish between static typechecking (presumably as a pre-step to script evaluation) vs dynamic typechecking (raising an error/warning if a runtime call to fn didn't actually provide a boolean). They're both extremely difficult to do in a normal runtime environment IMO, but in different ways that have different implications on this proposal.

@fabiospampinato
Copy link

fabiospampinato commented Mar 9, 2022

People should be sure to clearly distinguish between static typechecking (presumably as a pre-step to script evaluation) vs dynamic typechecking (raising an error/warning if a runtime call to fn didn't actually provide a boolean).

That's a good point. Those seem maybe some of the most important problems that one would expect types to tackle. It's interesting because the current proposal doesn't seem to tackle either of those, nor it seems to provide an even vague path toward tackling either of those, nor it seems to tackle any other valuable problem, at least as far as I can see 🤔

@lukaszpolowczyk
Copy link

That's what I'm thinking, too.

The only idea:
Make these type-comments allowed, only in a special dev browser mode....
This is mainly for such a purpose anyway, so that the developer doesn't have to wait for the code to compile for him.
Then, let the developer turn on the type-comment mode in his browser. :D

Then, the problem of breaking the web disappears, as does the problem of performance degradation - it would only work in the developer's browser.

But as far as I understand, it's not only about compilation time? It's also about being able to upload this "typed" code to the web without compiling at all?
I don't see how to solve the second problem.

@ktmud
Copy link

ktmud commented Mar 10, 2022

@jamiebuilds it's still possible to introduce breaking changes in JavaScript with a flag like "use strict". I'd argue for things as fundamental as type checking, it'd worth a new flag.

@lukaszpolowczyk
Copy link

I for one would like to see ignoring type-comments enabled only in the browser's DevTools.
By default, it shouldn't work anywhere.
This is a thing for the developer so they don't have to wait for compilation.

So not any "use strict" or anything like that. Just the browser's DevTools function.

@ljharb
Copy link
Member

ljharb commented Mar 10, 2022

@ktmud in practice, it is not, as the prevailing committee attitude remains “no new modes, ever”.

@chrisdothtml
Copy link

chrisdothtml commented Mar 10, 2022

the prevailing committee attitude remains “no new modes, ever”

So it seems that, if this continues to be the attitude of the committee, then this proposal would prevent any future possibility of runtime-enforcement of these annotations, as there's nothing stopping people from writing code with broken/inaccurate type annotations, so adding any runtime-enforcement would be backwards-incompatible

@glen-84
Copy link

glen-84 commented Mar 10, 2022

@chrisdothtml I think that's the whole point of this issue.

Implementing this in a way that would reserve the : syntax and prevent its future use for runtime checks would be a huge mistake IMO.

@jamiebuilds
Copy link
Member Author

To be clear, I don't know that we'd ever do any kind of runtime type checking. But I think it's important to note what this proposal would lock us out of doing and have the committee agree to that.

@wparad
Copy link

wparad commented Mar 10, 2022

"It would lock us out of runtime checks using the syntax defined here, without explicit indication to the runtime engine to do the check."

And if we don't actually have a supermajority on needing runtime type checking (even in the near future), this seems like the right approach.

@jamiebuilds
Copy link
Member Author

wparad 3 minutes ago
"It would lock us out of runtime checks using the syntax defined here, without explicit indication to the runtime engine to do the check."

@wparad What are you quoting?

@wparad
Copy link

wparad commented Mar 10, 2022

I was putting concretely what we would be doing implicitly with this proposal to make it easy for others to understand what the implications might be and what could be conveyed as part of the proposal as a caveat. Stating it was my attempt to make sure that I understood the concern correctly.

@glen-84

This comment was marked as resolved.

@glen-84
Copy link

glen-84 commented Mar 10, 2022

Sorry, I must have misinterpreted your comment. What seems like the right approach?

@giltayar
Copy link
Collaborator

the prevailing committee attitude remains “no new modes, ever”.

Never say "ever" 😀

@wparad
Copy link

wparad commented Mar 10, 2022

Sorry, I must have misinterpreted your comment. What seems like the right approach?

@glen-84, as @jamiebuilds suggested:

To be clear, I don't know that we'd ever do any kind of runtime type checking. But I think it's important to note what this proposal would lock us out of doing and have the committee agree to that.

@ljharb
Copy link
Member

ljharb commented Mar 10, 2022

@giltayar i was careful to say "prevailing" :-p

@simonbuchan
Copy link

simonbuchan commented Mar 11, 2022

I can see an API like Types.enableChecks("some-type-system", (diagnostic) => console.warn(diagnostic)) or the moral equivalent? Or even just Reflection.addVisitor(await import("some-type-system")) that gets the parsed JS, some context, and parses and checks the type annotations. The point is, APIs are easy to add (EDIT: in comparison to language semantics!)

@benjamingr
Copy link
Collaborator

I went over the discussion I've had (for this proposal) with the designers of Python's type system annotations and I recalled why this is impossible anyway.

There are many types that simply cannot be verified in runtime. This is true for many generic types. Some examples we all know and love are:

  • Any iterator - e.g. an Iterator since doing so would consume the iterator.
  • Promises (we don't know what the value is yet) and async iterators.
  • Streams (node/web), observables etc.

Basically any container that is not random access (not that iterating a 10000 item array to know it's all strings makes a ton of sense to me anyway).

To me: that's a lot more motivation for why we shouldn't (ever) do this given the language than "no other language is doing this" or "this isn't popular".

(Note the language does perform type checks in several places - e.g. 1.1 * 4n throws - it's just not related to the annotations)

@simonbuchan
Copy link

@benjamingr I'm not sure I understand this? There's no reason the semantics for (for the sake of argument) x as Iterator<string> would have to actually iterate every element and call typeof at that point. Two obvious to me options would be that x already has a full runtime type (like Generator<string>) from it's construction (either declared or inferred) and this just asserts that it is assignable, the other is that it wraps x with something that asserts that each retrieved value is a string.

@benjamingr
Copy link
Collaborator

@simonbuchan

There's no reason the semantics for (for the sake of argument) x as Iterator would have to actually iterate every element and call typeof at that point.

This would mean one can hold an Iterator<string> that isn't actually an Iterator<string> meaning there is no runtime type checking being enforced on it though.

Two obvious to me options would be that x already has a full runtime type (like Generator

Note everything in JavaScript already has a full runtime type. JavaScript already has types though they are not generic (that is, something can be an object with a generator prototype) so while something can be a Promise in JavaScript types it can't be a Promise<string>.

Two obvious to me options would be that x already has a full runtime type (like Generator) from it's construction

That would require "full" typing and effectively a complete breaking change for the language.

the other is that it wraps x with something that asserts that each retrieved value is a string.

I'm not sure I can see a semantics for this where this works for stuff like promises (you hijack the error and reject the promise if you get the wrong type?) - but mostly it doesn't compose or work for user types. It would also be prohibitively slow from a runtime's point of view.

@simonbuchan
Copy link

That would require "full" typing and effectively a complete breaking change for the language.

Why? There's potential warts, but nothing blocking from what I can see. At worst, you have to add new, generic aware APIs, like in .NET 1 to 2. At best, as an example Array is now shorthand for Array.<any> which matches any Array.<T> in instanceof and the like. Really, this just isn't that scary that you could say it can't be done.

you hijack the error and reject the promise if you get the wrong type?

Sure. The point is it's always legal to throw or kill the runtime, and it's always typesafe to do so instead of returning the wrong type. Handing invalid arguments to callbacks is not as easy to generically handle, but Promise is probably magical enough to get special treatment. I could imagine a Symbol.typeError hook for user types in some fashion, if that was desired.

It would also be prohibitively slow from a runtime's point of view.

I'm not a big fan of type checking of values for several reasons, performance being a big one, yes. But it's essentially the same as checking every value of an array?

@glen-84
Copy link

glen-84 commented Mar 11, 2022

I think that we should avoid going into a full discussion about runtime checking (which could even be limited to primitive types initially), and rather concentrate on the main point, which is:

Could there be any other more appropriate uses for this syntax in future (regardless of basic type checking, advanced type checking, or even something completely different), than just being used as what is essentially another comment syntax.

Does anyone believe that there will be zero better use of the : syntax in the future? (type-related or otherwise)

If not, then there are currently 2 alternatives:

  1. Pragma ("use type-comments"; or whatever), which TC39 want to limit/stop using.
  2. Something that is somehow tied to development environments only.

@benjamingr
Copy link
Collaborator

Does anyone believe that there will be zero better use of the : syntax in the future? (type-related or otherwise)

Yes, I believe reserving this syntax for userland type-checkers is the best use for this syntax for multiple reasons outlined in the README of this repo.

I believe that if any runtime type system or checks would have been specced 10 or 20 years ago we would have been at a much worse place today in terms of being able to write expressive type systems. I also believe that moving the static type system away from the language to tooling is a good thing which is also validated by other languages who have done this.

This isn't just true for Python. It's doubly true for JavaScript where performing meaningful type checks at runtime is very expensive so the type checking would have to be separate from running code anyway.

@glen-84
Copy link

glen-84 commented Mar 11, 2022

Future type-checking in JS doesn't have come close to TS in complexity, it could be limited to basic types, as shown here, to potentially improve performance, instead of the opposite.

TS/Flow would still exist, for more complex checking, and could down-level only the simple/supported types.

Reserving this syntax would be a mistake IMO.

@jamiebuilds
Copy link
Member Author

@simonbuchan
Copy link

A a strawman for the reserved syntax, type check <not open angle bracket or equal> could be reserved? Which could be used for anything from just type check; to type check "https://typescript.org/worker/5.0.4.js" to type check { <some semantic description> }?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests