YATT (Yet Another Typing Thread)

Luke Gorrie luke@REDACTED
Sat Sep 20 11:25:03 CEST 2003


Hello,

This is probably a bad time to start a different thread about typing
in Erlang. But I'm doing it anyway :-). In my playing around I have
found a nice type system, and would like to put it on the radar of
Erlang hackers and hear what people doing static-typing for Erlang
think of it.

I refer to CMU Common Lisp (CMUCL). This is a free Lisp system that
has been actively developed since early in the 1980s and continues
today. http://www.cons.org/cmucl/

They have a very interesting approach to typing which is both static
and dynamic. They don't make the language fully statically typed, but
instead do as much as possible with what type information they have
available. The type information available in a Common Lisp program is
very similar to what's available in an Erlang program, mostly from
type-checking guards. This makes me think the CMUCL approach may work
well for Erlang too.

CMUCL is interesting because they do a _lot_ with the type information
available. For example:

  * Compiler optimizations. e.g. if some variables are declared to be
  floats, you can generate more efficient code for doing arithmetic on
  them. Erlang/BEAM does this too - that's why there are so many
  'float(X)' type declarations in the Wings3D code that Ulf quoted
  (excerpted down below). This is safe because before the
  float-specific code is executed the arguments are runtime-checked to
  actually be floats -- like in Erlang, type guards/declarations are
  not blindly trusted, they are treated as assertions to be checked.

  * Type inference. If some variables have specified types, this is
  used to figure out the types of more variables. For example, with:

     foo(X, Y) when float(X) ->
         Z = X * Y,
         ...

  You can figure out that Z is also a float. You also know that Y has
  to be a number in any of the "..." code, because otherwise it would
  have crashed with badarg on the the first line before getting that
  far.

  * Efficiency notes. If you want a function to be fast, you can tell
  the compiler so. It will then report every optimization opportunity
  that was missed because of insufficient type information.

  Take the Wings3d example again: they have added float(X)
  declarations in strategic places to generate fast code. Exactly
  which declarations they add are, I believe, based on deep knowledge
  of the compiler and BEAM.

  In CMUCL it is easier for mortals. You write the function with no
  type declarations, and say "this has to be fast". Then the compiler
  will print notes to the effect that "Hey, I could generate faster
  code if I knew that X, Y, and Z were floats". Then, if you know that
  they really should be floats, you add the type guards and get the
  good code. Thus you can do effective low-level optimization without
  intimate knowledge of the compiler.

  * Conservative static type error detection. If the compiler sees
  that you will cause a type error, it will give you a warning. It
  does this when it can prove that your code _will_ lead to a type
  error, not just that it might. For example, this code would generate
  a warning:

      X + length(X)

  because it could never work correctly: X has to be both a list and
  an integer, which is impossible. Note that it's a warning and not an
  error: maybe you want to test some other parts of the program before
  you fix this.

Overall you get a lot of benefits and none of the drawbacks usually
associated (by us Erlang programmers at least) with static typing -
i.e. it makes no restrictions on how you write code and you can ignore
the warnings if you want. In practice you do not ignore the warnings,
because the compiler only bothers to warn you when you've almost
certainly made a mistake.

So what does this mean to us Erlang programmers? Is this something
we'd like? Are recent compiler/BEAM developments already leading us in
this direction? Are there some fundamental reasons that this would not
work as well for Erlang that the type-theorists can tell us? Should I
shut the hell up about Lisp already? :-)

In any case, there are worse ways to spend a lazy afternoon than
reading the CMU Common Lisp user manual -- particularly the section on
advanced compiler usage. It is a seriously excellent work of
programming language implementation, even if you aren't interested in
Lisp per se. The URL is:

  http://www.cons.org/cmucl/doc/index.html

Also -- I don't like playing the luddite, but I never understand
conference talks about type systems. I'm not familiar with the
formalism(s) that people use and just see a lot of greek letters. Can
someone explain what formalisms people are using (e.g. is it
declarative semantics, or..?), and perhaps point to a book or two that
one could read to appreciate what's going on?

Here's the Wings3D code that Ulf quoted:

    twist_fun(y, {Cx,_,Cz}) ->
        fun(U, Min, {X0,Y,Z0})
           when float(U), float(Min), float(X0), float(Y), float(Z0) ->
                Angle = U*(Y-Min),
                Cos = math:cos(Angle),
                Sin = math:sin(Angle),
                X = X0 - Cx,
                Z = Z0 - Cz,
                {X*Cos+Z*Sin+Cx,Y,Z*Cos-X*Sin+Cz}
        end;

(BTW, comparison to CL also suggests another possible notation for
writing type guards: "when float(U, Min, X0, Y, Z0) ->", i.e. to make
the type guards n-ary.)

Cheers,
Luke




More information about the erlang-questions mailing list