previous article

next article


Freely Annotating C#

Walter Cazzola, DICo - Department of Informatics and Communication, Università degli Studi di Milano, Italy
Antonio Cisternino, Department of Computer Science, Università degli Studi di Pisa, Italy
Diego Colombo, IMT - Istituzione Mercati Tecnologie, Alti Studi Lucca, Italy

space ARTICLE

PDF Icon
PDF Version

Reflective programming is becoming popular due to the increasing set of dynamic services provided by execution environments like JVM and CLR. With custom attributes Microsoft introduced an extensible model of reflection for CLR: they can be used as additional decorations on element declarations. The same notion has been introduced in Java 1.5. The annotation model, both in Java and in C#, limits annotations to classes and class members. In this paper we describe [a]C#a, an extension of the C# programming language, that allows programmers to annotate statements and code blocks and retrieve these annotations at run-time. We show how this extension can be reduced to the existing model. A set of operations on annotated code blocks to retrieve annotations and manipulate bytecode is introduced. We also discuss how to use [a]C# to annotate programs giving hints on how to parallelize a sequential method and how it can be implemented by means of the abstractions provided by the run-time of the language. Finally, we show how our model for custom attributes has been realized.

Keywords: Reflection, Code Annotation,.NET,C#.


1 INTRODUCTION

Reflection and dynamic loading are becoming essential elements of modern programs. Their usefulness is testified, for example, by the JDBC architecture that shows how to implement a driver-based architecture exploiting the Java dynamic loading.

Although reflection can be used to inspect the structure of types, to access fields and even to invoke methods dynamically, the concept of tagging has been anticipated as an interesting application. Consider for instance the Java serialization architecture: the programmer can declare the instances of a class simply by implementing the Serializable interface, which in fact is an empty interface. Thus, two types that differ only for the implementation of the Serializable interface are indistinguishable from the execution standpoint. Besides, the serialization of the instances of non-serializable types will not be allowed by the serialization support. Java serialization taught us that the meta-data stored with the code can be used for other purposes than mere execution. Other programs may rely on the reflective abilities of inspecting the compiled types and act differently depending on what they have found.

Although widely used by Java programs, the idea of providing explicit meta-data support for annotation has been introduced first by Microsoft in the common language run-time (CLR). The virtual execution environment is part of the standard Common Language Infrastructure (CLI) [14] and a crucial element of the .NET initiative. The CLR executes code expressed in an intermediate language (IL) like the JVM bytecode, though the code is stored and distributed in the form of an assembly. A single assembly contains the definition of one or more types and may refer to other assemblies. Together with the meta-data, required by the CLR for loading and managing the types contained within an assembly, it is possible to store arbitrary information in the form of custom attributes. A custom attribute is an instance of a class that inherits from the Attribute class. A custom attribute is created by invoking one of its constructors, though all the values used to create it must be computable at compile time. Custom attributes are serialized into an assembly at compile-time and ignored by the execution system. Nevertheless, the reflection API provides a means to retrieve these attributes at run-time. For instance, let be an instance of MethodInfo (a reflective descriptor of a method). In C# we can retrieve the custom attributes associated with the method as follows:

 

In the CLR model attributes can be used to decorate essentially all the objects accessible through reflection: assemblies, types (delegates, value types, and classes), fields, properties, and methods.

Problem Description.

The crucial idea behind the custom annotations consists of shifting up data about the code into the executable and to render them available at run-time. Custom annotations are interpreted by programs and are used for program transformation.

Microsoft .NET provides support for implementing web services by means of custom attributes. A custom attribute named WebMethod is used to label methods that should be exposed as web services. A minimal web service written in C# that computes the sum of two integers is the following:

Once compiled, the HelloWorldWS class does not provide any web services interface. A different program - actually part of the Internet Information Server - is responsible for looking up reflection information within assemblies and generating a SOAP/WSDL interface to the method add() over HTTP.

A significant limit to the annotation model introduced by the CLI is the granularity of annotations: they can only be used on methods and not inside them to annotate code blocks. This limitation is partially bound to the provided reflective model that does not permit to reify blocks of statements. Several programs whose goal consists of administering and manipulating other programs would benefit from a finer grained model for annotations.

