General musings on programming languages, and Java.

Saturday, September 19, 2009

Is it actually type inference we need, or just a better syntax for type declarations?

I've looked a little at Typed Scheme recently, because the main problem I have with Lisp is that it's untyped, but I lack the imagination and skill to make a typed version.

Typed Scheme has local type inference, like C#'s var, but other than that, if you want it typed, you write it typed. The types go before the declarations, like in Haskell, which provoked a surprising thought, namely the title of this post.

In Scala, Java and C#, type inference always seems desirable. Let's look at how you'd declare a method that takes a list, an int and returns an element of that list in each language:

Scala: def method[A](list: List[A], num: Int): A // the : Float would normally be inferred if left out.

Java: A <A> method(List<A> list, int num)

C#: A method<A>(List<A> list, int num)

Those aren't amazingly bad, but compare them to Python:

def method(list, num)

or Scheme:

(define (method the-list num))

The untyped versions are undoubtedly prettier, though far less informative. And compare now to Haskell:

method list num = ...

Haskell's version uses type inference; the types of list and num will be inferred by their usage in the function. But lots of Haskell programmers will write the type explicitly for all functions. I think they do this because in Haskell the syntax for explicit types is better than in Scala, C# and Java:

method :: [a] -> Int -> a
method list num = ...

You can read that first line as "method takes a list of some type we'll call a, an Int and returns an a."

The specific way in which the Haskell (and Typed Scheme) mechanisms are better is that the type information isn't mixed up in the syntax for naming parameters (and after Scala and C# add optional parameters, that too). It'll never happen for any, but I'd like to see the following syntaxes become possible:

method[A] : (List[A], Int) => A
def method(list, num) ..

A method<A> (List<A>, int)
method(list, num) { .. }

The programming language I'll one day write currently looks a bit like Typed Scheme. Like Typed Scheme, it has local variable type inference, but not function definition type inference. I realise that supporting one but not the other is a bit inconsistent, so I know I have more thinking to do, but Typed Scheme (and Haskell) made me realise not to imitate Scala, C# or Java's type declaration syntax.


Anonymous said...

I can't see why:

method[A] : (List[A], Int) => A
def method(list, num)

would be better than:

def method(list:List[A], num:Int):A

Apart from being more succinct, surely having the types line up with the parameters is clearer, particularly for longer parameter lists.

Ricky Clarkson said...

I consider long parameter lists to be a mistake.

I see your point though, and imagine that a decent editor for such a language would highlight the type and parameter name at the same time as you were moving your caret through either.

You missed an [A]: def method[A](list: List[A], num: Int): A

Lillplutten said...

In Scala you could of course declare your method like this:

def method[A]: List[A]=>Int=>A
= list => num => ...

Or like this:

def method[A]: (List[A], Int) => A
= (list, num) => ...

Doesn't that solve your problem?

Ricky Clarkson said...

A good point.

That defines a method that returns a function. The runtime characteristics are a bit different.

Also, I don't think it's as clear as Haskell and Typed Scheme, where the type signature is more out of the way.

Blog Archive

About Me

A salsa dancing, DJing programmer from Manchester, England.