James Gosling once said to me, discussing the birth of Java, “Occasionallyyou get to hit the reset button. That’s one of the most marvelous thingsthat can happen.” Usually, you have to maintain compatibility with stuffthat’s decades old; rarely, you don’t, and it’s great when that happens. Butunfortunately, as you can see with Java, it only takes you a decade untilyou’re the problem.

Seibel: Since you say that, is Java off in the weeds a little bit? Is it gettingmore complex faster than it’s getting better?

Bloch: That’s a very difficult question. In particular, the Java 5 changesadded far more complexity than we ever intended. I had no understanding of justhow much complexity generics and, in particular, wildcards were going to add tothe language. I have to give credit where credit is due—Graham Hamilton didunderstand this at the time and I didn’t.

The funny thing is, he fought against it for years, trying to keep generics outof the language. But the notion of variance—the idea behind wildcards—came intofashion during the years when generics were successfully being kept out ofJava. If they had gone in earlier, without variance, we might have had asimpler, more tractable language today.

That said, there are real benefits to wildcards. There’s a fundamentalimpedance mismatch between subtyping and generics, and wildcards go along way towards rectifying the mismatch. But at a significant cost in termsof complexity. There are some people who believe that declaration-site, asopposed to use-site, variance is a better solution, but I’m not so sure.

The jury is basically still out on anything that hasn’t been tested by a hugequantity of programmers under real-world conditions. Often languages onlysucceed in some niche and people say, “Oh, they’re great and it’s such a pitythey didn’t become the successful language in the world.” But often thereare reasons they didn’t. Hopefully some language that does use declarationsitevariance, like Scala or C# 4.0, will answer this question once and for all.

Seibel: So what was the impetus for adding generics?

Bloch: As is always the case for ideas that prove less wonderful than theyseemed, it was believing our own press sheets. My mental model was, “Hey,collections are almost all homogeneous—a list of strings, a map from stringto integer, or whatever. Yet by default they are heterogeneous: they’re allcollections of objects and you have to cast on the way out and that’snonsense.” Wouldn’t it be much better if I could tell the system that this is amap from strings to integers and it would do the casting for me and itwould catch it at compile time when I tried to do something wrong? It couldcatch more errors—it would have higher-level-type information and thatsounds like a good thing.

I thought of generics in the same way I thought about many of the otherlanguage features we added in Java 5—we were simply getting the languageto do for us what we had to do manually before. In some cases I was deadon: the for-each loop is just great. All it does is hide the complexity of theiterators or the index variables from you. The code is shorter and theconceptual surface area is no larger. In a sense, it’s even smaller becausewe’ve created this false polymorphism between arrays and other collectionsso you can iterate over an ArrayList or an array and not know or carewhich you’re iterating over.

The main reason this thinking didn’t apply to generics is that they representa major addition to an already complex type system. Type systems aredelicate, and modifying them can have far-reaching and unpredictable effectsthroughout the language.

I think the lesson here is, when you are evolving a mature language you haveto be even more conscious than ever of the power-versus-complexitytrade-off. And the thing is, the complexity is at least quadratic in the numberof features in a language. When you add a feature to an old language you’reoften adding a hell of a lot of complexity. When a language is already at orapproaching programmers’ ability to understand it, you simply can’t add anymore complexity to it without breaking it.

And if you do add complexity to it, will the language simply disappear? No, itwon’t. I think C++ was pushed well beyond its complexity threshold and yetthere are a lot of people programming it. But what you do is you forcepeople to subset it. So almost every shop that I know of that uses C++ says,“Yes, we’re using C++ but we’re not doing multiple-implementationinheritance and we’re not using operator overloading.” There are just abunch of features that you’re not going to use because the complexity ofthe resulting code is too high. And I don’t think it’s good when you have tostart doing that. You lose this programmer portability where everyone canread everyone else’s code, which I think is such a good thing.

Seibel: Do you feel like Java would be better off today if you had just leftgenerics out?

Bloch: I don’t know. I still like generics. Generics find bugs in my codefor me. Generics let me take things that used to be in comments and put theminto the code where the compiler can enforce them. On the other hand, when Ilook at those crazy parameterized-type-related error messages, and when I lookat generic type declarations like the one I wrote for Enum—class Enum>—I think it’s clear that the generics design wasn’t quitemature enough to go in.

We’re all optimists in our profession or we’d be forced to shoot ourselves.So we say, “Oh, yeah, of course we can do this. We’ve known aboutgenerics since CLU. This is 25-year-old technology.” These days you hearthe same argument applied to closures except it’s 50-year-old technology.“Oh, it’s easy; it doesn’t add any complexity to the language at all.”

Hell yes, it does. But I think many of us have learned from our experiencewith generics. You shouldn’t add something to a language until you reallyunderstand what it’s going to do the conceptual surface area—until you canmake a convincing argument that working programmers will be able to usethe new feature effectively, and that it will make their lives better.

If you look at how the man on the street has been reacting to generics, wecertainly should have done something other than what we did. Does thatmean we shouldn’t have done generics at all? No, I don’t think so. I thinkthat generics are actually good. The fundamental argument that mostcollections are homogeneous, not heterogeneous, so it should be easy todeal with homogeneous collections is true. Furthermore casting is generallya bad thing. Casts can fail and casts don’t make your program beautiful. So Ithink you should be able to say what kind of collection it is and then itshould just automatically be enforced for you. But does that mean you haveto suffer with all this complexity that we have today? No. I think we justdidn’t take the right cut at it.

Seibel: Was there real user pressure for generics? Were peoplecomplaining that the lack of generics was stopping them from writingsoftware?

Bloch: Were real engineers bitching about the lack of generics? I think theunfortunate answer to that question is, no, they weren’t. I think I was guiltyof putting in something because it was neat. And because it felt like the rightthing to do.

That said, a lot of engineering is from the gut. Had people been telling me toput in foreach? No. They hadn’t been telling me to do that either. But I justknew that it was the right thing to do. And I was right—everybody likes it.

But I think a big sin in our area, in engineering, is doing stuff just because it’sneat, because it’s good engineering, whatever. If you’re not solving realproblems for real users—in this case, Java programmers—then youshouldn’t add the feature.


Перейти на страницу:
Изменить размер шрифта: