Re: Java Futures Panel at TSS Symposium
Posted: Mar 30, 2006 1:17 PM
> I'm tired of a "Rails future" and a "Java past". I'm all
> for scripting language/dynamic frameworks, but blindly
> spreading the gospel of one framework is really just
> propaganda and marketing instead of insight. Maybe he
> strives to be Rails' Paul Graham...
It is funny because I think Ruby on Rails marketing has made both Java and Python folks feel a bit like Java marketing in the mid-90s made C++ people feel--like their language was being misrepresented by the marketing hype of a wildly successful upstart. I do see Rails as being marketed, and marketed well, but I also have found the marketing message to be quite honest. Rails proponents have drummed one message repeatedly: Rails helps you build web apps fast. And it does. They also point out that Ruby is very fun to program in. And it is. That's the marketing, yes, but on those points I agree with the marketing message. They tend to not talk about scalability until asked, but then they do have an answer. I'm very nervous about the scalability with Rails, but for many applications, "Mom and Pop" as you call them, I expect Rails will scale well enough.
Nevertheless, that single message that Rails helps you build web apps fast has worked very well at marketing Rails. But there's also an anti-Java message in the marketing too. They talk about how much more verbose and less elegant Java is than Ruby, and these are valid observations. But the marketing aspect is that you don't hear mention much of the tradeoffs.
For example, in Java you have primitive and wrapper types. In Ruby, if I understand it correctly, you just have what would equate to wrapper types. Numbers are objects. (I'm not sure of this in Ruby, so please correct me if I'm wrong.) This bifurcation between primitive and wrapper types in java adds complexity. You might not think the primitive/wrapper difference such a big deal, but I once gave a Java class to a group who had previously programmed in languages like Visual Basic and COBOL, and they were being retrained to program with Java servlets. This class really got hung up on this primitive/wrapper type thing. They couldn't understand why you needed two kinds of integer. I think half the class still didn't really feel they understood it after 15 or 20 minutes of talking about it.
The reason Java has that bit of complexity is for performance. Here's what Gosling said about it in an old interview:
Bill Venners: Why are there primitive types in Java? Why wasn't everything just an object?
James Gosling: Totally an efficiency thing. There are all kinds of people who have built systems where ints and that are all objects. There are a variety of ways to do that, and all of them have some pretty serious problems. Some of them are just slow, because they allocate memory for everything. Some of them try to do objects where sometimes they are objects, sometimes they are not (which is what the standard LISP system did), and then things get really weird. It kind of works, but it's strange.
Just making it such that there are primitive and objects, and they're just different. You solve a whole lot of problems.
James Gosling: That's one of the reasons that primitives are not objects, because it is so nice to be able to just replicate them. When you pass an integer to a method, you don't have to pass the pointer to that integer. You can just replicate that integer and push it on the stack. So, it's a different integer. The same value, but a different integer and you can't actually tell. And if you look at a complex number class in C++ versus complex numbers in Fortran. In Fortran, they do all kinds of goofy things allocating complex numbers to registers, which really doesn't work in C++. And that mostly has to do with the fact that in C++, they are still objects and they have an identity. It's this whole platonic thing about identity. The nit that causes problems with optimizers and immutable objects is that as soon as you have a notion of identity that is independent of the value, then various things get really hard.
Ruby's design center is more aimed at the development experience than runtime efficiency. Here's what Matz, the creator of Ruby, had to say about it:
Bill Venners: In an article, you wrote, "Ruby's primary focus is productivity." How does Ruby help productivity, and what about efficiency and robustness? Productivity, efficiency, and robustness are all good things. How do you trade those off in Ruby?
Yukihiro Matsumoto: In my point of view, efficiency and productivity are the same thing, because we focus on programming efficiency, not runtime efficiency. I don't care about runtime efficiency. The computer goes faster and faster every year, so I don't really care about performance. Actually, I care about performance when I'm implementing the Ruby interpreter, but not when I'm designing Ruby. The implementer should care about performance, but the designer shouldn't. If you care about performance, you will focus on machines in design instead of on humans. So you shouldn't focus on performance in design.
Ruby feels easier to learn and use than Java. Java programs can go much faster at runtime than Ruby programs. These are not accidents. It's how the languages were designed.
Rails marketing hasn't talked much about these tradeoffs, and to me that's the hype part of the marketing. Matz himself had no problem talking about where he felt Ruby was a good fit. Here's something from farther down in the interview at the URL I gave previously:
Bill Venners: One of the arguments made by static typers in the static versus dynamic typing debate is that static compile-time type checking helps programmers make robust systems. What is Ruby's attitude about robustness?
Yukihiro Matsumoto: The Ruby language itself doesn't care about robustness. Actually, the implementation of the interpreter, which is written in C, should be robust. No Ruby code should crash the interpreter. So I try to make the interpreter robust, but the language itself in its design does not care about robustness for two reasons. First, you need to test the system anyway to be robust. So we encourage unit testing using a testing framework to help achieve robust systems. The second reason is that programs written in dynamic languages are very easy to run and check. So for day-to-day programs that aren't not as serious as enterprise systems, you don't have to be as robust. It's not worth the cost of declaring types, for example. And because there are so many dynamic checks in dynamic languages, in most cases something very terrible usually does not happen. For example, Ruby checks array boundaries, so you don't have buffer overwrites. Ruby doesn't provide direct address manipulations, so you can't crash the stack space. Therefore in Ruby, I want to enable programmers to get a program ready to test in a short time by making programmers productive.
> Java is nowhere near threatened. Any high-level language
> that features duck-typing cannot replace Java, it simply
> wont. It will generally be slower, and it wont scale to
> large projects.
> As someone who has done web development since '99 or so,
> I've moved *to* Java from scripting languages. There are
> so many reasons why, but the list is almost identical to
> the scripting language benefits.
> To everything simply add "is a major convenience for small
> and expirable projects but becomes a major hassle when the
> code base is large, or the team has changed over time"
> 1. dynamic typing
> 2. speed sacrifices for code convenience
> 3. conventions over configuration
> It's simply true, and experience has taught me that lesson
> many many times.
I'd like on Artima to try and help people understand what the real tradeoffs are, so they can make wise decisions about which tool to apply to which problems. As part of that effort, I'd like to explore what scalability problems dynamic languages actually have that people haven't been able to overcome. Because even if I have to buy twice as many servers, that still could be cheaper than paying for twice as many developers. Maybe, I don't know, because I've never used a dynamic language to do anything besides relatively simple scripts.
Could you share some of the real-world problems you encounted when trying to scale something written in a dynamic language, and why you couldn't overcome it with techiques like clustering?