Oracle Blog

On the design and specification of Java

Complexity in language design

People talk about the "conceptual weight" of language features. Here's a way to make that a more precise concept, and more accurate too.

The JLS is structured bottom-up: universal elements like grammar, types, values and names; then Java artefacts both major (packages, class, interfaces) and minor (arrays, exceptions), then back to universal concepts like statements and expressions. (The chapters on execution and binary compatibility are in the wrong place; they should be at the end with assignment analysis and the memory model.)

We can exploit this structure when adding a new language feature. By asking which JLS chapters would be affected by the feature, we can gain an idea of the feature's semantic impact, and thus its complexity. For example, adding a new statement form is done near the end, so it's a minor addition. Adding a new keyword is done up front, implying there are many artefacts the new syntax could interact with - such as the names of all your variables.

So if a new language feature L needs changes in a set of chapters S, the complexity of L is:

where degree(S) is the number of cross-references between chapters necessary to fully describe L. An approximation of this factor is P(S,2) - note a permutation not a choice because a forward reference and a backward reference each add complexity.

S should never include 1, the introduction, or 18, which is really an appendix. (And a syntactic grammar is already introduced in chapters 3-15.) You'd have to watch out for a couple of things: some chapters (notably 6) trivially recap or preview other chapters, and example code should not generate vacuous cross-references.

Since b is probably higher than a, 1.75b will be higher than 2.33a, reflecting the sense that the complexity of generics is higher than the complexity of enums. However, to really capture how much higher, you'd want to improve the granularity of S's elements from chapters to sections or subsections, so that |S| shoots up for generics. Also you'd want to force the measure's range into a reasonable value set by means of constant factors. (Different factors would be needed for different granularities of S.) Finally, since I'm claiming that a total order exists for the chapters, the breadth of the changes - i.e. max(S)-min(S) - could be used in the formula.

I don't use this measure in real life but it is fairly plausible. Comparing an abstract view of a single feature against the abstract view of the whole language might serve as a proxy for the effort needed to implement and test the feature in a compiler.