Real problems in software evolution render impossible a fixed, one-size-fits-all approach, and these problems are usually solved by gluing together various tools and languages. Such ad-hoc integration is cumbersome and costly. With the Rascal meta-programming language the Software Analysis and Transformation research group at CWI explores whether it is feasible to develop an approach that offers all necessary meta-programming and visualization techniques in a completely integrated language environment. We have applied Rascal with success in constructing domain specific languages and experimental refactoring and visualization tools.
The goal of our research is to rapidly construct many different (experimental) meta-programs that perform software analysis, transformation, generation or visualization. The underlying motivations are (a) to do experimental research in software evolution and construction and (b) to transfer our results to industry in the shape of tools. We need innovative tools that contribute to understanding and improving very complex software systems.
The challenge is diversity: the mixture of programming languages and data formats one encounters is overwhelming when solving problems in software evolution. The range of questions to answer is even larger; they range from general (eg computing a call graph or a widely used metric) to application specific (eg checking in-house coding standards or migrating to a different API). As a result, software evolution problems are often solved with different tools that are glued together. The gluing itself introduces yet another kind of complexity.
Rascal is a domain-specific language that tackles this challenge by integrating all aspects of meta-programming. It is a language for performing any or all meta-programming tasks such as the analysis, transformation and visualization of existing source code and models and the implementation of domain-specific languages. Rascal is completely written in Java, integrates with Eclipse and gives access to programmable IDE (Interactive Development Environment) features using IMP (the Eclipse IDE Meta-Tooling Platform). We are aiming to provide a complete “One-Stop-Shop” for analysis, transformation, generation and visualization of software systems.
Rascal has many applications in the software evolution domain, for example, when studying the effects of choosing between design patterns. Design patterns provide reusable, named solutions for problems that arise when designing object-oriented systems. While in some cases it is clear which pattern should be used, in others multiple patterns could apply. When this happens, the designer has to carefully weigh the pros and cons of each option as applied both to the current design and to plans for future evolution of the system.
The specific design choice we focused on was between structuring AST-based (Abstract Syntax Tree based) language interpreters according to either the Visitor or the Interpreter design pattern. While it seems clear that either pattern will suffice from a functional point of view, it is unclear what the non-functional quality of the interpreter will be in each case. In theory, the Interpreter pattern might have lower method call overhead because it does not involve double dispatch, it should allow easier extension with new language features, and it should be easier to add local state to AST nodes. In theory, the Visitor pattern should allow easier extension with new kinds of operations on AST nodes and should allow better encapsulation of state required by such operations. The question remains how this choice affects the design in practice, given the plethora of other factors of software maintainability and efficiency.
Our research method is as follows. Given is an implementation of an interpreter (in this case study the Rascal interpreter itself) that uses Visitor in several places. Using Rascal, we construct an automated source-to-source transformation that transforms the Java code of each instance of Visitor to an instance of the Interpreter design pattern. This then allows us to conduct a comparison between two implementations varying only in the choice of design pattern. The choice has been isolated among all the other factors in software design. We can now compare ease of maintenance and runtime performance between the two semantically equivalent systems.
This method enabled us to identify the differences between using the Visitor and Interpreter patterns in the interpreter. We applied real maintenance scenarios to both versions and did initial performance measurements. There was no observable difference in efficiency, but we did reach some counter-intuitive conclusions regarding maintainability: Visitor wins in the long run, even where Interpreter should be better. While these results cannot be directly generalized, we expect that other designers of tree-centric object-oriented software — such as compilers, interpreters, and XML processors — will benefit.
Rascal was used to rapidly (two person-weeks) create this complex ad-hoc Java source-to-source transformation. The task required substantial analysis of Java syntax and semantics, integration with the Eclipse Java front-end, and the necessary source code transformation and generation.
In other projects Rascal has been or is being applied to software metrics, static analysis (Java, PHP, Rascal), transformation (refactoring), code generation (Java, HTML), and domain specific language design (forensics, auditing, courseware). The design and implementation of Rascal are in an advanced stage but are not yet frozen. Based on these examples, we believe its integrated design is on the right track. The pieces of the puzzle are coming together.
Jurgen Vinju, CWI , The Netherlands
Tel: +31 20 592 4102