Site Menu Project Specification Implementation Recommendations Reference Needs Updating Work in Progress Wastebasket Wiki Manual |
Template Based GenericsThe following describes a method to support template based generics outside of the language definition. The basic principle is to let the build system take care of template expansion and hide this process from the compiler altogether. In order to do this, two external utilities are required:
A suitable template engine utility (about 350 lines of code) is available at Benjamin's private repository: This template engine takes any input text which contains placeholders tagged with leading and trailing "@@" tags and recursively replaces those placeholders with their translations, copying them into the output text. For example, the template ... "Dear using the translations title="Mr." and name="Sutcliffe" is expanded into ... "Dear Mr. Sutcliffe," This can be used to expand placeholders in source code templates to generate compilable source. In order for a make utility or make script to know when to expand templates into compilable source and what translations for the placeholders need to be passed to the template engine, there would either have to be a configuration file or the information would have to be embedded in the definition part source files that import the expanded source files. A configuration file would have to be created by the user of a library separately from the actual source files for which the expanded source is produced. This would then require three different files to be maintained per module: a configuration file for the make utility, the definition part and the implementation part. This is not as user friendly as it could and should be. Embedding the information that the make utility needs directly into the source code can be easily accommodated by an additional pragma, for instance
The compiler would ignore the body of this pragma. Its content is only to be understood by the make utility. The delimiters for the actual information could be chosen differently if for some reason parentheses seem unsuitable. The above is entirely sufficient to implement template based generics that are fully integrated into the build process, that is to say, not requiring the human user to expand templates manually. At the same time, a human user could choose to expand templates manually if he or she wished to do so. An ExampleThe following is a concrete example of a generic stack template and its use in a Modula-2 program: Client Program Using a Template Derived Module<*MAKE="expand(template:stack, license:"@@BSD@@", module:"CardinalStack", type:"CARDINAL")" *> MODULE UseCardinalStack; IMPORT CardinalStack; (* generated by make utility from template *) VAR stack : CardinalStack.Stack; num : CARDINAL; ... CardinalStack.push(stack, num, NIL); ... num = CardinalStack.pop(stack, NIL); ... END UseCardinalStack. Driving the Build ProcessThere are two principle ways in which a project could then be built. Either the compiler is used as the driver program for the build or the make utility is used as the driver program for the build. If the compiler is the driver, it would recognise the If the make utility is the driver, it would first scan the source code for any occurrences of the The TemplateAn example of a template to generate the CardinalStack definition part is given below: NB: The CTE template engine recognises %% Template to generate definition modules for stacks in Modula-2 %% %% requires translations for the following placeholders: %% %% - module : the identifier of the generated module %% - type : the identifier of the base type for values to be stored in the stack %% (* Stack module for @@type@@ derived from template stack Copyright (c) 2010 Jon Doe (template author). License: @@license@@ *) DEFINITION MODULE @@module@@; TYPE Stack = OPAQUE; PROCEDURE new(VAR status : Status) : Stack; PROCEDURE push(stack : Stack; value : @@type@@; VAR status : Status); ... END @@module@@; %% %% End of template stack Expanding the TemplateBy invoking the template engine utility with a path to the stack template and placeholder translations for 'module' and 'type' the template is expanded and generates the definition part for module CardinalStack. When the compiler is invoked on the generated source, the source will be type checked by the compiler in the same way as usual. The compiler does not have, nor does it need to have any knowledge about the fact that the module was generated from a template. The debugger does not need to know either, nor does the human reader of the resulting output when examining the program. The tags ConclusionThe template expansion can be done right now with the CTE library as it is, no modifications required. The autotools and Cmake build systems could be relatively easily scripted/configured to control the build process in the way described above, again without making modifications to the source code of their respective make utilities. The only addition required to accommodate the above is the The language itself does not need any modifications. No complexity is added to any of compiler, linker, debugger. In the context of education, it would seem that making the template expansion process explicit and transparent should be a benefit to understanding the code and its translation process. The issue becomes another case of "eliminating magic". |