In this paper we present [a]C#, an extension to the C# programming language supporting custom annotations on arbitrary code blocks or statements. The language extends the syntax of the C# language to allow a more general form of annotation and provides a run-time library that extends the reflection support with operations for retrieving the information about annotations inside methods.

It might not be evident that this finer grained model for custom annotations of code can be of any use, thus we provide a detailed example of how custom annotations and [a]C# can be used to render parallel a sequential C# program. In particular, we discuss the general operations that can be used on annotated code blocks, which hide from the programmer the complexity of manipulating intermediate language instructions explicitly.

We also present the implementation of the compiler, which is realized as a source to source translator. In particular, it is interesting how the compiler reduces the extended model for custom annotations to the existing one with the help of small modications of the generated intermediate language.

2 [a]C# IN A NUTSHELL.

[a]C# extends the original language by allowing the use of custom attributes inside a method body.

In the example, we have defined two attributes, MyAnnotationAttribute and AnotherAnnotationAttribute, that we will use for annotating the method body. They inherit from ACS.CodeAttribute rather than from the System.Attribute class.


Inside the method Main() we use these two annotations and, as it is usual in C#, we omit the suffix within square brackets. Inside a method body custom attributes can be used before statements or code blocks delimited by braces.

The ability of putting custom annotations into methods is of little use without any means to retrieve the information the programmer has specified using the annotations. How can a tool retrieve annotations from an assembly? The run-time of the language (a library linked to the program resulting from the source to source transformation) provides the method GetCustomAttribute() to look at the method code for custom attributes:

Although we cannot extend the reflection library, this method should be considered as belonging to the MethodInfo class: given a method reification, it returns all the annotations associated with it (if present) by reflective inspection.

The retrieved annotations are stored into a forest. Each tree represents a group of nested annotations rooted at the outermost one, whereas each node represents and stores information about a single annotation. Nested annotated blocks are sub-trees of the node representing the outer annotation sorted as they appear.

Although, to be able to retrieve annotations related to a single method body is often enough, there are still situations where a broader view is necessary. For example, consider a tool whose aim consists of performing the static analysis of a program by means of pre and post conditions. In this case, the annotation tree of a single method can be of little use because the conditions about the program's state do not only depend on a method body but also on the methods it calls. The rec argument of GetCustomAttributes() serves this purpose: if true the returned annotation forest represents the closure of the annotations attached to the specified method body and, recursively, of the annotations attached to body of the methods it calls. In this case, the leaves at a given level epresent both nested annotations and annotations attached to the body of methods called in the scope of the annotations in the upper level.

The [a]C# run-time provides operations to manipulate the intermediate language instructions within the scope of annotations. These operations are:

  • Extrusion: is used to extrude the annotation by generating a new method whose body and arguments are respectively the annotated code and the free variables of the annotation;
  • Injection: is used to insert code immediately before and after an annotation;
  • Replacement: is used to replace the annotated code with the specified code.

All these operations can feed an ILGenerator that generates the body of a method. A tool can generate new methods, which are a translated version of the original ones, using these high level operations, without the need for explicitly manipulating IL instructions.

Code injection simply requires an stream that corresponds to a method m with a signature void m(). This operation is useful for tools like aspect weavers. The same can be done for replacement. A variant of injection and replacement allows the generated code to access the same variables used by the code block target of the operation.

3 CASE STUDY: TO PARALLELIZE A METHOD.

To render parallel a program provides a good example of application of our model for custom annotations of code blocks. Suppose we are interested in giving hints about how to parallelize the execution of a method. Of course, these hints can be ignored and the method is executed sequentially. On the other hand, specific tools could recognize these annotations and transform the method consequently.

We have chosen this case study because it offers a relevant application domain where the [a]C# annotations schema proves to be useful. In our case study we focus on the code manipulation aspects rather than on the techniques to render it parallel.

The Used Annotations.

With the standard model of custom attributes it is possible to specify information about a method, but there is no easy way to indicate which portions of its body can be run in parallel: in this case the information about the scope of the annotation is required. We introduce the following annotations:

These definitions must be known by the programmer who uses them to annotate the code, and by tools that understand them and behave depending on the annotations. Note that we provide a constructor that allows the user to specify some descriptive text to be included with the annotation. Note that we use the names Parallel and Process for the annotations, but this does not imply by any means that parallelism is achieved through system processes. In general it is the tool that defines the semantics of annotations by manipulating the annotated code.

