Why D _still_ needs the C preprocessor
David Medlock
noone at nowhere.com
Wed May 9 17:56:58 PDT 2007
nobody at nowhere.nonet wrote:
> I am currently working on a program to manipulate OMF import libraries.
>
> It turns out that OMF files consist of a series of records, and as
> a result, a class that handles OMF files sort of resembles a database.
>
> I decided to use one of D's best features, delegates, to add a member
> whose function is analogous to SQL's "SELECT" statement. Impossible
> implement in C and C++, it is declared as follows:
>
> OMF_Record[] select_records(bool delegate(OMF_Record rec) where_clause) ;
>
> I thought I could call this method as follows:
>
> OMF_Record[] results = library.select_records({ return (rec.type == LIB_HEADER); });
>
> It looks something like an SQL query, and it should do something similar as
> well.
>
> But it turns out that a delegate literal's type defaults to a delegate
> that takes no arguments and returns an int. As a result, the above statement
> does not compile, for two reasons: Wrong argument type, and 'rec' isn't
> defined in that scope.
>
> Since D does not implicitly give the delegate the correct type,
> it takes a ton of keywords to make the delegate have the desired
> type. The result is this:
>
> OMF_Record[] results = library.select_records(delegate(OMF_Record rec) { return (rec.record_type == LIB_HEADER);});
>
> Hideous, no matter where you place the tabs and line breaks. It is now
> several orders of magnitude more complicated than an SQL query, and
> it duplicates information: The type, name, and number of arguments
> that the delegate must have will be repeated every time select_records
> is used.
>
> Also, it can be noticed that D actually does infer the return type of the
> delegate (using 'bool' in the above expression causes a compile error),
> but it still can't infer the number of arguments or their types.
>
> So I tried to use D's "alias" keyword to make some syntactic sugar:
>
> alias delegate(OMF_Record rec) where_t;
>
> This gives an error to the effect that a basic type is required where
> the word "delegate" is. This compiles:
>
> alias bool delegate(OMF_Record rec) where_t;
>
> But the resulting definition of where_t cannot be put in front of the
> delegate literal (it can be used in the declaration of the member function,
> however).
>
> I tried using the following mixin:
>
> template selrec() {
> const char[] selrec = "delegate(OMF_Record rec)";
> }
>
> But this produced an error, and the invocation of the mixin had
> twice as many parentheses as the expression it was intended to
> replace.
>
> I finally tried to use D's "lazy evaluation" feature, but I didn't
> really expect it to work because it uses delegates underneath it
> all:
>
> class OMF {
> /* ... */
>
> // Change the declaration of the member
> // function... It just happens to be that the
> // foreach loop inside this function contains
> // a variable called 'rec' that it was passing
> // to the delegate as its 'rec' argument.
>
> OMF_Record[] select_records(lazy bool where_clause) ;
> /* ... */
> }
>
> /* ... */
>
> // Now let's use it:
>
> OMF_Record results = library.select_records(rec.type == LIB_HEADER);
>
> But as it turns out (as I expected, which was why I tried this last),
> D's "lazy" evaluation isn't as lazy as it would be if this was lazy
> evaluation in an interpreted language. "rec" comes from the scope of the
> calling function, not the scope of the foreach loop inside select_records
> where the expression will be evaluated.
>
> The only way I can get the result that I want is to subject the beautiful
> D programmming language to the ugly C preprocessor. This enables me to
> write this:
>
> #define select_records(x) _select_records(delegate(OMF_Record rec) x)
>
If you don't mind using a local var:
Record rec;
Record[] select_records( rec, rec.type==LIB_HEADER );
where the function is defined:
Record[] select_records( ref Record r, lazy bool clause )
{
Record[] result;
foreach(Record temp; items ) {
r=temp; if ( clause() ) result ~= temp; }
}
return result;
}
-DavidM
> ...which would make it LOOK like the delegate implicitly has the type
> of the argument (which was what I initially assumed, and what would
> be better). This technique would bring with it all the perils of the
> C preprocessor, and even threatens to wipe out some of the benefits
> of D. If I released such a class as open-source software, its users
> would have to subject _their_ programs to the CPP to be able to use
> the class.
>
> Fortunately (or not), I cannot abuse D in this way using DM's C
> preprocessor, because the preprocessor seems to be built into
> the C compiler somehow (as opposed to GCC, which has an external
> CPP that can be called separately).
>
> But D is still in its infancy. Over the years, future D programmers
> will run into many duplicates of this problem, and they may eventually
> cope with it by introducing an external C preprocessor to the mix.
>
More information about the Digitalmars-d-learn
mailing list