onsdag, januari 16, 2008

Viability of Java and the stable layer

This post is basically a follow up to Language explorations. That post had several statements about what I believe, and some of them have been a bit misunderstood, so I'll try to substantiate them a bit more here. Specifically, I want to talk about the viability of the Java language and whether "the stable layer" should be a static or dynamic language.

Lets begin with the stable layer. First, notice that I didn't have any specific definitions for the different layers when I wrote the post. In fact, I think that they are inherently a bit fuzzy. That's OK. DSL's are also quite fuzzy. The attributes I put at the stable layer is first of all that it shouldn't need to change much. In a smaller application, you can actually look at supporting structures as the stable layer, things like application servers or web servers. But for larger applications I find that you usually need your own stable kernel.

The reasons I choose static typing for stable layer is for several reasons. Performance is absolutely one of these, since everything will run on this base it's an advantage if that part is as performant as possible. Secondly, I am no dynamic language, TDD purist that says that static typing is totally unnecessary. Static type checking can be very helpful, but it stops you from having a malleable language. So the kernel should be stable, this means that as much checking as possible is necessary. None of these requirements explicitly preclude a dynamic language, but the specific features of dynamic languages doesn't really come to their rights at this level, and also leading to performance and static type checking suffering.

The more contentious part about my post seems to have been my off hand comment that I don't believe Java is really good for anything. I didn't give much reason in that post, and people have reacted in different ways, from saying that "Java is really good" to "Why are you involved in JRuby if you think Java is so bad?". So lets start with why Java is a bad language. (I am only talking about the language here, not the platform). Also, that Java is a bad doesn't say anything about the worse alternatives, so no comments along the lines of "if you think Java is so bad, why don't you use X instead".

In short:
  • Java is extremely verbose. This is really a few different problems in one:
    • No type inference
    • Verbose generic type signatures
    • Anonymous class implementations
  • There is no way to create new kinds of abstractions:
    • No closures
    • Anonymous classes are a really clunky way to handle "block" functionality
  • Broken generics implementation
  • Language is becoming bloated
A few notes. That Java is becoming bloated is one of those things that people have been blogging about lately. After 1.5 came out, the complexity of the language got very much larger, without actually adding much punch for it. The improvements of generics were mostly negated by the verbosity of them. Fixing all the problems above will bloat the language even more. And at the same time, programming in Java is needlessly painful right now.

So, lets look at the question about why I'm working on JRuby. Well, first, I believe the JVM is a very good place to be at. It's the best platform out there, in my opinion. The libraries are great, the runtime is awesome, and it's available basically everywhere. The bytecodes of the JVM spec is good enough for most purposes. There is some tweaking that can be done (which we are looking at in JSR292), but mostly it's a very nice place. And working on JRuby is really one of the ways I've seen how bad Java as a language is. We are employing several different tricks to get away from the worst parts of it, though. Code generation is used in several places. We are generating byte codes at runtime. We are using annotations to centralize handling of JRuby methods. And we are moving parts of the implementation to Ruby. I believe that JRuby is important because it can run in the same environment as Java, but without the problems of Java.

What are the solutions to the problem with Java? There are basically two different ways. Either define a subset of Java, not necessarily totally compatible, that takes the best parts of Java syntax, does away with the problems and so on. That should be possible, but I don't know anyone who has done it. Or, you can go with an existing static language on the JVM. Here you have two choices - either one of the ports of existing extremely static languages (like ML or Haskell), or you can go with something like Scala. I haven't decided on the best solution here yet. The only thing I'm sure of is that Java in itself is a problem. I'm investigating Scala, but maybe Scala isn't the right answer either. We'll see.

18 kommentarer:

Anonym sa...

Well, you could always us C# - most of those things that you don't like about Java the language are fixed already :)

-John
http://www.iunknown.com

apohllo sa...

@anonym: Assuming you are working on Windowz... since Mono is still not the full implementation of .NET and I guess it'll never be. On the other hand - JRE when is published, is available for all platforms at once (approx.).

Martin Probst sa...

If you think Java is bloated then I'm looking forward to see your reaction to Scala. The number of concepts in Scala is - well - surprising.

I used to think that Java was beyond hope, but after looking into Scala it seems to me that some careful additions like weak type inferencing and closures would really fix that language.

Scala itself is IMHO much too complex. Languages should be simple, as in solving complex problems elegantly using a simple and small set of concepts (e.g. Lisp, Smalltalk, ...).

Clinton Begin sa...

It's unfortunate that the following page hasn't been kept up over the years, but it is interesting to see what others have done in the way of preprocessors and alternative languages on the JVM:

http://www.robert-tolksdorf.de/vmlanguages.html

Anonym sa...

Java *does* have closures. Do you really know what the term means?