Annotated Code.

A method annotated with these annotations may look like the following:

Listing 1: Hints for Parallelizing a Method

We notice that a sequential computation can be annotated by declaring portions of code that can be executed either sequentially or in parallel. If we execute the method m, as specified by the CLI virtual execution system, annotations are ignored and the code is executed sequentially. A tool capable of understanding the annotations Parallel and Process is required, as in the case of web services implementation based on the WebMethod attribute. This tool will be responsible for giving a semantics to the annotated methods.

Giving Semantics to Annotations.

In the domain of parallel execution we can even think of a JIT compiler aware of these annotations leading to better performing code. Nevertheless, an off-line approach can be also followed: a tool can read the method m in its binary form from the assembly where it lies; and it can generate a new assembly with a method whose body has been translated so that its execution will be rendered parallel according to the annotations. Our tool will give semantics to the annotations as follows:

  • Parallel: a block annotated with this attribute denotes a scope within the code, where the blocks annotated with are executed in parallel. When the execution control reaches the end of the block, all the processes spawned within should have finished their activity.
  • Process: the code within a Process block is executed by a separate execution thread. In our implementation the code is responsible for ensuring that the access to shared variables does not cause race conditions.

The transformation schema we have adopted for transforming an annotated method m in its parallel form relies on the asynchronous methods support provided by CLI through delegate objects. Given a delegate object (wrapping a method) it is possible to invoke the corresponding method by calling the method BeginInvoke(). A thread is taken from the ThreadPool to execute the method referred by the delegate and the result of the invocation is an object representing the running method. The main thread calls the method eginInvoke() for each Process block. At the end of the Parallel block a WaitAll() method call is performed to wait for all the asynchronous methods to complete, then the execution continues with the single thread.

Our tool relies on the operations provided by the [a]C# run-time for implementing this code transformation, as follows:

  • for each Parallel block (obtained from the GetCustomAttributes() method):
    • it extrudes a method for each Process block within its scope;
    • it generates a delegate type for the extruded methods;
    • an asynchronous call to a delegate wrapping the extruded method replaces the corresponding Process block;
  • finally, it injects a call to the method WaitAll() with the references to the handlers of each extruded method.

The algorithm shows how the operations defined in [a]C# run-time are useful for transforming the code.

Unbound Process Spawning.

At first sight it may be thought that the annotations we have introduced allow only expressing a fixed number of processes to be spawned by the translated code. This is not true: in our transformation schema, if we annotate the body of a loop the main thread will spawn an asynchronous method for each execution of the body. We consider the classic example of paralleling the rendering of Mandelbrot fractals (see [9]). Our goal is to draw the fractal by using four threads, one for each fourth of the drawing area.

Of course we could repeat four times the code needed to draw a single portion and annotate the four blocks as Process. Although this approach works it requires us to replicate a portion of code. Thus, to avoid code replication, we introduce a loop that repeats four times the code that draws a region of the fractal. The resulting code is the following:

The Mandelbrot method computes the fractal given a region in the complex plane (bound by the two complexes z1 and z2). The algorithm implemented subdivides the complex plane in four regions (whose upper left corners are contained in the rects array), and performs the classic Mandelbrot algorithm on each of these. We used the Process annotation on the block of the first statement. Accordingly toour transformation schema, the block will be replaced by the invocation of an asynchronous method. Note that the code can also be executed as it is; in this case the four regions will be drawn in sequence rather than in parallel.

The spawning of asynchronous methods in the example is known (though not reading the annotation); a variant of the algorithm may determine at run-time the number of regions that should be drawn in parallel.

Final Considerations.

The annotations we used to render parallel sequential methods introduce a form of parallelism with shared memory. The variables, defined outside the scope of the Process attribute, are shared among processes (which in fact are threads) though the tool does not provide any form of automatic synchronization. The variables defined inside the scope of the Process attribute are local to the process itself.

Without our extensions the standard model for annotations would not have been enough for expressing scopes inside method bodies. However, some may wonder if the employment of different techniques would have led us to the same result.

