>> Nikhil Swamy: All right. Well, thank you all for coming to Aseem Rastogi’s End of Internship Talk. Aseem’s been here for the last three months and has had a super productive summer working on Safe TypeScript which he’s worked on pretty much for the whole year actually since last summer. And we've also spent some time this summer looking at a secure multi-body computation. So Aseem’s had this sort of doubleheader sort of internship. So he's going to tell you today about Safe TypeScript, our type safe the version of the TypeScript Compiler. >> Aseem Rastogi: Okay. Thanks Nick. Good morning everyone. Thanks for coming. My name is Aseem Rastogi, and I'm a PhD student at University of Maryland, College Park where I'm advised by Mike Hicks. So I'm going to talk about, as Nick said, about Safe TypeScript which is joint work with Nikhil Swamy. Okay. So TypeScript. It's a language from Microsoft, and the goal is to improve the state of the art in JavaScript programming. It's a gradually typed superset of JavaScript and just putting some codes from the TypeScript website it gives strong tools for large applications such as static checking, symbol-based navigation, auto completion, re-factoring and so on. It provides classes, modules, and interfaces to help you build robust components, and it complies to simple JavaScript. And compared to current JavaScript programming there's a great leap forward. So if you're still writing JavaScript code I would strongly recommend you using TypeScript. Okay, but typing JavaScript is in a way hard because it has so many dynamic programming idioms that assigning, having a sound type system is hard. So TypeScript, like its counterparts Dart and Closure, intentionally gives up on type soundness. What that means is when the code is compiled in JavaScript all the types from the program are uniformly erased and that leads to unsoundness because, for example, [inaudible] at runtime. This unsound type eraser has some benefits. You get very lightweight code generation. So the produced JavaScript is readable; it's in one to one correspondence with the source TypeScript that you write. Since there are no runtime checks the performance is identical to what it would have been had you written plain JavaScript, and finally, types do not get in the way of good programmers. So if you're a good programmer you get it on the type system and if you know what you're doing. But this unsound type erasure comes at some cost, and the cost is that TypeScript components are not robust. Okay. So let's make it a bit concrete on what I mean by TypeScript components are not robust. Let's say I am a service provider, I have some variable X which encapsulates a state which is, let's say an array of numbers, there is an index which is the current index into the array, an index of the number, and it has a method next through which I expect my clients to navigate through this array. So next just returns whatever is the current index and increments the index. And as a service provider my expectation is that clients will only use that this variable X at the interface of this iterator. So I defined an interface, I iterate a generic interface which has a method next, and I call the client with this X variable of mine only if clients have this expected type, and then my expectation from this robust interface is that clients will respect my abstraction. But is it possible in TypeScript? Well, unfortunately no. So here's a client code which has the correct type. It takes an iterator to number but in the body it just writes a dynamic field index and in a sense it's [inaudible] thereby breaking the abstraction. Now this is a well typed TypeScript program. Types are [inaudible] uniformly, it compiles to [inaudible] Script and there is a TypeScript [inaudible] because I expected the clients to use only iterated variables but they can write dynamic properties. But not only this, in fact I want a stronger guarantee. I want that client should not be even able to see my index field. So even if it writes a number to index I want even that to be prohibited because I explicitly said that you should only use my next method and not muck around with the index at all. So as expected from a robust interface I would like clients to not even access my index field. And this is an abstraction violation and in TypeScript it’s not possible to do so currently. Okay. So in this talk I present Safe TypeScript which is a sound and efficient gradual type system for TypeScript. We demonstrate that contrary to the popular belief soundness and efficiency is achievable for idiomatic TypeScript. The sound typing in Safe TypeScript comes with advantages. For example it helps you find type errors early. So we compiled the TypeScript compiler with Safe TypeScript and found 478 type errors. We found one functional correctness bug in NavierStokes which is a heavily used and heavily tested Octane benchmark, but still this bug was written[phonetic] and Safe TypeScript found it. And another benefit of sound typing is that you get provably robust components as opposed to what we just saw. But sound typing comes with its cost, and the cost for one is the runtime performance penalty. Since we have to check all the downcast at runtime we have to instrument the dynamically typed code there is a runtime performance penalty for soundness. And the penalty is, so we compiled 118,000 lines of code using Safe TypeScript which was spread across eight applications and the performance over that ranged from six percent to 3x. Now more details on this will follow later in the talk. Another cost of sound typing is that the programmer needs to understand some subtle corners of JavaScript semantics and he needs to know how our type system works. So it's a trade-off. Okay. So how is Safe TypeScript implemented? So this is the usual TypeScript workflow. The programmer writes an application app.ts, invokes the TypeScript compiler using tsc app.ts , the compiler does syntactic checking, does some type inference and some [inaudible] checking, provides some basic diagnostics and finally emits the JavaScript code. Safe TypeScript is fully integrated into the TypeScript compiler currently in version 0.9.5. Programmer can invoke Safe TypeScript using this one compiler flag minus, minus safe to the TypeScript compiler. So programmer can enable or disable using this compiler flag. And our time checker runs both TypeScript type imprints and provides stricter static checks, and moreover, [inaudible] checks in the emitted JavaScript code. So the kind of static diagnostics that are type checker does are inconsistent subtyping, implicit downcast, variable scoping and unsafe uses of this and so on. Okay. So in the next 15-20 minutes I'm going to walk you through some highlights of our type system and show how Safe TypeScript enforces soundness. So Safe TypeScript type system is object-oriented as with the TypeScript type system, but in contrast to TypeScript which is purely structural, Safe TypeScript distinguishes between nominal classes and structural interfaces to match the JavaScript semantics of classes. Okay. So let's take an example. So let's define a point interface which has two fields X and Y both are type number. We have point class, which again has two public numbers X and Y, again both are type number. We write a function F that expects an argument of type point class and inside the body it's going to assert the argument that it receives is indeed of type point class by doing P instances of PointC. So I didn't say it earlier, but I'm using this function to assert whose semantics is that on false are just I’s and if it’s true then just [inaudible]. Okay. So that's it. We call this function F with a structural [inaudible] with fields X0 and Y0. Now, as you may notice, with this call the assertion inside the function is going to fail because this is not an instance of point class. But for TypeScript this is a well typed program because classes can be converted to structures, structures can be converted to classes and therefore TypeScript will say it’s a well-typed program, it will go on but my assertion will fail at runtime. In Safe TypeScript, however, classes are treated nominally. So what that means is you cannot convert structures to classes and therefore in Safe TypeScript at this point in the code you’ll get a static type error saying that X, the structural type X number, Y number is not a subtype of point class thereby preventing the assertion violation as compile time. On the other hand, if you called F with a new, by creating a new class instance this will be okay with Safe TypeScript. Okay. So now let's modify the example a bit. Let's have function F instead of taking point class takes point interface but we still call F with new point class. Now this is also okay with Safe TypeScript because it allows point classes to be converted to structures. So you cannot go the other way, you cannot convert class structures to classes but you can always create classes structurally using this subtyping provided by Safe TypeScript. So point class is a subtype of point interface. Okay. So next we are going to see how Safe TypeScript instruments the dynamically typed code in order to ensure type safety in that part of the code. So with that point interface and point class as before let's define a function F that takes an argument B of type any and it just writes a property X with string boom. Now there's a call of function G that expects a point interface. It calls F and then asserts that type of field X must be a number. As you can probably see this code is going to fail the assertion but for TypeScript this is well-typed code. And again, this code is, the assertion is going to violate it at runtime. So instead what Safe TypeScript does as a first step towards enforcing types F [inaudible] in the dynamic code it tags the values when they pass from statically typed code to the dynamically typed code. So the compilation of function G, before calling F is going to Shallowtag P with point interface. We'll see how these tags are used later on, but for now the key thing to notice is that before calling F it instruments a call to function Shallowtag which is implemented by runtime labeling. Okay. Now this function Shallowtag, it's a very simple function. It just takes [inaudible] whatever you give it and just combines it with the current RTTI. So the current RTTI of P maybe nothing in which case it’s just going to add point interface to the RTTI of the object. Okay. So now let's see how these tags are used. So now we’ll look at the compilation of the function F. All the writes in the dynamically typed code are instrumented with another runtime function called write which is also provided by Safe TypeScript runtime library, and this write function is going to enforce that when you write a field you’re always going to respect the invariants of the object. So in this case what that means is when you write we are going to look at that P’s RTTI. We’ll see in that RTTI what does P expect for field X and then we'll see if the value boom respects that type. Since P’s RTTI because of the Shallowtag is going to be point interface field X of point interface is a type number. So this will take you from boom string is of type number which it's not so it's going to fail. And we catch the type error early. Okay. So classes are treated a bit special in Safe TypeScript in that the tagging operations and classes are optimized. So let's modify our previous example slightly. Instead of point interface let's say the G function is point class and similarly call the function F remains the same and we call F and then assert again. In this case when this code is compiled there's no tag Safe TypeScript in search no tagging operation for P. But earlier as you saw there was a Shallowtag for point interface. And why is there no tagging? Because classes have primitive tags provided by the JavaScript semantics. When classes are compiled to JavaScript they have a prototype field where the prototype field points to the class that they are instance of and that gives us the RTTI so we need not add our own RTTI. So classes just as a primitive RTTI, no tagging, so you get efficiency if you are using more classes. Okay. So this was what happens when values flow from statically typed code to dynamically typed code. Now we are going to see what happens when values flow the other way around, when dynamically typed code passes values to the statically typed code and they're used [inaudible] downcasts. So we have a function F, which takes P which is of type point interface and it asserts that whatever it got has actually a field X which is of type number. But here's a dynamic caller G which has P of type any and then it calls function F but performs a downcast on P before passing it to F. And then this is a caller of G which has [inaudible] a string. So in TypeScript it’s going to, it is all the types. It's going to erase all the costs, and therefore as you can see, this assertion is going to fail at runtime because X is value boom which is a string and it’s not type number it’s type string. In Safe TypeScript, however, the downcasts are not, it is completely, but downcasts are checked at runtime. So when this function G is compiled the call to F is actually it inserts a call check that P is of type PointI. And this check function is, again, a Safe TypeScript runtime labeling function. It's going to say that okay, you're checking for P’s conformance to PointI, so P should have a field X of type number, it should have a field Y of type number. If it does I’ll add PointI to the tag and return otherwise [inaudible] type error. So they’ll maybe catch the assertion violation early in the code. So all the downcasts I checked in Safe TypeScript. Okay. As with the tagging operations>>: I have a question [inaudible]? >> Aseem Rastogi: Oh, yeah. Definitely. >>: Can you go back a step? >> Aseem Rastogi: Yeah. Please feel free to ask questions. >>: So you have, you’re passing in like object literal that matches the shape of PointI but before you said when I was nominally subtyped, sort of structurally subtyped and then your assertion over here checks structurally instead of nominally. Is>> Aseem Rastogi: The point class was>>: PointC. >> Aseem Rastogi: So PointC was the class point; I was interface. [inaudible]. >>: So if you did not have the cast would you still call a check at the PointI cast? >> Aseem Rastogi: You mean this cast? >>: Sorry. I can see. No, the cast in TypeScript. In function G, rather. >>: The PointI cast. >>: If you did not have the- >> Aseem Rastogi: In that case TypeScript would give you another because it won’t. But we will check [inaudible] even if it doesn't. >>: So you'll still check. >> Aseem Rastogi: We'll still check. Yes. >>: So [inaudible] write function in some previous write? [inaudible] function write into this is the same version of the [inaudible]? Does this mean all the assignments are [inaudible] and you have to explicitly use [inaudible] write function? >> Aseem Rastogi: So if you have an assignment in the dynamic part of the code then it's going to be instrumented with this write. It does not necessarily mean that it's unsafe. So, for example, you could have written a number over here in which case write would have succeeded. >>: So the X function is [inaudible] write automatically? >> Aseem Rastogi: The compiler, the safe type compiler inserts instruments that call to insert this write every time you write a field in the dynamically typed code. >>: The right-hand side of the slides is generated code by the compiler. >>: In the first example where you have the index and the client was actually updating index directly what was the check that prevented that from happening? >> Aseem Rastogi: I’ll tell you about that. >>: Okay. >> Aseem Rastogi: [inaudible] those examples towards the end of the talk. >>: Okay. So your [inaudible] function instead of casting to [inaudible] then your relation for the [inaudible] function just compares structurally, right? >> Aseem Rastogi: No. >>: [inaudible] different checks? >> Aseem Rastogi: We have check depending on what's the target type. So let's see. That’s the next thing. So yeah; it’s a good thing. So let’s say instead PointI I was downcasting it to PointC. But as happens with the tagging even downcasts are optimized for classes. So now instead of taking it structurally I can just do JavaScript native instance of check so I don't need to do structural checks. I can just call JavaScript native instance off. And this is very fast, much optimized and so on. >>: So TypeScript doesn't do that runtime check [inaudible]? Do you know why they chose not to do that? >>: So TypeScript’s really, the philosophy there is [inaudible] and leaving the JavaScript as [inaudible] as possible. Like the moniker is the kind of JavaScript you would've written by and I think any kind of runtime checks, any kind of conserving that and you would have to be, been doing all the work to back to that point. Instead we could give you [inaudible] experience where you can get IntelliSense, you can get it a lot of good error checking but maybe not all the error checking that’s [inaudible]. >>: Then again, you would do this without the cast as well. >> Aseem Rastogi: Yes. Any other questions? Okay. Great. So now comes the part, so if you've seen that when going from statically typed code to dynamically typed code we inserted tags on the objects. But Safe TypeScript is even smarter. It's going to add minimum amount of tags that are needed to ensure type safety, and in addition it's going to provide programmers a way to get around the tagging behaviors. So if the programmer says that I'm willing to use this type system at a much stricter mode I don't need any tagging behavior. Programmer has a way to say that. So that's what I'm going to talk about next. Okay. So let's extend our example a bit. So instead of, so we had a PointI before which was an interface with X and Y fields. Let's write another interface which is 3dPointI, which is a 3d point and it adds a field Z of type number to the interface. We have these small functions F, G and H which, so the function takes this argument at 3dPointI it calls H. H takes an argument of 3dPointI, calls G, G takes an argument of PointI calls F and F takes any. So as you can see going from bottom to top the precision in the type is decreasing. So how is this compiled in Safe TypeScript? There will be some tagging involved. But how does the tagging work? So when you compile F there is no tagging. >>: [inaudible]. >> Aseem Rastogi: I'm sorry, [inaudible]. Thanks. So when you compile mean there is no tagging. And the reason is that there's no loss in position in the argument type. I have a 3dPointI, the [inaudible] expects a 3dPointI so I'm just going to call the function. Then you compile H. There is a loss in precision because I have a 3dPointI but the other guy expects a 2dPointI so there's a loss in precision of field Z and Safe TypeScript is then just going to add only the field Z on the tag. So we call this differential tagging. So you only add parts of the tag that are being lost in precision rather than the complete type. So you just add the field Z and that's it. Okay. Now when you compile function G there’s a complete loss in precision. You're going from point interface to any and so you need to add to the tag point interface. So these tags evolve at runtime. So at this point the tag will be maybe nothing. At this point the tag will be Z, call a number. At this point it’s again going to become a 3dPointI. And again, the Shallowtag just takes the existing tag, combines it with the tag that you give it, and resets that tag. >>: So that records equal the number and then the one above it, PointI, what exactly are those that you're passing? >> Aseem Rastogi: So those are runtime representation of types. >>: Okay. >> Aseem Rastogi: So Safe TypeScript compiles types into the imager JavaScript program and types have some runtime representation like objects. So we have a type class here of different instances of the cast and so on. >>: So for each type you actually emit>> Aseem Rastogi: [inaudible] representation. >>: [inaudible] type representation as well. >>: You'll see it in the demo. >> Aseem Rastogi: Yes. We’ll see it in the demo. >>: Okay. >> Aseem Rastogi: Okay. Right. And function F will be compiled like we don't care. Okay. So, but this is a bit unfortunate. I mean if you're going to say that the compiler is always going to emit tags no matter what server than programmer has no flexibility to say that I don't want this tagging operation. There’s a performance overhead and I want to avoid that. So then Safe TypeScript provides programmers a way to adhere to a stricter type discipline but avoid tagging. So we provide a new operator called erased point types. The semantics of erased types is that a value of type erase D is known to be a D statically but it may not have a runtime type there at runtime. It may not have a type there at runtime. And if programmer writes these erased types in the program he has to conform to a more strict discipline which we'll see in the next slide. But all the rest types it is from the output. So we are compiling these nominal types into the JavaScript output, but the erased types will be erased just like what TypeScript does with of all the types. Okay. So how does programmer say that some types should be erased? So this is how programmer says that. So let's say programmer wants the point interface to be erasable. So he says okay, extend erased. It is an empty interface provided by the Safe TypeScript compiler and it's just doing the [inaudible] that this interface should be marked at instance one. And the other 3dpoint as before. And now let's see how the compilation of this looks like. So when this code is compiled there is no tagging involved in this code. Specifically in function H we were losing precision going from 3dPointI to PointI but it just compiles as is. Previously it was a Shallowtag but now no tagging despite the loss in precision and the reason is that your target type is an erased type so the compiler knows that it’s not going to be used dynamically because it will be erased, so I do not tag it. On the other hand, in function G we are passing erased type to dynamic context and that's a static type error. So Safe TypeScript does not allow you to program dynamically with the erased types because recall that they may not have an RTTI at runtime. We cannot enforce the invariants; therefore you have to use them only statically. So this is a static type error and you cannot pass erased types to dynamic context. Okay. So now we will visit the robust component example. So this was our first example in which>>: So, I mean couldn’t you have allowed that one but then it’s passing the 3dPointI to the PointI and then just to make sure that there was no other downcasts from on the other side when you're asking the two. >> Aseem Rastogi: So that’s what we did. So we allowed 3dpointI to go to PointI>>: The static type error is where? >> Aseem Rastogi: This is in G part on the call [inaudible], give a PointI to any. >>: What's any? >> Aseem Rastogi: That's a static type error. But we did allow 3dPointI to go to PointI and it compiled as is. There was no tagging involved. But if you try to provide PointI to the dynamic context that's a static type error. >>: [inaudible]? And you also wouldn’t be able to downcast from PointI to 3dPointI, right? >> Aseem Rastogi: No. >>: And you also wouldn't be able to index like inside G to index into it with a Z. >> Aseem Rastogi: Exactly. No you cannot. >>: Right. >> Aseem Rastogi: Good point. Yeah because PointI is an erased type all we know that it has X and Y. We don't know anything about it. At runtime it will not have an RTTI so that’s it. You need to adhere to a stricter type discipline. And only then we can guarantee there is property erased types. Right. So using our robust components example. This was our first example in which the client was trying to write index to 1 Boolean value true which was bad. But now Safe TypeScript provides robustness by a [inaudible] type soundness to them. So at runtime this is going to be our type error and Safe TypeScript gives you formal guarantees for that. So there are several useful results that come out of type soundness [inaudible] one of which is the runtime type tags that you add always remain consistent with the object. So if I say that the tag has a field F type number then the object has a field F and it contains number in it. Safe TypeScript invariants always ensure that, and the tags evolve in the subtyping hierarchy. So the tag’s just not, are some ad hoc tags. They always become more and more precise in the subtyping hierarchy. And our full formalization and proofs are in the [inaudible] technical report. Okay. So now this is the more interesting example. In this case we won't even distribute this [inaudible]. This is basically types F in the sense that the client is writing a number to A but we don't want to even this to happen because index is my private field. I don't want to expose index to you. So how can programmer achieve this? So programmers can make iterator to be an erased type. So he says hey, the interface iterator A extends the erased interface and this is going to ensure that this is not a well-typed code anymore. So this will be a static error because you're trying to take it to any and this way you can get stronger abstraction properties from various types. >>: So opaque types, is the erased the same as opaque or is there some sort of, why didn’t you just, I guess the idea of hiding abstractions, right, by saying you can't do anything inside the box has been around. >> Aseem Rastogi: Right. >>: So is it the same, I guess? >>: I mean there are ways, erased types are like you’d expect types to behave in most libraries Their types are often erased in a language like [inaudible] see? And you have to respect to the invariants of, the only way you can use the values by published interface and that's what this is allowing you to do. >>: So it’s just what other languages have anyway. >>: The interesting thing here is that it’s a partial iteration [inaudible]. You don't systematically erase everything. You get to decide exactly what is erased and what is not erased. And it’s not quite the same as opaque types because here the iterator, it’s saying that it has a next field. It's not completely abstract. >>: Right. >>: So you're revealing that this is the interface I published and that’s all you can use. >> Aseem Rastogi: Right. So we have an abstraction theorem for various types as well. It's an our technical report again. Okay. So this finishes the overview of Safe TypeScript system. There are many more features in Safe TypeScript. We have support for generics, we have support for erased, and we support covariant subtyping of erased in a way by having mutability controls. We've support sound over-riding, inheritance and so on. And all these features help us scale our Safe TypeScript to large TypeScript applications. Okay. So some experience with TypeScript. >>: You first. >>: I was just looking at the list and one of the [inaudible] with a lot of JavaScript programmers is this pointer>> Aseem Rastogi: Yes. >>: At how flexible a dynamic that thing is. >> Aseem Rastogi: Yeah. We did not add at this point [inaudible] but Safe TypeScript enforces that you use this pointer in a sound manner and a short introduction is that it reads methods and functions differently. So, for example, you do not allow it to project a method. So if you write a method and you use this parameter in that we won't allow you to project a method out of the object because this will be [inaudible] dynamically to something else. So Safe TypeScript enforces that you use this in its own manner. Does that answer your question? >>: Yeah. I had to think about that for second. >>: So how big is the language manual for Safe TypeScript? How much does it extend, the TypeScript manual? >> Aseem Rastogi: We don't, it's only implemented in the TypeScript. >>: Well, I mean it’s [inaudible] and it has features, and the question is how long does it take to tell people all the features that you provide? [inaudible] erased is one part of it. You're talking about mutability controls. What exactly is that? >> Aseem Rastogi: Yeah. So I mean there is some learning involved. So mutability is basically in TypeScript code. It allows arrays covariant subtyping which is unsound, but it's a useful idiom. So we provide you covariant subtyping of erase provided that the target is that you’d only array. So you can go from 3dpoint array to a point array but that point array, the target point array should be immutable because otherwise it's not sound. So we have these many things like that which are to support the [inaudible] like this. But [inaudible]. >>: [inaudible] checking the report is [inaudible], it formalizes a large part of this TypeScript, and it's larger than any known formalization of TypeScript. So formalizing the whole thing is a huge effort. >>: Yeah. I'm not talking about formalization. I'm more interested in, I’m a programmer that knows TypeScript and I want to know you how to use this. How many pages of text do I have to read until like I understand all the things that are necessary to use it? >>: That's a good question. 12 pages [inaudible] at this point. >>: That's pretty good. >>: I don’t know. Maybe just look on topical. >> Aseem Rastogi: You can just read the technical session and know a lot. You don't have to read the formalization to understand Safe TypeScript. >>: Sorry. One other question. Do you treat properties and indexers invariantly or covariantly? >> Aseem Rastogi: Invariantly because they’re immutable so it’s [inaudible]. You have a question? Okay. So experience with Safe TypeScript. So we used, we Bootstrapped the Safe TypeScript compiler. It's about 90,000 lines of code with 80,000 lines of TypeScript compiler code and 10,000 lines of code written by us. The compiler is heavily, so it's implemented in version 0.9.5, and that compiler code base is heavily class-based which is good for us because then the performance will be minimal, as we saw. Most of the code is carefully type generated. It's written quite well I would say. We found 478 static type errors which are classified as follows, so 98 uses of bi-variant and covariant subtyping, 130 uses of covariant method argument subtyping, 128 cases of variable scoping, 52 cases of projecting a method and leading to a potential unsound use of this and so on. We fixed all of those errors and then we found 26 failed downcasts as well when we ran the compiler out of which five were in the code that we wrote. So, I mean without tool supporting it's very hard to write the sound code. >>: So, like I know [inaudible]? >> Aseem Rastogi: They were type safety violations, but we did not have an example where that would reveal you to some bug. But these are type safety violations where you make some downcast, the downcast was not sound but it so happened that you didn't end up using the variable later on in the code. >>: You might've been doing some kind of [inaudible] check if you have an invariant that once I have this invariant I can [inaudible] the downcast? >>: Or you did the downcast, it succeeded silently, and you projected a field that didn't exist but that undefined, vaporized into a Boolean at some point that it>>: So when you say bi-variant array subtyping you just said that arrays were allowed to keep covariant Safe TypeScript. So how do you have>> Aseem Rastogi: So they're allowed to be covariant if the tag is immutable. But in TypeScript there's no such notion. So we had to add mutibility support for the>>: [inaudible]. >> Aseem Rastogi: Yes, yes, yes. Okay. So the runtime [inaudible] type safety in this experiment was only 15 percent which is quite good I would say. And it's mainly attributed to the fact that most of the code was class-based. So the downcast checks were very cheap because we could do instance of and tagging was just [inaudible]. Okay. So we also compiled the latest TypeScript code version 1.1 with that compiler. That's a much smaller code base. It's 18,000 lines of code as opposed to 80,000 lines of code previously. But there is a design paradigm shift. Instead of heavily class-based the code is now heavily interface-based, so this gave us like the other end of the spectrum. And so we found 81 total static type errors out of which, so mainly they were variable scoping and error subtyping. But the runtime we wanted now increased to three times and it's because interface checking and tagging is costly. >>: [inaudible] new version of TypeScript? [inaudible] smaller? >> Aseem Rastogi: I think it's a previous version but, yeah. >>: [inaudible] runtime is faster. >>: I mean part of it is that the compiler leading up to 1.0 kept changing because the language, we kept mucking with the language and changing it. So it kept getting bloated and bloated because of the code that was left behind. And then we decided okay, let's actually start from scratch and first principles, what we already know and that’s a language that’s not changing so much and then builds something. And we built a much lighter weight [inaudible]. >> Aseem Rastogi: Okay. So as I said, the high overhead is because more structural types, but having said that I would also say that we did this experiment in the last two weeks, so we did not optimize a runtime library for interface as much. So there may be even more useful optimization there. Okay. The third experiment we did was we used Octane, the standard Octane benchmarks. That's a total of 10,000 lines of code. We found one variable scoping bug in NavierStokes which is a heavily tested and heavily used benchmark, but we found this bug which yields to functional incorrectness. So for these benchmarks there was high runtime overhead if you don't have any type annotations. And the overhead ranged from 2.4 times in Splay to 72 times in Crypto and average of 22 times. But once you start adding type annotations to these benchmarks you recover the performance, and for the type benchmarks the average overhead was just 6.5 percent. >>:. How many annotations did you have to write? >> Aseem Rastogi: It's in the paper. I don't have that number here. >>: So it starts as just pure JavaScript? >> Aseem Rastogi: Yeah. It starts at pure JavaScript and then we add annotations to it to make it type and this is what the performance [inaudible]. >>: What's interesting in some sense when you have these benchmarks kind of came to Octane from language like Smalltalk>>: Right. >>: Where, you know, they started out life as typed programs, they became untyped, and now they're sort of became typed again. >> Aseem Rastogi: Okay. So now let's see a small demo. So this is that Safe TypeScript Playground. So I have it at this PointI, I have it at this point class, there’s a function H which is writing X star X2 boom. There’s a function F, which is pointed to this and then G which has three numbers just like 3dPoint interface. Okay. So this is what the first thing happens. We'll adjust our types. So this comes to your question for the type representation is. So it's registering a PointI interface and saying that it has an X field which is of type number by field type number and some other things. This is the class compilation and this is the registration of the class with the runtime system and so on. So if you see below we see that incremental tagging here. So we have X, Y, and Z. PointI is just X and Y so the Shallowtag in this case is just for the Z caller number. Then you go from PointI to any you tag it with the interface type point and finally the write in the dynamically typed code is instrumented by using write field. Okay. So now let's see. Let's try to modify this to user point class and I’ll just recompile it. I don't know how good dynamic thing works. Anyway, so once you annotate it to be a class you know that the tagging disappears. So there's no tagging anymore because tags for classes are free. So when you go from F to H there’s no tagging. Moreover, this guy now has to be checked and tagged to the class type. So recall that structures are not [inaudible] to classes so we have to insert a runtime check and depending on how this guy originated, started its life this check is either going to fail or succeed. Okay. So now let's make this a point in the first part. Let's make this guy erase. So we call it virtual [inaudible] implementation. So this is how you say that an interface should be erased, and if you have to recompile it, so if you recompile it then you should see that right. So now at this point the tagging disappears. Earlier we were tagging at field Z, but now since PointI is erased this just goes through as it is. But at this point we get a static type error which is that you cannot pass any argument to, you cannot pass erased arguments to context any, so this is a type error and Safe TypeScript emits with this unsafe annotation and you can give some semantics to unsafe, whatever you like. Okay. So limitations and work in progress. So we currently do not have eval and other unsafe constructs of the language in Safe TypeScript. But we know how to add them, and this is some work that we did last summer on giving this eval and other unsafe costructs and adversarial type. So we explored on how you can have unsafe JavaScript and still interact in a sound manner. So we think that same ideas can be used in this case. Some implementation limitations. So as I said it’s implemented in version 0.9.5, but we currently do not support external modules. We only support internal modules and the TypeScript compiler has now moved on to be 1.1. And we are having ongoing discussions on how to integrate our Safe TypeScript with the TypeScript compiler version 1.1. Okay. So that's the end of my talk. So I talked about Safe TypeScript. Feel free to download it. It's available on this link for download. We've submitted a POPL paper on this with our terms and [inaudible] and whatnot and [inaudible] paper is here. We have a full technical report which contains hard formalization of a large call of Safe TypeScript and complete proofs, and here's the online Playground which I just showed you in the demo. So thank you. >>: Excuse me. I had a quick question on sort of the overhead you're talking about, right? It seems like there are two parts. One is you just have to do the tag checks, but the other is the particular, I mean you're encoding all the type information in the JavaScript itself, right? So that seems like just pushing all of that type stuff in JavaScript could be pretty expensive. I was wondering if you knew sort of a rough breakdown of what was the cost of just having the conditional check versus the cost of managing all the type information. And then sort of the following one is would it be useful to push that type information in the actual JavaScript runtime? It might be a lot more efficient to represent there and it might be actually useful to the runtime as far as its code gen and execution. >> Aseem Rastogi: Definitely. So I'll answer the second part first. >>: Sure. >> Aseem Rastogi: So it's much more, it's going to be more efficient. And in fact if you have the option of more defined runtime then you can even make use of soundness of Safe TypeScript to, for example, do a [inaudible] that checks the JavaScript virtual machine already does. So if you have X plus Y in the source types we know the X is a number, Y is a number, so we can add them without doing all the case analysis in the JavaScript virtual machine. So if you had the option you can definitely optimize much more. For your first question, I think the cost of translating types is one-time cost. It just happens during>>: But I guess when you're doing a comparison you type X and you have type Y. Like if you're representing them as strings or something>> Aseem Rastogi: Yeah. >>: You're doing a lot of stuff there. I was sort of wondering like>>: We're trying to be careful about using it a lot of sharing. So the same type is going to be [inaudible] program and we’ll try to use reference [inaudible] as much as possible. We've tried to use nominal types as much as possible. If a type is nominal we can do a nominal check as opposed to a structural check. >> Aseem Rastogi: We are caching off, for example, if you are in interface and you want to check if some object complies to that interface we go to the structural interface and we cache all the structural representations also. So we are trying to optimize it, but then at some point for structural types you have to go through each field and do these expensive checks. >>: All right. >> Aseem Rastogi: But I don't think we have a breakdown on just that because checks in a way involve every single type. So I don't know we can separate cost on just the checks versus traversing their type. >>: Well, I guess I was thinking that the transversal part versus just the if range, right? I mean you always have the same if and do a little call through there, and then there's the other cost which is actually traversing the type information or how you could get actual resolution of that. And one of those you’re always have to pay, right? You always have to do the if check. The other one can be optimized more or less than the [inaudible]. Whatever representations you have. >>: I guess the other thing is that it's nice to generate a code that's just in Script five and apply it. Changing the engine would be great but would also scope down its usability. >>: So I also have two questions. So with your instance of checks, not for the classes, how does that deal with inheritance and base classes? If I say I have a drive and I want to check instance of base, so how does that work with>> Aseem Rastogi: So in this inheritance system compiled by TypeScript it's going to maintain the prototype. So, the base is going to eventually appear in the prototype chain of the derived instance. So the instance of check will work and we'll use the instance of check itself. >>: Okay. We’ll just piggyback on the>> Aseem Rastogi: Yes. You can just piggyback on the JavaScript instance of check. >>: And my second question is you showed kind of properties. So how does the RTTI work with signatures and overloads? It might be a very big question. >> Aseem Rastogi: Right. So if you have methods in the type then those methods are also put in the RTTI, and if you call those methods dynamically we will do dynamic type checking for arguments and for return type and so on. >>: Including what? Loose signatures and interface? >> Aseem Rastogi: You mean like overloads? >>: Yeah. But without, like not methods but loose signatures. So I have an interface I that is [inaudible]. >>: We support that too. So the way, for those of you not TypeScript experts, correct me if I'm wrong on this one, so the way TypeScript supports overloading is that you get to write, you have an implementation of a function and then you get to supply multiple signatures of that function that need not be related by subtyping to the implementation signatures. I can write a function that is a number function and then claim it as type any [inaudible] also. That would be fine. >>: They do have to be related by subtype, but it's>>: But it's your weak notion of subtyping, right? So for soundness what we do is we say okay, what goes into the RTTI is the implementation signature only, and if during type checking we will piggyback on your type inference results to resolve to the overload that TypeScript chooses; but at runtime we will check against the implementation signature which the only sound signature assumption. Does that answer your question? >>: Yeah. Part of it. There’s also the case where you have no implementation. >>: Yes. So when you have no implementation then what you can do is to go, so we do this, so the TypeScript programs are all type with respect to this library that gives types to the JavaScript environment. It's like a 15,000 lines speck. So we implicitly treat every type preparation in the .ts as an erased type meaning that you can some external library is claiming that it provides to you a function that behaves both like an any to any function as well as number to number function. And you're willing to trust that array.splice behaves in this kind of ad hoc homomorphic way, and then since it's erased there’s no runtime representation for it, and as long as you call array.splice on a value where the receiver has static type array you will just resolve it the way the captured compiler [inaudible] and there’s no runtime check. >>: So if I declare interface of my own code>>: And then you can mock that interface that’s erased and you can just use it. But you would have to then respect the static typing discipline for that particular, for values of that integer. >>: I see. >> Aseem Rastogi: So that's how we support [inaudible].ts. So we mark all the specification in the [inaudible].ts to be erased so that we don't add tags to things that are not ours. >>: Other questions? Let's thank Aseem.