
Why we're supporting Typed Clojure - pbiggar
http://blog.circleci.com/supporting-typed-clojure/
======
brudgers
The paper behind Racket's new contract system which allows optional typing to
be determined at runtime or compile time or both and across modules:

[http://www.eecs.northwestern.edu/~robby/pubs/papers/oopsla20...](http://www.eecs.northwestern.edu/~robby/pubs/papers/oopsla2012-stff.pdf)

~~~
ambrosebs
That's insane.

~~~
bionerd
For a very long time I've regarded Racket as a purely educational Scheme
dialect not particularly useful for real work. It was only a few months ago
that I actually bothered to look at it's ( _amazing!_ ) documentation [1] and
realized how wrong I've been. It's incredible what are the Racket guys doing
and what they've already achieved. The Typed Racket [2, 3] is "only" a cherry
on top.

[1] [http://docs.racket-lang.org/](http://docs.racket-lang.org/)

[2] The Type Racket Guide: [http://docs.racket-lang.org/ts-
guide/](http://docs.racket-lang.org/ts-guide/)

[3] The Type Racket Reference: [http://docs.racket-lang.org/ts-
reference/](http://docs.racket-lang.org/ts-reference/)

~~~
brudgers
What I see is that in part the transition from MZscheme to Racket has meant
that a new generation of Lisp oriented academics are in PLT leadership roles -
this is something Felleisen has long promoted in his own work (e.g. listing
junior authors first on joint papers since everyone already knows who he is).

In other words, Racket is now being driven by research into computation and
the earlier generation's area of emphasis - the pedagogy of computation - is
being treated as a largely solved problem. This is not to say that PLT is no
longer pursuing pedagogical projects or that in the past there wasn't
significant discovery and invention within computation, only that the _How to
Design Programs_ project offers a mature and battle tested framework for
teaching introductory programming and there is not a lot of reason to revisit
it.

One of the things that attracts me to Racket - beyond the fact that it is a
Lisp - is that the documentation is full stack. I was aware of the paper
because there is a link within the Racket documentation of the contract
system. The payoff from reading a paper that is specifically organized around
the language at hand is intellectual continuity and when the language is a
Lisp that continuity extends all the way from implementation to the lambda
calculus.

------
breckinloggins
One of the best ways to get people to support optional typing in dynamic
languages is to make sure their tools can read those types and provide
metadata.

Program verification is cool, but enabling "intellisense" on a hash is even
cooler.

~~~
ambrosebs
What is intellisense on a hash?

~~~
pbiggar
Autocompletion on the keys of a hash.

~~~
brandonbloom
I know that in several communities, "hash" and "hash map" are synonymous.
However, in Clojure hash maps are only one of several map implementations. We
have implementations backed by linear array scans, prefix trees, and other
data structures too.

The word "hash" a shorthand for the noun-phrase "hash code" (aka "digest") and
a verb for the process of creating hash codes.

~~~
breckinloggins
Oops. Sorry about that; I was still thinking in Ruby (day job) mode!

------
anaphor
I still don't think this is worth supporting if you don't use Clojure. As far
as dynamic languages go, I already use Racket quite a bit and as mentioned I
can just use Typed Racket if I want, or I can use Racket's excellent contract
system for some things (sparingly if I need good performance). Also I doubt it
will catch on in the Python community, which is hostile to this sort of thing.
JavaScript is perhaps a good use for it but there are already typed languages
that run in the browser.

~~~
ambrosebs
FWIW I've been pushing Typed Clojure in interesting directions that can be
directly applied back to Typed Racket. The implementations are so similar that
there is good potential for cross pollination.

~~~
anaphor
Fair enough, it does sound like an interesting research project, I'm just not
sure what will come of it. Can you make any speculations about what those
directions might be? Or is it too early? Edit: global type inference? I
thought that was infeasible for TR and Clojure at the moment?

~~~
ambrosebs
Also I'm not aware of a tool to "guess" top level annotations for Typed
Racket. This is an area I want to explore further, soon.

~~~
anaphor
One of the TR maintainers (samth?) told me on IRC a while ago that it is very
infeasible to do global type inference (top level) for TR. So I'm not sure how
much you could get done in so short a time.

~~~
ambrosebs
Yep that's correct. I want a tool that infers a rough approximation of top-
levels to accelerate the process of porting untyped code to be typed. The
programmer would inspect the annotations manually and fix any inaccurate ones,
and then run the type checker.

~~~
moomin
I'm far from an expert on this, but F# has no requirement for all forms to be
explicitly typed, so I'm a bit puzzled as to why this is hard.

~~~
ambrosebs
Typed Clojure's type system is too rich to avoid top-level annotations. It's a
similar situation to Scala.

------
dribnet
Pleased to see Rich Hickey also supporting this.
[http://www.indiegogo.com/individuals/222990/activities](http://www.indiegogo.com/individuals/222990/activities)

------
zcrar70
Typescript also uses 'gradual' typing. See
[http://siek.blogspot.co.uk/2012/10/is-typescript-
gradually-t...](http://siek.blogspot.co.uk/2012/10/is-typescript-gradually-
typed-part-1.html) \- Siek is referenced in the original post, too.

Clojure's type system sounds more powerful than Typescript's though.

~~~
ambrosebs
AFAIK Typescript is level 1 gradual typing. Typed Clojure is also level 1, but
I'm aiming for level 3.

I guess Typed Clojure is more powerful than Typescript in a few ways, but it's
more about how well the type system fits the language. I've never used
Typescript, but it seems to fit nicely, with interesting tradeoffs.

------
pjmlp
This is great news for Clojure.

Based on my experience, dynamic languages without optional typing make large
scale enterprise development unbearable.

Sure, one should be writing unit tests, but in the enterprise context those
tests rarely do exist, or if they do, either don't test what they should or
are so complex that invalidate any re-factoring taking place.

~~~
quatrevingts
Do you have any experience with the inverse statement? That is, have you had a
good experience with optional types in an enterprise context?

I'm curious how many runtime errors persist due to the optionality of the type
system. Perhaps code standards requiring all "library" code to be typed would
be a good balance.

~~~
pjmlp
Just kind of.

Most enterprise customers I have worked with, favour dynamic languages just
for scripting tasks, while using static typed ones for the large scale
projects.

By large scale, I mean, projects with at least three development sites, at
least 30 developers, all the different set of skills. With lots of attrition.

The only time I saw it working, was in a project done with TCL, which lacks
optional types, but everyone on team was a top developer, the team was small,
and located on the same open space. So startup world, not enterprise.

------
mseebach
An introduction to typed clojure (strangely missing from both the blog post
and the IndieGoGo campaign):

[http://www.clojure.net/2013/03/14/Typed-
Clojure/](http://www.clojure.net/2013/03/14/Typed-Clojure/)

------
cabalamat
People interested in optional types for Python may be interested in my @typ
decorator that implements them:
[https://github.com/cabalamat/ulib/blob/master/debugdec.md](https://github.com/cabalamat/ulib/blob/master/debugdec.md)

Sample:

    
    
        @typ((int,float), ret=(int,float))
        def square(x):
            return x*x
    

Here the parameter x is an int or float, and so is the return type.

It doesn't currently let you compose types, but that wouldn't be too difficult
to add, e.g. {str:int} could mean a dictionary whose keys are strings and
values are integers.

~~~
acjohnson55
That's okay, but that doesn't seem to help much to verify your type
correctness before runtime, which seems to me to be a big part of the benefit
of type checking. Also, what you'd really want is something that implements
type variables like:

    
    
        @typ[A implements *](A, ret=A)
        def square(x):
            return x * x
    

But I don't know how you'd do that in Python.

BTW, your printargs looks pretty cool! I might just makes something like that
for JS...

~~~
cabalamat
> that doesn't seem to help much to verify your type correctness before
> runtime

I don't think that's possible in Python.

> Also, what you'd really want is something that implements type variables

That is possible, you could check what the type of the incoming parameter is
and then check that the return value is the same type. I'm not sure that
there's an obvious syntax for saying this, but one could always send a string
to @typ and have it parse some made-up syntax.

I suspect this would be a lot of effort and it would probably make sens to use
a typed language, instead of trying to shoehorn it into Python. I invented
@typ so I could quickly document the types in my functions, & with the added
advantage that it catches some errors.

> your printargs looks pretty cool! I might just makes something like that for
> JS...

I look forward to seeing it.

------
wcummings
This guy is a little too souped on optional type-checking. This has existed in
erlang for years, in the form of dialyzer (which allows for compile time
validation of complex nested data structures), and in any dynamic language a
good developer is using pre-checks & post-checks (in the case of js) or a
combination of tagged values and pattern matching to ensure type-checking at
runtime.

It's a nice feature, but calling it "one of the biggest advancements to
dynamic programming languages in the last few decades" is ignorant.

~~~
pbiggar
OP here. I do actually believe what I said.

Pre- and post-checks are of course possible, but I've rarely seen them used in
practice. More importantly, they can't be used to provide any sort of
correctness guarantee, which static typing can.

I'm not sure what you mean by tagged values and pattern matching - I know what
those concepts are, but I think you're saying they're widely used by good
developers? I have not seen evidence for this.

The reason I call it one of the biggest advancements is that it is actually
being used in production, has low overhead (both in cognitive load and
performance-wise), and actually handles the complexities of duck-typing. It
shows that it is practical. (By contrast, Erlang is sufficiently different to
most other dynamic languages, both in use case and semantics, that it is
difficult to generalize from Erlang to say Python).

~~~
wcummings
>Pre- and post-checks are of course possible, but I've rarely seen them used
in practice.

I agree, I wish more people (especially Javascript developers) saw the value
of pre (and post!) checking.

>The reason I call it one of the biggest advancements is that it is actually
being used in production, has low overhead (both in cognitive load and
performance-wise), and actually handles the complexities of duck-typing. It
shows that it is practical. (By contrast, Erlang is sufficiently different to
most other dynamic languages, both in use case and semantics, that it is
difficult to generalize from Erlang to say Python).

This is fair, I just meant to point out that conceptually this isn't new, it's
just a new implementation. Can you expand a bit on what you said about duck-
typing?

~~~
pbiggar
So most type checking, especially in how people write pre- and post-checks, is
of the form "is this an X", for example, "is this object an instance of the
String class". In duck-typed languages, that's not good enough, because you're
not passing an instance of a subclass of a string, you're passing "something
that quacks like a string" (aka implements the necessary interfaces to act
string-like).

So the type of an object in a duck-typed language is based on the functions
and fields it has _now_, not its instance type. Since there is no name for
that type, you cannot do "nominal" typing. Instead, you must use "structural"
typing, which checks its structure. This is exactly what Typed Clojure does.

An example of how that works in practice, is you say that the 2nd parameter
must be a map with one of the following configurations: a key named :foo and a
key named :bar, both mapping to strings, or a key named :error, mapping to a
string.

------
draegtun
Perl6 & Rebol are some other examples of dynamic languages which come with
_optional typing_.

NB. And I believe Perl6 in certain cases will/can raise compile-time type
errors.

------
dep_b
There one thing that really stirred my interest:

 _nil isn’t allowed_

If this really is what I think it is (a certain reference to a class can never
be nil) then I am really excited. It never made sense to me that someone was
able to call a function I wrote that really needed instances with nils
instead, so I was forced to check and throw in case they did. It's just not
clear and it leads to a lot of unnecessary checking or nil pointer exceptions.

~~~
ambrosebs
nil is explicit in Typed Clojure, and it's a goal to statically avoid misuses
of nil.

This rough screencast describes on aspect to the approach
[http://vimeo.com/55280915](http://vimeo.com/55280915)

------
heyadayo
Check out cobra, python inspired -- it already helped developers "realize how
great optional typing can be in everyday code": [http://cobra-
language.com/docs/why/](http://cobra-language.com/docs/why/)

Great language too if you're down with .NET.

------
jafaku
> Typed Clojure is one of the biggest advancements to dynamic programming
> languages in the last few decades. It shows that you can have the amazing
> flexibility of a dynamic language, while providing lightweight, optional
> typing.

I'm sure there have been great advances. But you are showcasing this as if it
was a completely new idea, even though PHP has been using it for a long time.
Correct me if I'm wrong.

~~~
TylerE
You're totally wrong. For one thing, PHP coerces WAY too much for any type
system to be effective. That's just plain duck typing.

~~~
jafaku
What do you mean?

~~~
TylerE
I'd like to see your defintion of structural typing in PHP. (Hint: Not casts,
not lots of manual gettype)

~~~
jafaku
I don't have a definition, I just use the thing. That's why I'm asking, I'm
not a computer scientist. Eg:

    
    
        $f = function helloAction(Http\Request $request) {
            $response = new Http\Response("Hello " . $request->query->get('name'), 200);
            $response->setMa // at this point the IDE will show a list of methods like 'setMaxAge($time)', because it knows its type
        };
    

Now I can pass $f somewhere else, like this:

    
    
        $someObject->someMethod($f);
    

And the method can accept it like this:

    
    
        protected method someMethod($f) {} // no checks!
    

Or like this:

    
    
        protected method someMethod(\Closure $f) {} // only an argument of type Closure will be accepted.
    

So those are types for me. If you are asking for something like this:

    
    
        Response $r = new Response(...);
    

Then yeah, PHP doesn't have that. Though I don't know why we would want that,
it's kind of redundant.

~~~
tel
The redundancy can be alleviated by type inference, but it's also kind of
nice. The 'Response' on the left is your _expectation_ about what $r is, while
the one on the right is your _implementation_ of that expectation. The
separation is very important.

Of course, in this example, it's silly and type inference would be used to
ensure that you don't need to write the left side.

The advantage is that before running your code you can suss out much greater
degrees of what your code "could possibly mean". The \Closure bit is a start,
but it needs to fail prior to running to be statically typed. It also could
potentially include much more information like (\Closure[Http\Request ->
Http\Response]) and reject even more bad arguments.

------
memracom
There is already typing in Clojure (and Python and Ruby). It`s called "100%
unit test coverage". If you want it, you can have it now.

~~~
acjohnson55
Can 100% unit test coverage give you intellisense, real-time warnings, and
refactoring capabilities? Nope.

Unit testing is great for verifying that a piece of code works conforms to
specification, but typing verifies that you're using a piece of code as
expected. Two different things.

