Getting started - D meta-program question
downs
default_357-line at yahoo.de
Sun Oct 4 05:11:54 PDT 2009
Justin Johansson wrote:
> Daniel Keep Wrote:
>
>> Justin Johansson wrote:
>>> There was mention** on the general discussion group that the D foreach_reverse
>>> language construct could be replaced (emulated?) with a (D) meta-program.
>>>
>>> ** "Even a novice programmer can write a meta-program to replace
>>> foreach_reverse without any runtime performance hit."
>>>
>>> http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=97362
>>>
>>> As I'm less than a novice with the D meta-programming facilities (at this stage of my journey into D),
>>> if someone would kindly show me the D meta-program solution to do this,
>>> I'd really appreciate the enlightenment.
>>>
>>> Thanks again.
>> Short answer: you can't.
>>
>> Long answer: you can, provided you aren't trying to reverse an opApply,
>> which is patently impossible.
>>
>> As for the "meta-program", I would suspect whoever said that was talking
>> about writing a templated type or function to handle it. You would need
>> to use template specialisation or static ifs to switch on what type
>> you've been given to reverse.
>>
>> http://digitalmars.com/d/1.0/template.html
>>
>> http://digitalmars.com/d/1.0/version.html#staticif
>
> Thanks for your answer, Daniel. I thought the original post was a bit of a red herring but
> thought I'd ask about it anyway. Good thing I did as you motivated me to delve into the
> subject just after reading your reply.
>
> Just now I've written a bit of CS101 play around code (shown below) for constructing a
> singly-linked list of numbers (Conslist idiom). As the code seems to work, it looks like
> I've cut my first teeth on "D meta programming".
>
> I'm sure there's lots to learn though .. especially looking though some of that std.functional
> stuff.
>
> If you have any comments / suggestions for improvement about this code, I'd graciously accept the same.
> It's just a tutorial exercise for learning the D way of doing things.
>
>
> class List
> {
> List next;
> int data;
>
> this( int data) {
> this.next = null;
> this.data = data;
> }
>
> static List opCall() {
> return cast(List) null;
> }
>
> static List opCall( int data) {
> return new List( data);
> }
>
> static List cons( int data, List list) {
> auto newList = List( data);
> newList.next = list;
> return newList;
> }
>
> int opApply( int delegate( ref int data) dg) {
> auto result = 0;
> auto list = this;
>
> while ( list !is null) {
> if ((result = dg( list.data)) != 0)
> break;
>
> list = list.next;
> }
>
> return result;
> }
>
> }
>
>
> void printdata( int data) {
> writef( " %d", data);
> }
>
>
> void print( List list) {
> writef( "(");
>
> if (list !is null) {
> foreach ( x; list) {
> printdata( x);
> }
> }
>
> writef( ")");
> }
>
>
> void println( List list) {
> print( list);
> writefln();
> }
>
>
> List list(A...)( A args) {
> static if (A.length == 0) {
> return List();
> }
>
> else {
> return List.cons( args[0], list( args[1..$]));
> }
> }
>
>
> void main() {
> auto l0 = list();
> println( l0);
>
> auto l1 = list( 10);
> println( l1);
>
> auto l2 = list( 10, 20);
> println( l2);
>
> auto l3 = list( 10, 20, 30);
> println( l3);
>
> }
>
>
> Outputs:
>
> ()
> ( 10)
> ( 10 20)
> ( 10 20 30)
>
> Thanks again, Justin
>
I really recommend using a struct. There's rarely need to subclass List nodes dynamically, and structs would allow you to define allocators externally, for instance, for implementing freelists.
Also, I generally think of a list node as a value, not an object :)
In that sense ..
module test;
import std.string;
struct List(T)
{
List* next;
T data;
static List* opCall(T data, List* next) {
auto res = new List;
res.next = next;
res.data = data;
return res;
}
static List* opCall(T[] data...) {
if (!data.length) return null;
else if (data.length == 1) return opCall(data[0], null);
else return opCall(data[0], opCall(data[1..$]));
}
List* cons(T data) { return List(data, this); }
int opApply( int delegate( ref int data) dg) {
auto current = this;
do {
if (auto res = dg(current.data)) return res;
current = current.next;
} while (current);
return 0;
}
string toString() {
string res = "(";
bool first = true;
foreach (value; *this) {
if (first) first = false;
else res ~= ", ";
res ~= format(value);
}
return res ~ ")";
}
}
void print(T)(T what) {
if (!what) writefln("(nil)");
else writefln(what.toString());
}
import std.stdio;
void main() {
auto l0 = List!(int)();
print(l0);
auto l1 = List!(int)(10);
print(l1);
auto l2 = List!(int)(10, 20);
print(l2);
auto l3 = List!(int)(10, 20, 30);
print(l3);
}
gentoo-pc ~ $ gdc test.d -o test_c -g && ./test_c
(nil)
(10)
(10, 20)
(10, 20, 30)
More information about the Digitalmars-d-learn
mailing list