Skip to end of metadata
Go to start of metadata

Introduction

We want type checking for Clojurescript.

[Design] New Host, New Types

Javascript has a different primitive types to JVM. What are they? Are they important enough to include in the type system for CLJS?

Lots of things in Java are Classes. Does Javascript have classes? Does GClosure have a similar notion? What does CLJS use?

What is a deftype in CLJS? eg. Is it a Class with fields? Is it just a structural type?

[Design, Theory] Built on Protocols

The types in TC are fairly sophisticated for combining interfaces and protocols. We have an `Extends` constructor that takes positive and negative information on things it can extend.

eg. `(Extends [(Seqable t)] :without [Number])` is a type that implements `(Seqable t)` and explicitly does not implement `Number`.

ClojureScript brings an interesting challenge with its core protocols, because there is no explicit inheritance. In Clojure, the corresponding solution is to use interfaces with inheritance. eg. `(IPersistentMap t)` is a `(Seqable t)` and `(IPersistentCollection t)` explicitly because the interface extends both these types.

In CLJS, `IMap` is a protocol. There is no explicit inheritance of `Seqable` or `ICollection`. This seems to imply that we need quite large type aliases like this one:

 

This complicates even further a problem I have in Typed Clojure.

Consider code like this:

 

What do we update the type of x to? `(Seqable Number)`? `(ICollection Number)`? Some combination? Ideally we'd want the equivalent of `(Vec Number)`, but this seems pretty hard to achieve.

This kind of updating of an expressive collection type seems like it might be useful, but maybe it's just enough to update the `Seqable` or `ICollection` portion of the type?

[Implementation] High-level, write in CLJ vs CLJS

For high-level implementation, we have two options:

  1. Rewrite TC in CLJS
  2. Reuse the type infrastructure of TC and provide "type-checking as a service", callable from a CLJS REPL

Option 1 is a lot more effort. We probably need a full CLJS compiler available anyway, which probably also implies Java is available at development time.

Option 2 is probably the better way to go.

Clojurescript patches

These things need to be improved in Clojurescript:

  • Preserve original operation of js* (fixed)
  • Track extenders of protocols (CLJS-570)
Labels:
  1. Aug 05, 2013

    The JavaScript primitive types are Array, Function, Object, Date, Number, Boolean, String. And yes I think they should be part of the type system.

    JavaScript does not have classes though it may get something like that with ES6, but it would mostly be sugar as far as I understand it. You use functions to create type constructors - ClojureScript deftype leverages this directly. However prototypal inheritance gives you subtyping.

    GClosure does have its own notion of extending classes but I don't think CLJS will ever have anything to do with it since it is GClosure specific and not a property of JS the language.

    Yes we don't have protocol inheritance in ClojureScript but I don't think this is really an issue.

    As to your other point, why do we need to "update" x? This is probably giving away my unfamiliarity with how Typed Clojure works internally Smile Since the result is discarded I don't know why you need to update x.

    To the final point I think CLJS-in-CLJS is stills a ways off and even if we do arrive it will be an option not the default. I think writing Typed Clojure in ClojureScript would be a big distraction Smile