An alternative approach to compute the Mandelbrot set in parallel could consist of employing a tool performing source to source transformations. The disadvantage of this approach is that, unless the tool implements a full parser for the C# language, a shallow parsing approach would have been more error prone than ours that simply has to detect and retrieve the annotations. Moreover, annotations in the binary code allow different languages to benefit from the tools written to use them. Finally, the decision of transforming the program or of executing it sequentially can be postponed and the transformation can be adapted to the particular machine where the program will run.

4 COMPILER IMPLEMENTATION

The [a]C# compiler has been implemented as a source to source compiler, reducing our enriched model to the standard model for code annotation. We believe that our approach in the realization of the compiler is another contribution of this paper in two ways: first of all we show how the more expressive code annotation schema proposed by [a]C# can be reduced to the existing annotation model combined with a particular coding convention schema; the transformation engine constitutes a second contribution because of its general structure based on a full parser rather than on a shallow system.

Representing Code Annotations

As already discussed, the existing model for custom annotations cannot keep track of the attributes' scope within the body of a method. Nevertheless, the execution environment already provides all the machinery to support annotations.

We have considered extending the virtual machine by modifying Rotor [15]. Although feasible, the problem of this approach is that the code generated by our compiler would have been compatible only with the modified version of the runtime. Thus, we have decided to encode information about ranges of code annotations by inserting placeholders into the bytecode. As shown in [3, 4], we used a call to a dummy method to indicate the beginning and the end of an annotated block. Annotations are lifted onto methods and indices are used to preserve the binding between dummy method calls and the relative annotations.

Consider, for instance, the [a]C# code in Listing 1. The [a]C# compiler transforms it into the C# equivalent method:

We rely on a language feature provided by custom attributes in C#: the constructor of a custom attribute allows specifying named arguments after the standard arguments. Each named argument corresponds to the assignment to a class property. In the previous example the second Process attribute is instantiated calling the parameterless constructor, and then the ACSIndex property of the instance is set to the value 3.

Classes defining code annotations must inherit from ACS.CodeAttributes class. Through this class we are able to inject the ACSIndex property into all the code annotations, allowing the transformation system to preserve the association between the attribute lifted to the method and its scope. The definition of the base class for code annotations is:


The class CodeAttribute inherits from Attribute. This allows to use its instances as custom attributes in C#. The data about the scope of the annotation are stored within the compiled IL.

The language run-time support is responsible for retrieving the information stored within the executable file in the form of custom attributes plus the Begin/End method invocation pairs.

A finite state automaton reads the method body looking for method calls to the static methods Begin() and End() of the Annotation class. When the appropriate instruction is found the automata looks for the instruction used to load the integer arguments on the arguments stack and used to relate the method call to the scope defined by an attribute.

The invocation of the GetCustomAttributes() method causes the language runtime to analyze the method body and fill the reflection objects used to describe the annotation tree. The AnnotationTree class is used to retain not only the attribute object, but also the information needed to locate the begin and the end of the intermediate language instructions within the annotation's scope.

The indices used as arguments to Begin() and End() methods are used to associate the scope with the corresponding custom attribute. It is worth noting that the annotations generated by the [a]C# compiler can be consumed by all the languages targeting the CLI execution environment.

Annotations and Run-time Execution

Our translation schema introduces method calls into annotated programs. It is natural to ask whether these calls may introduce performance hits with respect to their non-annotated versions. One of the most important assumptions of code annotations is that the execution of an annotated program should run as fast as the same program without the annotations. Besides, we rely on fake method calls to preserve the scope of annotations. Therefore, it is natural to wonder if these IL instructions may introduce inefficiencies when the container method is executed.

It is worth noting that the called methods are static and empty. A JIT compiler can easily avoid generating the call instruction by simple inlining strategies. Nevertheless, they might generate a call instruction in the code generated by the JIT compiler. As a matter of fact all the non trivial JIT compilers perform inlining and are capable of removing the method call at JIT time. This is the behavior of the Microsoft .NET JIT, and of the Mono JIT. The Rotor JIT is very trivial and emits the call instruction.

Another issue we may think of is: does the compiler eliminate the method call to optimize the generated code? The answer is negative: the compiler links the method that is already compiled in a different assembly. Thus, it does not know the actual definition of the method demanding this optimization at later stages in the execution pipeline. Moreover, it cannot change the position of the method call inside the method body because it cannot establish whether the static method will perform side effects that may lead to a different semantics. Besides, the JIT compiler will have full knowledge of the code to be executed and will perform these optimizations if possible.

