Home | About | Partners | Contact Us

SourceForge Logo

Quick Links
Home
News
Status
Building XL
XL Mailing List

Understanding XL
Conceptual overview
XL examples
Inside XL
Concept Programming

In depth
Browse GIT
Bugs
SourceForge Info
Contact

Other projects
GNU Project
The Mozart Project

XLR: Extensible Language and Runtime

The art of turning ideas into code

Compile-time variadics

Prev: XL operators

Up

Next: Generic declarations

A frequent need in the representation of a particular concept is the notion that a same operation applies to a set of entities, the size of set not necessarily being known ahead of time. A very common case is text I/O, where writing multiple elements is as common, if not more, than writing a single one. Another example is the computation of a maximum, minimum or average of a set of values. A mathematician would denote that as max(x,y,z) for instance.

Historically, there have been a number of ways to address this particular problem. They all introduce significant semantic noise, which manifests in the form of run-time inefficiency or other undesired properties:

  • Built-in constructs, as in the BASIC PRINT statement, or Pascal's writeln procedure are special cases, and the programmers cannot define similar constructs for their own use.

  • C-style variable arguments lists (defined in <stdarg.h>) are not type-safe, since the program accesses a raw memory image of the arguments.

  • Concatenating strings of characters before emitting a single string, is an approach taken by Java or Ada. This works only for text I/O, but is not applicable for instance to computing a maximum. It is also inefficient, since it involves the construction of many larger and larger intermediate strings.

  • Doing a concept cast from a variable set of arguments to a container with all the arguments allows one to reduce the problem to a single (large) argument. The cast can be done implicitly as in C# or Lisp or explicitly (as is done in many Java interfaces). The concept cast makes the intent less clear, and making the management of container transparent to the programmer requires complicated and sometimes expensive memory management mechanisms (which have their own side effects).

  • Invoking a short-hand notation multiple times, for instance the << operator in C++. This notation splits a single conceptual operation into little chunks, which causes code bloat and prevents a library to perform global operations on all arguments (so computing an average that way would not be practical).

  • Currying is an approach that can be used when the operation can be applied one element at a time. If the function returns itself, it can be repeated on many arguments. The << operator in C++ can be seen as a form of currying. The operator returns the stream given as its left operand, so one can see out<< and out<<x<< as being the same function. Using currying when the whole set of arguments needs to be considered (as needed to compute an average) is more complicated.

XL takes a different approach for variadics. A variable parameter list can be declared using other at the end of a parameter list. The other parameter stands for all other arguments. In the body of the variadic entity, other can be used as an argument, and it is replaced with the actual list of arguments. Properly used (typically, by "shaving off" one argument at a time using a regular parameter), this mechanism allows a recursive instantiation of all the required entities.

// Example of variable argument max for integers // See a more general implementation here function max(X : integer) return integer is return X function max(X : integer; other) return integer is result := max(other) if result < X then result := X

The expansion is performed entirely at compile-time, so there is no run-time cost associated with list management. At every step in the recursion, the type system is used to make sure that the argument types are corrects, and the technique is compatible with overloading. The same technique can be used for text I/O as well as for maximum or average functions, and it doesn't require the creation of any intermediate object (containers, boxing or unboxing). For these reasons, the XL approach to variadics creates less semantic noise that alternatives.

Note: At this point, variadics only work in the C++ version of the XL compiler.

Prev: XL operators

Up

Next: Generic declarations


Copyright 2008 Christophe de Dinechin (Blog)
E-mail: XL Mailing List (polluted by spam, unfortunately)