Structural abstraction a mechanism for modular program construction

Much of programming languages research has been directed at developing abstraction mechanisms to support the “separation of concerns”: Orthogonal pieces of functionality should be developed separately; complex software can then be constructed through the composition of these pieces. The effectiveness of such mechanisms is derived from their support for modularity and reusability: The behavior of a piece of code should be reasoned about modularly—independently of the specific compositions it may participate in; the computation of a piece of code should allow specialization, so that it is reusable for different compositions. This dissertation introduces structural abstraction: a new abstraction mechanism that advances the state of the art in modularity and reusability by allowing the writing of highly reusable code—code whose structure can be specialized per composition, while maintaining a high level of support for modularity. Structural abstraction addresses the reliance of mainstream abstraction mechanisms on fixed structures. Although abstraction mechanisms have been developed to allow code to be reused over ranges of values (e.g., procedural abstraction) and ranges of types (e.g., type genericity), their modularity guarantees crucially rely on separately developed pieces of code having fixed structures: A procedure is a structure with a fixed name and a fixed number of argument types, a type-generic procedure is a similar structure with a fixed number of type variables. This rigid notion of abstraction means a piece of code cannot be reused for clients with different structures, and thus often leads to the same piece of functionality having to be manually specialized for the (possibly infinite number of) different structures it may be composed with. Structural abstraction addresses this limitation by providing a disciplined way for code to inspect the structure of its clients in composition, and declare its own structure accordingly. The hallmark feature of structural abstraction is that, despite its emphasis on generality and greater reusability, it still allows modular type checking: A piece of structurally abstract code can be type-checked independently of its uses in compositions. Thus, errors in generic code are detected before composition time—an invaluable feature for highly reusable components that will be statically composed by other programmers. This dissertation introduces two specific techniques supporting structural abstraction: static type conditions, and morphing. Static type conditions allow code to be conditionally declared based on subtyping constraints. A client of such a piece of code can configure a desirable set of features by composing the code with types whose positions in a subtyping structure satisfy the appropriate typing conditions. Morphing allows code to be iteratively declared, by statically reflecting over the structural members of code that it would be composed with. A morphing piece of code can mimic the structure of its clients in composition, or change its shape according to its clients in a pattern-based manner. Thus, using either static type conditions or morphing, the structure of a piece of code is not statically determined, but can be automatically specialized to reflect the structure of its clients in composition. We show how these structural abstraction techniques can be smoothly integrated with a modern Object-Oriented language, by implementing the languages cJ (for static type conditions) and MorphJ (for morphing), both of which are extensions of Java. We demonstrate the practical impact of structural abstraction by reimplementing a number of real world applications using cJ or MorphJ. We show that the reimplementations are more reusable, and, at the same time, modularly type-safe.