We conclude that it is reliable to insert method calls and look for them in the binary output to find the boundaries of custom annotations. Moreover, in any reasonable implementation of the CLI standard the annotations would not affect the performance of annotated programs at all. Other compilers may support the same mechanism by simply adopting the same conventions when generating code and linking the [a]C# run-time library.

CoCo/R and the C# Transformation System

The [a]C# compiler transforms an annotated program into a standard C# program using the transformation schema previously illustrated. A few transformations are necessary but they require information about the program structure: attributes must be extended with the ACSIndex value, though the existing arguments should be preserved. Moreover, attributes should be lifted on the method they are used. A shallow approach to program transformation is, in this case, risky and error prone. We decided to rely on a full parser of the C# 2.0 [1] syntax. Fortunately, the CoCo/R project [18] produced a parser generator for C# and a full annotated grammar for the language.

The C# annotated grammar has been modified in order to obtain a parser that parses an C# program and rewrites it. The buffer where the output is stored provides operations to insert marks within the code, and then to insert text in a marked site. Thus, we obtained a transformation system for C# that performs full syntax parsing to implement code transformation patterns.

The [a]C# compiler has been developed by changing this transformation system (that implements the identity transformation). As an example, we include two productions of the annotated grammar (semantic actions are delimited by "(." and ".)"):

The first production defines the body of a class; we mark the output buffer ob with a label called ACS each time we encounter a member of the class. This mark is used to insert the attributes found while parsing the method body.

The second production defines a statement of the language; it has been extended with a case for statements with attribute. In the associated action we see that we inject the attribute definition where the ACS mark lies in the output buffer.

We derived the transformation system by customizing a generic C#-to-C# rewriting system based on the CoCo/R parser. The transformations needed by the [a]C# compilation strategy cannot be achieved without full understanding of the source code: the compiler needs to have information about types in order to ensure that code annotations are of types derived from CodeAttribute and that the attribute lifting process preserves the semantics of the original program. The whole annotated grammar and the whole source code of the [a]C# compiler is available as part of the CodeBricks project1.

Programming Tools

A well-known problem with source to source tools is that the programmer manipulates a source file different from the one the compiler deals with. Fortunately, C# re-introduced (similar to the C/C++ preprocessor directive) the #line directive. Thus, we annotate the lines of the generated C# file with the reference to the line in the original source. This is important because in the process of parsing and rewriting the source code we loose the original formatting of the code.

As a consequence, the whole programming infrastructure, ranging from the compiler to the debugging tools, is capable of supporting the real source code rather than the one generated by the translator.

The command line version of the [a]C# compiler is just a front-end to the standard C# compiler: it preprocesses all the files with .acs extension and then passes all the file names of the generated files to the C# compiler. The front-end allows mixing .acs and .cs files.

We have also integrated the [a]C# compiler in Visual Studio.NET 2003. The Visual Studio programming environment includes the notion of a custom tool. A custom tool is a preprocessor that the programming environment runs before starting the compilation process. A custom tool is a COM component implementing a set of interfaces that the editor uses to manage the code generator. We developed the custom tool as a .NET library exposed as a COM component using the interoperability facilities of the execution environment. We have also added wizards to the programming environment so that the creation of attributes and [a]C# files is supported by the programming environment.

5 RELATED WORK.

Code annotation, in several different forms, is not a new idea and is largely used in several contexts. Some of the most interesting applications are related to code instrumentation, analysis and documentation. Mainly, they have been used to enhance the flexibility and the efficiency of the compiling step and to support new language features, see [10, 11, 12].

Code generation is another of the most diffuse application for code annotations. The XDoclet2 tool [17] for Java has been successfully used for performing code generation tasks. The tool relies on comments similar to those used by Javadoc to annotate programs, and then the ant3 building tool is used for controlling the code generation. This approach to code annotation is based on source code manipulation: XDoclet comments are used by Java modules to generate Java source code. On the other hand, [a]C# provides operations to retrieve annotations at run-time on executable files without any need for a whole compilation infrastructure to be available at run-time.

