Wednesday, September 2, 2009

Unit Tests in the Core Language for Improved Duckiness

I've thought some about how you could make a language that looks ducky (no types required) but still is semi-statically typed for speed, toolability, and so on. One option is the run-time tracing option used by Psyco, TraceMonkey, and so on. That is, see what types are needed as the program runs and JIT specialized code on the fly.

Another alternative, really making things more static is to make unit tests an important part of compiling code. Sort of like how to need to give examples to C++ for template creation. It only knows what typed versions it needs to generate if you try to use those types.

For example:

def factorial(n, one) = {
var result = one
while (n > one) {
result *= n
n -= one

No types to be seen. Expected available operations ('>', '*', '-'), yes. Side note, that need to specify the "one" above is annoying, but I don't want to think of anything more clever at the moment.

Now, in my unit tests, I could say this:

assertThat(1) == factorial(1, 1)
assertThat(24) == factorial(4, 1)
assertThat(6.0) == factorial(3.0, 1.0)

If the main compiler/builder is aware of the unit tests (which I should have anyway, right?), it is aware of which types are available for the function/class/whatever in question. So, 'factorial' clearly needs both integer and floating-point (or whatever) implementations. I'm being vague on the language specifics here. Also, the main code base could also be used for inference. The unit tests just have a chance to go beyond that.

Such a system should even be able to determine which spots are co or contravariant. Not sure how many examples would be needed. I'm not even sure if this a good idea, but it's interesting to think about. Maybe some type placeholders, like templates in C++, would still be helpful.

This technique wouldn't require unit tests to be embedded in the main code. I personally tend to like the current common technique of parallel dirs. Main code here, tests over there.

Oh, and I also like screaming fast compilers. I'm afraid fanciness like this might slow things down just a tad ...


  1. What's wrong with type inference? You don't need to write even the unit tests!

  2. That's great for locals. I'm talking about a larger scale here. For good or ill.

  3. By the way, understood that not all languages limit inference to locals. Seems like I've heard that generalized type inference is NP-Complete, though. I haven't studied it myself. Just recall having seen that mentioned in passing sometime. Also, sometimes you might not want every type with related operation names to apply. This technique here allows some level between implicit and explicit. Again, I don't necessarily think it's good. Just something to consider.

    Of course, without some kind of dynamic nature, it's hard to apply anything like this forward to types not seen at compile type.