Thanks for reading our paper! We're happy you liked our work and will use the next paragraphs to answer questions embedded in your reviews. * RA * > The paper is on the lower end in novelty… the only contribution of > this paper is the addition of concrete types and nominal subtyping. Yes! It's one of those papers trying to get the devil out of those details. There are two reasons why we think that the work is worth publishing: a) TypeScript has moved to adopt structural subtyping. We show that with a small change to the existing TypeScript semantics it would be possible to get a sound sublanguage within TypeScript. Coincidentally we just learned that Google is looking at variant of JS called SoundScript that makes many similar choices, so we may be on the right track. b) Friends who spend all their time implementing JS VMs told us that type information, of the kind we provide, is useless for performance because the VMs are doing such a great job inferring types are runtime. Our performance numbers are encouraging in that respect — also they are more reliable than VM optimizations as they are not dependent on fragile heuristics. > How easy/difficult is it to add annotations… Easy because the type system is simple. As discussed in the paper, we were able to run all the TypeScript benchmarks (of the SafeScript POPL paper) out of the box. This was quite surprising to us as the type systems are different. We guess that none of those benchmarks exercised the difference. We had expected to have some refactoring to do, but no. For DeltaBlue (which had the largest number of annotations, a revolting 186), the programmer effort was ~30 minutes for someone with no knowledge of the algorithm being implemented. In general the type annotations are simple and straightforward to insert, but there are programs with many functions and variables that all have to be annotated. Tedious… likely automatable. * RB * > The type safety theorems are presented without proof We have pencil and papers proofs, on actual paper. Space permitting, we’ll sketch the strategy and key invariants in the next revision. Our implementation of the type-checker closely follows the typing rules of the formalization and has been exercised on large programs. * RA * > The performance evaluation leaves a lot to be desired... Are they > real improvements or execution noises? The authors did not measure > deviations among running times… Argh. We have all the statistical data… Somehow a better graph did not make it into this version paper. We will definitely fix. The speedups are statistically significant, but 3% is low enough that it could be just luck, the larger speedups are genuine improvements. As for the how: the TruffleJS runtime supports intrinsics to describe object layout; our compiler exploits those to describe the layout of concrete objects, accesses to fields can thus be optimized. * RC * > …can you optimize numeric variables, to allow the unboxed representation… No, this is not supported by the underlying VM. It is however an obvious application of concrete type annotations. * RC * > I expect that your implementation would also need to introduce > wrappers for untyped functions being used at concrete types. ... > but the previous sections read as if you won't end up needing them > at all. Right. The text should be clearer: there are no wrappers in a concretely typed context. * RC * > Similarly, you mention earlier in the paper that your interface > types are structural, so it seems, like function types, you would > need some sort of wrapping, i.e., annotating a class with a concrete > interface type requires wrapping parts of the class to ensure that, > say, the types of methods are adhered to. However, interfaces don't > appear in the model, and I don't see this discussed in your > implementation section. Are interfaces not allowed to appear within > concrete types? Interfaces can't be concrete. * RB * > [TObj] surely has some preconditions. I'd expect something like "If > Gamma |- O[s]:C[s] for each s in fields(C) then Gamma |- { O | !C} : > !C" and "Gamma |- { O | any } : any". Indeed, we will update the rule as suggested (in practice the programmer creates terms with run-time type-tag !C only via new C(), which implies the checks above). > Field update is only allowed on non-function types, and it would be > helpful to know why. Arbitrary field update is allowed on dynamic objects, as in JS. On concretely or optionally typed objects, we prevent update of methods because that could end up requiring wrappers. > [TDelete] only allows delete on any, which seems quite restrictive. Indeed the implementation allows delete on concretely typed objects provided that the field has been added subsequently and is not part of the class interface. The semantics has been simplified. > The operational semantics adds some extra dynamic checks above those > provided by JS, for example delete{O | !C}[s] fails if s is a field > of C. Did you include the penalty of these extra checks in your > experimental results? Yes, but we could not measure those costs in any of our benchmarks. > Some discussion of why any is not the top type would be useful, and > of the reason for distinguishing any and Object. Thanks. Shortly: Any is not the top type because values that mention concrete types must be wrapped whenever they are injected into the dynamic world. This is performed at run-time when executing the explicit casts to any (with no loss of generality as casts to any always succeed). Was any the top of the type hierarchy, then casts would not be needed and the runtime would miss the "hooks" to insert the dynamic type-checks. > There is no derivation for !C <: Object. !C <: !Object <: Object.