Program manipulation with bytecode transformation is a technique that has been employed in several applications [13, 16]. There are also attempts to raise the abstraction level of this bytecode manipulation. The Javassist [6] library attempts to provide the programmer with operations that do not require knowledge on the underlying bytecode. However, the Javassist approach still focuses on the manipulation of single instructions like method calls, field accesses and so on. We are trying to build meta-programming abstractions that have coarser grain though focus more on the behavioral aspect of the code. Operations such as extrusion, injection and replacement can be type checked and provide the programmer with operations that recall the Lego bricks: "take this block of code and put it here". As a matter of fact the CodeBricks library [2,4] performs similar tasks using entire methods as the unit for code manipulation.

Code annotation is becoming more and more relevant also in the novel aspectoriented technology. Alice [7, 8] is an aspect-oriented based approach that exploits annotations to provide additional meta-information about components they are associated with. The annotations identify components' constraints and requirements that the weaver has to consider. In [5], the annotations are used to mark the join points inside the bytecode with the high-level specification to simplify the join point selection. Both examples could benefit from an annotation model that supports block-level annotations (as the one provided by [a]C#).

6 CONCLUSIONS AND FUTURE WORK

In this paper we have presented [a]C#, an extension of the C# language that allows custom annotations inside method bodies. The run-time library of the language extends the .NET reflective information by providing operators to retrieve custom annotations and to manipulate the annotated code blocks in their binary form.

We have presented a case study in the domain of code parallelism. The aim of the exercise was to show how a well-known problem can be faced by writing an external tool that manipulates a program rather than extending a programming language. We have also shown how the operations provided by the language are used to transform a method into its parallel version.

The compiler has been implemented as a source to source transformation. Nevertheless, we avoided the shallow approach by adopting a full C# parser that rewrites the program after parsing. We have been able to transform the program during parsing and reduce the extended model for code annotations to the one already present in .NET. We have encoded the annotations' scope by inserting dummy method calls at the beginning and at the end of each block.

The compiler is still in its early stage, and the run-time of the language should still evolve. The operations for manipulating bytecode still expose some of the complexity of the underlying execution environment. Moreover, we are considering the possibility of integrating the CodeBricks library [4] into the language run-time. In this way we could expose annotated code blocks as code bricks that can then be mixed to work as basics for the operations provided by the library.

We believe that code annotations can be useful to develop software that meets the always increasing demand for flexibility and dynamic adaptation. We are exploring the possibility of using code annotations to describe the behavioral aspect of components. In particular, in the embedded device domain, devices may give the code to access them (as it is in Jini) annotated with a description of the operations performed by methods.

Footnotes

a The name[a]C# should be pronounced as annotated C sharp.

1 See at: http://www.robotics4.net/Software/ACS.aspx

2 See at: http://xdoclet.sourceforge.net/xdoclet/index.html

3 See at: http://ant.apache.org


REFERENCES

[1] Tom Archer and Andrew Whitechapel. Inside C#. Microsoft Press, second edition, 2002.

[2] Giuseppe Attardi and Antonio Cisternino. Multistage Programming Support in CLI. IEE Proceedings Software, 150(5):275-281, October 2003.

[3] Giuseppe Attardi, Antonio Cisternino, and Diego Colombo. CIL + Metadata> Executable Program. Journal of Object Technology. Special issue: .NET: The Programmer's Perspective: ECOOP Workshop 2003, Vol. 3 No. 2:19-26, 2004. http://www.jot.fm/issues/issue_2004_02/article2