How about F#? That has lots of functional programming goodies, runs on a well-supported (for now) platform, is now an official Microsoft product, and is a dialect of OCaml, which is open source, so code can live longer than Microsoft's product plans.

eao197 sa...

Do you see Nice language? It is a really good language for JVM, much more simpler than Java and Scala. It is not actively developed now, but looks like stable enough.

Ola Bini sa...

Anonym2: Eh. Yes. I know what closures are. Do you? Java does not have closures. The only thing that exists is a limited copying of values into anonymous inner classes, but that is not a closure.

jChris sa...

it seems that the upcoming Ecma script may be a good fit for all of your layers (except DSL.) I'm specifically thinking of its ability to refactor to strict types. Why cross a language barrier between layers when you can just add type information and achieve speed and stability? Plus it also runs on the JVM (and everywhere else...)

Pierre-Henri Trivier sa...

"Either define a subset of Java, not necessarily totally compatible, that takes the best parts of Java syntax, does away with the problems and so on. That should be possible, but I don't know anyone who has done it."

I suspect Groovy people might have been trying to do exactly this ... but I'll let them the pleasure to start yet-another-language-flame-war.

Daniel Spiewak sa...

For the record, Java actually *does* have a very limited type inference mechanism, but it ties right in with the "verbose generics declarations".

Ola Bini sa...

Pierre-Henri Trivier: what Groovy is doing is extremely different from what I'm aiming at in that sentence. First of all, Groovy is - mostly - a dynamic language.

Danial: I have _no_ idea whatsoever what you're talking about. Care to elaborate?

Daniel Spiewak sa...

You can trick Java into type inference through something like this:

public <K, V> V get(Map<K, V> map, K key) {
return map.get(key);
}

...or maybe something like this:

public class Entity<T> {
public T getKey() { ... }
}

public <E extends Entity<T>, T> Entity<T> get(Class<E> type, T key) {
// ...
}

It's not particularly obvious in either of these two examples, but the compiler is capable of doing some fairly clever inference for the types here. The Entity example is probably better because it shows some more depth, but almost any time you work with generic methods you're dealing with some form of type inference. In the entity example, this would be the type of the second parameter being inferred based on the class literal type passed in the first parameter.

(I don't know if blogger is going to eat my code or not, hopefully it all shows up)

patrickdlogan sa...

As a couple of data points on suitable languages for a "stable layer" -- I am trying to understand what this means -- consider the implementations of Squeak Smalltalk and Gambit Scheme. Both of these languages are implemented in subsets of themselves. Both of those subsets compile to C primarily to avoid implementing special translators for each instruction set architecture they run on.

Those subsets (of Smalltalk and Scheme) are essentially as efficient as C. But they are each "dynamic languages". And the stability of each can be measured now in decades, regarding how long they've been around, used in "real" systems.

Ola Bini sa...

Daniel: That is really not type inference at all. Generics sets a bound on the other argument types, true, but you still need to declare the type. In this case you declare it to be a bound type. That's not inference of any kind.

Daniel Spiewak sa...

Any type inference is bounding at a more or less basic level. In both my examples, the return types (and even the parameter types) are inferred based on values passed. Yes, the types are bound, but they are bound to weak inferences.

Anonym sa...

Ola, we are waiting for your verdict on Scala.

It can be a static layer
It is also suitable for dynamic layer - check out lift
And for DSL too: http://sant.googlecode.com/svn/sant/trunk/build.scala

One language for all layers - no need in Java+JRuby/Groovy... Just Scala.

I hope that your work on Rails-company & involvement in Ruby-community won't affect on your decision)

Hervé sa...

Judging by my experience, I would not say that Java (as a language) is so bad or broken. For once, I used C or C++ before (sometimes with MFC when I needed GUIs) for simple applications and it was hell, as you can imagine. Of course you can always use better graphic libraries for C++ but you end-up having to learn and linl to other big libraries,... I used perl too for small quick and dirty quick applications, and it quickly became a nightmare to maintain when there were more than a few lines of code...

Now I'm using Java even for things I would have done with perl before, for example, because it is much simpler and maintainable. Of course, what is good with efforts like JRuby is that you have a good scripting language with a good performance while having access to the Java platform (for example GUI).
And I don't agree with anonym when he is saying that C# fixes what is broken in Java. C# is tied to MS Windows platform (even if they are really doing well, Mono will never be able to catch up the never-ending addition of functionalities in MS .NET), and there's too much shiny thing added in the language (LINQ, etc...) which end-up in my point of view as bloated in an ordre of magnitude to what you can think of Java ;-)

Anonym sa...

Hervé: You're wrong about bloatedness of C#, since LINQ (your only example) uses a subset of itself for its implementation and nothing has changed since the CLR 2.0 in terms of what it compiles into.