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