[4] Giuseppe Attardi, Antonio Cisternino, and Andrew Kennedy. Code Bricks: Code Fragments as Building Blocks. In Proceedings of 2003 SIGPLAN Workshop on Partial Evaluation and Semantic-Based Program Manipulation (PEPM'03), pages 66-74, San Diego, CA, USA, 2003.

[5] Walter Cazzola, Sonia Pini, and Massimo Ancona. AOP for Software Evolution: A Design Oriented Approach. In Proceedings of the 10th Annual ACM Symposium on Applied Computing (SAC'05), pages 1356-1360, Santa Fe, New Mexico, USA, on 13th-17th of March 2005. ACM Press.

[6] Shigeru Chiba and Muga Nishizawa. An Easy-to-Use Toolkit for Efficient Java Bytecode Translators. In Frank Pfenning and Yannis Smaragdakis, editors, Proceedings of Generative Programming and Component Engineering (GPCE'03), LNCS 2830, pages 364-376, Erfurt, Germany, September 2003. Springer.

[7] Michael Eichberg. Component-Based Software Development with Aspect-Oriented Programming. Journal of Object Technology, Vol. 4 No. 3 :21-26, April 2005. http://www.jot.fm/issues/issue_2005_04/article3

[8] Michael Eichberg and Mira Mezini. Alice: Modularization of Middleware Using Aspect-Oriented Programming. In Thomas Gschwind and Cecilia Mascolo, editors, Proceedings of the 4th International Workshop on Software Engineering and Middleware (SEM04), LNCS 3437, pages 47-63, Linz, Austria, September 2004. Springer.

[9] Benoit Gennart and Roger D. Hersch. Computer-Aided Synthesis of Parallel Image Processing Applications. In Proceedings of the Conference on Parallel and Distributed Methods for Image Processing, pages 48-61, Denver, USA, 1999.

[10] Brian Grant, Markus Mock, Matthai Philipose, Craig Chambers, and Susan J. Eggers. Annotation-Directed Run-Time Specialization in C. In Proceedings of the 1997 ACM SIGPLAN Symposium on Partial Evaluation and Semantics-based Program Manipulation (PEPM'97), pages 163-178, Amsterdam, The Netherlands, June 1997. ACM Press.

[11] Andreas Hartmann, Wolfram Amme, Jeffery von Ronne, and Michael Franz. Code Annotation for Safe and Efficient Dynamic Object Resolution. Electronic Notes in Theoretical Computer Sciences, 82(2), 2003.

[12] Raimund Kirner and Peter Puschner. Classification of Code Annotations and Discussion of Compiler-Support for Worst-Case Execution Time Analysis. In Proceedings of the 5th Euromicro International Workshop on Worst-Case Execution Time Analysis (WCET'05), Palma, Spain, July 2005.

[13] Hidehiko Masuhara and Akinori Yonezawa. Run-time Bytecode Specialization: A Portable Approach to Generating Optimized Specialized Code. In Proceedings of Programs as Data Objects, Second Symposium, PADO'01, 2001.

[14] James Miller. Common Language Infrastructure Annotated Standard. Addison-Wesley, November 2003.

[15] David Stutz, Ted Neward, and Geoff Shilling. Shared Source CLI Essentials. O'Reilly, March 2003.

[16] Éric Tanter, Marc Ségura-Devillechaise, Jacques Noyé, and José Piquer. Altering Java Semantics via Bytecode Manipulation. In Don S. Batory, Charles Consel, and Walid Taha, editors, Proceedings of Generative Programming and Component Engineering (GPCE'02), LNCS 2487, pages 283-298, Pittsburgh, PA, USA, October 2002. Springer.

[17] Craig Walls and Norman Richards. XDoclet in Action. Manning Publications, December 2003.

[18] Albrecht Wöÿ, Markus Löberbauer, and Hanspeter Mössenböck. Compiler Generation Tools for C#. IEE Proceedings Software, 150(5):323-327, October 2003.

 

About the authors



  Walter Cazzola (Ph.D.) is currently an assistant professor at the Department of Informatics and Communication (DICo) of the Università degli Studi di Milano, Italy. His research interests include reflection, aspect-oriented programming, programming methodologies and languages. He has written and has served as reviewer of several technical papers about reflection and aspect-oriented programming. He can be reached at cazzola@dico.unimi.it


  Antonio Cisternino is research fellow at the Dipartimento di Informatica of Università di Pisa. His current research is on run-time code generation and multi-stage programming on execution environments like JVM and CLI. He can be reached at cisterni@di.unipi.it
space Diego Colombo is PhD student at IMT Lucca. He is interested in robotics, computer vision, 3D graphics and Game Design. He can be reached at colombo@imtlucca.it

Cite this article as follows: Walter Cazzola, Antonio Cisternino and Diego Colombo, "Freely Annotating C#", in Journal of Object Technology, vol. 4, no. 10, Special Issue: OOPS Track at SAC 2005, Santa Fe USA, December 2005, pages 31-48, http://www.jot.fm/issues/issues 2005 12/article2


Previous column

Next article