A translator is a collection of D assignment statements provided by
the supplier of an interface that can be used to translate an input expression into an object
of struct type. To understand the need for and use of translators, we will
consider as an example the ANSI C standard library routines defined in
stdio.h. These routines operate on a data structure named
FILE whose implementation artifacts are abstracted away from C
programmers. A standard technique for creating a data structure abstraction is to provide only
a forward declaration of a data structure in public header files, while keeping the
corresponding struct definition in a separate private header file.
If you are writing a C program and wish to know the file descriptor corresponding to a
FILE
struct, you can use the fileno() function to obtain the
descriptor rather than dereferencing a member of the FILE
struct directly. The Oracle Linux header files enforce this rule by
defining FILE as an opaque forward declaration tag so it cannot be
dereferenced directly by C programs that include <stdio.h>. Inside the
/lib/libc.so.6 library, you could imagine that fileno
is implemented in C something like this (of course, the real implementation is nothing like
this fictitious example):
int
fileno(FILE *fp)
{
struct file_impl *ip = (struct file_impl *)fp;
return (ip->fd);
} Our hypothetical fileno takes a FILE pointer as an
argument and casts it to a pointer to a corresponding internal libc
structure, struct file_impl, and then returns the value of the
fd member of the implementation structure.
Unfortunately, observability software such as DTrace needs to be able to peer inside the
implementation if it is to provide useful results. DTrace cannot call arbitrary C functions
defined in Oracle Linux libraries or in the kernel. You could declare a copy of
struct file_impl in your D program in order to instrument the routines
declared in stdio.h, but then your D program would rely on Private
implementation artifacts of the library that might break in a future micro or minor release,
or even in a patch. Ideally, we want to provide a construct for use in D programs that is
bound to the implementation of the library and is updated accordingly, but still provides an
additional layer of abstraction associated with greater stability.
A new translator is created using a declaration of the form:
translatoroutput-type<input-typeinput-identifier> {member-name=expression;member-name=expression; ... };
The output-type names a struct that will be
the result type for the translation. The input-type specifies the
type of the input expression, and is surrounded in angle brackets <> and
followed by an input-identifier that can be used in the translator
expressions as an alias for the input expression. The body of the translator is surrounded in
braces {} and terminated with a semicolon (;), and
consists of a list of member-names and identifiers corresponding to
translation expressions. Each member declaration must name a unique member of the
output-type and must be assigned an expression of a type
compatible with the member type, according to the rules for the D assignment
(=) operator.
For example, we could define a struct of stable information about
stdio files based on some of the available libc
interfaces:
struct file_info {
int file_fd; /* file descriptor from fileno() */
int file_eof; /* eof flag from feof() */
}; We could then define a hypothetical D translator from FILE to
file_info as follows:
translator struct file_info < FILE *F > {
file_fd = ((struct file_impl *)F)->fd;
file_eof = ((struct file_impl *)F)->eof;
}; In our hypothetical translator, the input expression is of type FILE *
and is assigned the input-identifier
F. The identifier F can then be used in the translator
member expressions as a variable of type FILE * that is only visible within
the body of the translator declaration. To determine the value of the output
file_fd member, the translator performs a cast and dereference similar to
the hypothetical implementation of fileno() shown above. A similar
translation is performed to obtain the value of the EOF indicator.