torsdag, november 02, 2006

Introducing TIJuAVA - Java with Type Inference

Every time I've written Java code lately, I've been painfully aware of how much unnecessary code I write every time. And most of this is Java's fault. This blog post is a very small thought experiment. TIJuAVA does not exist as software. Yet. If I someday have the time I would love to implement it, but there are more pressing needs right now.

So, what are the rules? Basically, all valid Java programs are valid TIJuAVA programs. Some valid TIJuAVA programs are not valid Java programs. Simply put, the main difference is that you don't need to declare a type for any local variables or member variables. Type declarations are only necessary in method declarations. You can declare local variables and member variables if you want to, and in certain very unlikely circumstances you will need too.

Let's take a very simple example. This code is taken from the JRuby source code, but I have added one or two things to make it easier to showcase:
package org.jruby.util.collections;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class IdentitySet {
private items = new ArrayList();

public void add(Object item) {
items.add(item);
}

public void remove(Object item) {
iter = items.iterator();
while (iter.hasNext()) {
storedItem = iter.next();
if (item == storedItem) {
iter.remove();
}
}
}

public boolean contains(Object item) {
iter = items.iterator();
while (iter.hasNext()) {
storedItem = iter.next();
if (item == storedItem) {
return true;
}
}
return false;
}

private Collection getItems() {
return items;
}

private void something(java.util.AbstractSet inp) {
val1 = inp;
for(iter = val1.iterator();iter.hasNext();) {
System.err.println(iter.next());
}
}
}
This code doesn't really show all that can be done with this approach, and if I were to show a real example, this blog would be unbearably filled with code. So, this is just a tidbit.

The TIJuAVA system would need to be implemented as a Java two-pass compiler. Basically, the first pass finds all variable names that need to have a type inferred, and then walks through the information it's got, basic on method signatures and methods called on the variable. In almost all cases it will be possible to come to one conclusion on which type to use. The compiler would then generate regular Java byte code, basically the same bytecode that would have been generated had you written the types by hand.

Of course, most people use IDE's to write code nowadays. Wizards and code generators and what not. So why something like this? Well, even though your IDE writes your code for you, it is still there, and you still have to understand it at some level. If not when writing, you would still need to read it. And boy does type declarations clutter things. Especially generics. And here is one interesting tidbit. Generic types would also be possible to infer in most cases.

Another thing that could be easily added is some kind of in-place literal syntax for lists and maps. This would be more like a macro feature, but the list syntax would mostly just be a call to Array.asList, which isn't to bad.

An objection that I anticipate is from people who think that the code will be less readable by removing the type pointers. This should be more of a problem when you have large methods, but everyone these days use refactorings so they won't have methods with a LOC over 20. And if that's the case, the local variables should be easily understood by the operations that are used on them.

So. Someday, when I have time, this may be reality. If anyone is interested, that is.

7 kommentarer:

Mariano sa...

Ola,

yep, that would be pretty cool.

Unknown sa...

Hey Ola,

C# already has this feature, you would write it like this:

var iter = items.iterator()

which is nothing but a short-hand for

Iterator iter = items.iterator()

I think in general C# has a lot of neat features we can learn from.

Alexey Romanov sa...

If you want a language close to Java and compiling to Java bytecode, Scala has type inference (and a lot more!). If you are willing to settle for .NET, there are Boo, Nemerle and F# (C# doesn't have type inference yet, it will be in the next major version). Finally, there are (obviously) Haskell/Ocaml/SML.

vi sa...

What does Eclipse use for their Java parser?

They obviously have decent type inference built in -- leveraging that to create a two-pass build seems like it would be fairly strait forward.

I would definitely go with the C# approach of using "var" if I were implementing this.

Anonym sa...

Of course, you can have all this (and most other Ruby-like features) today with Groovy.

Anonym sa...

I've used BeanShell for stuff like this in the past.

ashishwave sa...

dbt is right
this is already FULLY available as beanshell.
it is a very small jar, and is rumoured even to be included in jdk in future.
all valid java syntax is valid here, and

you may/may not declare the types of variables.

there are lots of other goodies available too.

bye :-)
Ashish Ranjan