www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - "Modern D Design" :))

reply "Aleksey Bobnev" <uw front.ru> writes:
Yesterday I tried to get back to idea of using D templates for
meta-programming. Last time I tried it there were some serious bugs which
made meta-programming if not impossible at all, still very hard to achieve.

This time it turned out to be a fairly easy task. Though C++ specialization
is still much more powerful than D's one. Therefore template
meta-programming code in C++ is declarative by nature, while in D it seems
to be mostly imperative. But due to unique template syntax introduced in D
and some other advantages, D code surely looks cleaner, much more compact,
and doesn't require any preprocessor macros.

At this time I have only typelists and related meta functions similar to
those from famous Loki library, but it already seems to me - D language has
a Bright(sorry for a pun) future in area of meta-programming. Possibly with
some more improvements to template facility it will beat C++ completely some
day.

I ported a simple lisp program, which finds a solution to hanoi tower
problem, both to C++ and D.
Here's an original code(slightly modified code from xlisp examples):
(defun hanoi(n)
 (eval (cons 'progn (transfer "A" "B" "C" n ))))

(defun print-move ( from to )
  (princ "Move Disk From ")
  (princ from)
  (princ " to ")
  (princ to)
  (princ "\n")
  nil)

(defun transfer ( from to via n )
  (cond ((equal n 1) (list (cons 'print-move (list from to))))
    (t (append
            (append (transfer from via to (- n 1)) (list (cons 'print-move
(list from to))))
            (transfer via to from (- n 1))))))

Here's C++ meta-program "port"(via Loki):
#include <iostream>
#include <typeinfo>
#include "TypeList.h"

using namespace std;

struct A
{
    static const char * name()
    {
        return "A";
    }
};

struct B
{
    static const char * name()
    {
        return "B";
    }
};

struct C
{
    static const char * name()
    {
        return "C";
    }
};

template <typename From,typename To>
struct print_move
{
    static void exec()
    {
        cout<<"Move Disk From "<<From::name()<<" to "<<To::name()<<endl;
    }
};

template <typename From,typename To,typename Via, int n>
struct transfer
{
    typedef typename Loki::TL::Append<typename
transfer<From,Via,To,n-1>::type,Loki::Typelist<print_move<From,To>,Loki::Nul
lType> >::Result type0;
    typedef typename Loki::TL::Append<type0,typename
transfer<Via,To,From,n-1>::type>::Result type;
};

template <typename From,typename To,typename Via>
struct transfer<typename From,typename To,typename Via, 1>
{
    typedef Loki::Typelist<print_move<From,To>,Loki::NullType> type;
};

template <typename FnList>
struct eval
{
};

template <typename Fn,typename Fns>
struct eval <Loki::Typelist<Fn,Fns> >
{
    static void exec()
    {
        Fn::exec();
        eval<Fns>::exec();
    }
};

template <>
struct eval <Loki::NullType>
{
    static void exec()
    {
    }
};

int main()
{
    eval<typename transfer<A,B,C,3>::type>::exec();
}

And here's D port (via my crazy little library):
import Thor.typelist;
import Thor.meta;
import std.stdio;

class A{}
class B{}
class C{}

template PrintMove(From,To)
{
    struct PrintMove
    {
        static void eval()
        {
            writef("Move Disk From %s to
%s\n",typeid(From).toString(),typeid(To).toString());
        }
    }
}

template Transfer(From,To,Via,int n : 1)
{
    alias TL!(PrintMove!(From,To)) Transfer;
}

template Transfer(From,To,Via,int n)
{
    alias
Append!(Append!(.Transfer!(From,Via,To,n-1),TL!(PrintMove!(From,To))),
                  .Transfer!(Via,To,From,n-1)) Transfer;
}

template Eval(TL_ : TypeList)
{
    void Eval()
    {
        TL_.H.eval();
        .Eval!(TL_.T)();
    }
}

template Eval(T : NullT)
{
    void Eval()
    {
    }
}

void main()
{
    Eval!(Transfer!(A,B,C,3))();
}

Now to implementation details. Here is how my TypeList looks and
works(complete code may be found in attachment along with hanoi sample in
C++,
lisp and prolog):

// end of list marker type
class NullT
{
}

// common base type for all typelists
class TypeList
{
    alias NullT H;
    alias NullT T;
    template Length()
    {
        const int Length = 0;
    }
}

// 1-type typelist constructor
template TL(T0)
{
    class TL : TypeList
    {
        public:
        alias T0 H;
        alias NullT T;
        template Length()
        {
            const int Length = 1;
        }
    }
}

// 2-type length typelist
template TL(T0,T1)
{
    class TL : TypeList
    {
        public:
        alias T0 H;
        alias .TL!(T1) T;
        template Length()
        {
            const int Length = 2;
        }
    }
}

// generated constructors for any arbitary number of types
// ...
//

//  Cons is similar to cons in lisp
/*
    Construct type list from head and tail
    typical use :
    Cons!(A,Cons!(B,Cons!(C,NullT)))
*/
template Cons(_Head, _Tail : TypeList)
{
    class Cons : TypeList
    {
        alias _Head H;
        alias _Tail T;
        template Length()
        {
            const int Length = 1 + .Length!(T);
        }
    }
}

template Cons(_Head : NullT, _Tail : TypeList)
{
    class Cons : TypeList
    {
        alias _Tail.H H;
        alias _Tail.T T;
        template Length()
        {
            const int Length = .Length!(_Tail);
        }
    }
}

template Cons(_Head, _Tail : NullT)
{
    class Cons : TypeList
    {
        alias _Head H;
        alias _Tail T;
        template Length()
        {
            const int Length = 1;
        }
    }
}

/*
       General meta-functions
*/

template Equal(T0,T1)
{
    const bool Equal = false;
}

template Equal(T0,T1 : T0)
{
    const bool Equal = true;
}

template SelectType(bool c, T0,T1)
{
    alias T0 SelectType;
}

template SelectType(bool c : false, T0,T1)
{
    alias T1 SelectType;
}

template SelectAlias(bool c, alias T0,alias T1)
{
    alias T0 SelectAlias;
}

template SelectAlias(bool c : false, alias T0, alias T1)
{
    alias T1 SelectAlias;
}

/*
    typelist manipulation
*/
template Length(_TL : TypeList)
{
    const int Length = 1 + .Length!(_TL.T);
}

template Length(_TL : NullT)
{
    const int Length = 0;
}


template RemoveAll(_TL : TypeList, T)
{
    alias SelectType!(Equal!(_TL.H,T),.RemoveAll!(_TL.T,T),
                                      .Cons!(_TL.H,.RemoveAll!(_TL.T,T))
                     ) RemoveAll;
}

template RemoveAll(_TL : NullT, T)
{
    alias NullT RemoveAll;
}

template RemoveAll(_TL, T : NullT)
{
    alias _TL RemoveAll;
}

template Remove(_TL : TypeList, T)
{
    alias SelectType!(Equal!(_TL.H,T),_TL.T,
                                      .Cons!(_TL.H,.Remove!(_TL.T,T))
                     ) Remove;
}

template Remove(_TL : NullT, T)
{
    alias NullT Remove;
}

template Remove(_TL, T : NullT)
{
    alias _TL Remove;
}

template IndexOf(_TL : NullT, T, int i = 0)
{
    const int IndexOf = -1;
}

template IndexOf(_TL : TypeList, T, int i = 0)
{
    const int IndexOf = .Equal!(_TL.H,T) ? i  : .IndexOf!(_TL.T,T,i + 1);
}

template TypeAt(_TL : NullT, int i)
{
    static assert(0);
}

template TypeAt(_TL : TypeList, int i : 0)
{
    alias _TL.H TypeAt;
}

template TypeAt(_TL : TypeList, int i)
{
    alias .TypeAt!(_TL.T,i - 1) TypeAt;
}

template TypeAtNonStrict(_TL : NullT, int i, _Default = NullT)
{
    alias _Default TypeAtNonStrict;
}

template TypeAtNonStrict(_TL : TypeList, int i : 0, _Default = NullT)
{
    alias _TL.H TypeAtNonStrict;
}

template TypeAtNonStrict(_TL : TypeList, int i, _Default = NullT)
{
    alias .TypeAtNonStrict!(_TL.T,i - 1,_Default) TypeAtNonStrict;
}

template Append(_TL0 : TypeList, _TL1: TypeList)
{
    alias Cons!(_TL0.H,.Append!(_TL0.T,_TL1)) Append;
}

template Append(T: NullT, _T : TypeList)
{
    alias _T Append;
}

template Append(T: NullT, _T : NullT)
{
    alias NullT Append;
}

template NoDups(_TL : TypeList)
{
    alias Cons!(_TL.H,Remove!(.NoDups!(_TL.T),_TL.H)) NoDups;
}

template NoDups(_T : NullT)
{
    alias NullT NoDups;
}

template TypeidPrint(_TL : TypeList)
{
    void TypeidPrint()
    {
        typeid(_TL.H).print();
        .TypeidPrint!(_TL.T)();
    }
}

template TypeidPrint(_T)
{
    void TypeidPrint()
    {
        typeid(_T).print();
    }
}

template TypeidPrint(_TL : NullT)
{
    void TypeidPrint()
    {
    }
}

/*
    and finally a little sanity test
*/
alias TL!(int,float,char,double) tl0;
alias TL!(double,char,float,uint) tl1;
alias Append!(tl0,tl1) tl2;
alias NoDups!(tl2) tl3;

template TypeidPrint(_TL : TypeList)
{
    void TypeidPrint()
    {
        typeid(_TL.H).print();
        .TypeidPrint!(_TL.T)();
    }
}

template TypeidPrint(_T)
{
    void TypeidPrint()
    {
        typeid(_T).print();
    }
}

template TypeidPrint(_TL : NullT)
{
    void TypeidPrint()
    {
    }
}

void main()
{
    static assert(IndexOf!(tl0,char) == 2);
    static assert(IndexOf!(tl0,TypeAt!(tl0,IndexOf!(tl0,char))) == 2);
    static
assert(IndexOf!(tl0,TypeAtNonStrict!(tl0,IndexOf!(tl0,uint),char)) == 2);
    printf("tl0.l == %d\ntl1.l == %d\ntl2.l == %d\ntl3.l = %d\n",
            tl0.Length!(),tl1.Length!(),tl2.Length!(),tl3.Length!());
    printf("types in tl0\n");
    TypeidPrint!(tl0)();
    printf("types in tl1\n");
    TypeidPrint!(tl1)();
    printf("types in tl2\n");
    TypeidPrint!(tl2)();
    printf("types in tl3\n");
    TypeidPrint!(tl3)();
}


begin 666 Thor.zip

M9IDQG N&IJ8!``"^!0``$ ```&-P<"]H86YO:5]C="YC<'"E4TU/ S 8OI/P

M,BN:G ,52IN:LS(-`P\B).3'#F2^*R[D4 UXN5"WJVTL6B!Q+K2Y745A$ :-

M;II:0C2)D [<A,%FVW5ZCNMTG^OL'-?9R-7PLBJ8Z6=KY?!4JS)V_Q8J==E5
M+:1Y+]6:#TNLE<B!?_%L'(X%&T-I](PR>!3ZLPV B%+[2TA7&0E E$47RF-<






M^FAK%/WOH[340;L>&\& ;>KQZ>F1TLDKC^GDY 0N.X25W1*LJ/;"#R5X;MW 
MJ>TBO)7OX.ST] /4`RR-\DBPU' G\F>0:4=!`:15"$)*VSMA" -$)JZMW2XR
MYDG2?,=4P>P79WD#Y\?'\!4#M68!W]& )PD;;ULO^IY,"YRYFX?"EL=&Q,BY
M`9;.:4(UJUZ07<%2*0K6O/^-0>-0E?0-^IY"(&L 6D !YR Y=0Z]5=3PFU.B
MISI%+$L'U!IBWF6P3;P5'J&QGJ>&O1R7O+,! 4$=>F2[6+V)J."68F=3A 9Y


M3 P>G<?P2!#R#E/9ZUY)2!1%39KB`+9YV=M'2RNXB$!A;]U,!/Z?C6RCPWB7
M%PY9(O6E*8 )<QE*X5]Y3"=%P$J$",DI$7$!/Y)!;KQY:;X,>$.-4=C ^FJU


M,_EP__!E.GF83 ZQ8+X..V%:!&W;<ID]K?("\KE!E6_(-<DMGY7DR\722 EG
MU>=/U<<*?B9EP[P`CHZ.#J

MM&O)\9N2YL:-TS9WKB\3R].YF9OI0"0D84(1.I!TXNODO]\N(!*B24007Q39

M?X_T#P][9'1/+J) ,DXN0O:)XF'LI]74SY$:R<C/8A2Q\7 AB<?$%P$CU/?%
M;$XCSF*2 /R1$!\&2%/ [2T$'I"=WZ&7C,CK'WX ERSFDVA ?F41D]PG[Z28
M2#J;\6A"H.?B.E'<\/6.) GTC<G%?!YR%NP<5&AW0"Z" ,<BVO^#Q2

MD'#IWL"9IW(N8D: :,HD`SL!^BAA`?G(DZE($S)F(&<NQ1T/6 #L:*)L1$?B
MCA$_ VXX1B+A/ER?SQF5A$>$AB'2H7%IM. P$LE4'QD.NB/2:- &H]&[Q#Q.
MYW,A$[1V(/QTQJ*$)D!YD#L334
M&8,8-4R5K 9)G/*$CGC(DWLBQM6VS4QZ0-XF8%9CNAT:P^<=PRVS,/N$ F.$
MR&?**0 PQ&%0`]_RZ]MG"L 5C1.2S .:L 'Y1QHQ<#Q

M\UUH!3K-J"]%;-#U

MH_N#O_$(_-?X!08,$H#OT
M2)SLE20O2T4RC#FD[,C;2E[3VQWV]LA  'E^,! N;/%RV//RDYD;O2HP,-HA




M.[4ARZ+,<4O*8'/LJM'S%C12`JUJG;2I%C8GKKH=MZ6;DFI5\+1U!;$Y==7R
MI%4ME6BKJF?=J(K-F:N^I^WKJ^1;E3[O4&ELSETU/^M(\P4(R]3XL&OUD?FA

M \V1JX7Z&[20`F8U4UMSN+708//<U59MS/IJH+,9K-5YXEJ0L#EVM5IK,TL;
MQ$)G&UJK%=N?EM:%B,V)JU7;G=,V FPU;4<3XKHXL3EUM6\'L^E&N*U&[G(J
M7A<L-F>NENYJ'M\(O-7<G2\"ZB+&YMS5YIVN(!II8*VJ;V;Y41<VHCITM7[W
M:Y=&:EB'8%,+GP;8L7%=-1UM8M747!?+8&QJR=54`6SZKB.RB?5:2PI9AF53
MB[U6M,#FR
ML#EV';KM6" W4M4ZE%NVRJZK'S8GKN.Y14OT1OI:!W4;U_=UE<3FU'5DMZTX
MT$AIZ_!N;66AKJ;8G+F.\5:6)1II;AWH[:YIU%47FW/7T=[> D C]:W?*WP$

M77UAZ\M/+5G#XA"/HG;5B FP.7+UBJTO?+5I$HMK/(JJ67MVP.:YJW]L?<FM
M=;M8G.2)U.MLQBAV+ML%&^<_H7D"Q;Y&=K(ZT5.J%-8U#C8GKI[T5,J,K7O2
MDRM/UO4D;$Y=W>E)U38;6<SJ6$^S,%K73-B<N7K7TZNJ-C*;U<6><$FVKJVP
M.7?ULR=:SVUD.^M? C_U8G!= Z$=#ET][BE7DIL94+N=VKAB3GV]"\^WS_[J
M8D\(V++"#VD
MDJGJ<1LSPG&S%BG2R13^9X6M-_3&((KR4D553."=L$ QC0?YUAN_,1J0W3&7


ME::+\Y]?9&*-\PRO])D-N<^5<8778C9/$[V3T\)%E,, =N-B;Z,[X5,</+([


MS'FT=5Y4D3^ >9GA77A?[FSFQ:)T1OXBRL3D)W)(/AO&A6-]Y.3D^"KB(.:N
MX $9<<;3(S]D/&XS3W `L;-MC2I2Y87VXE]X%"A'UTF))H22"0<_(7"!?8)V


M2CR21KCS&PO0;AIJ'A7:4$Y.C?DW\VO,N277SJR>>[;JH6D]<FCS<)/+D9[H
M02KYLRNJA]JNB9*O1HG_X^TE8Z2E<K)/>KF/+;3XBE%Y+:*;1'*_>7C&'<0G
MW6LY1#TB9
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
M<\-$CC#BJ

MC&5+UL'MT:/YTNDED,WJFT*MA) 655QNJ8>M86!=XBF--!D=[]9O[T6RL 'Z

M:!7+E81N[^+-9;=W='QVV.TN7ZL79UM'"9RTPZ^D(__B*G:I#OC+L5?3F78>
MN7X3TF(O]>Z:?Y* 5'XZAF$EIVE-\[,7*E%D.]^*RH:W'TNILY+8AM\]MZTT
MM>\_YI7SP/WN -Z3!/Q3]H3$) I1\-Q9ZYE-/5U=/IEK<NW_9P5]VP5QU<TN


MA)LQ(8\F6%$!``!"`P``!P```&AA;F]I+F2-44U+`S$0O2_L?\ 6A 1BH'BS
MI[8J'JH(!D^"A&ZJP6RR)-.*E/YWDZ:[V?H]L)MA/MZ;-Z.:UCI _,4Z!N^M
MU,K#I
MXBMG&\HM*8MM6:! 'MQZ";DB10_)5"! +='&JAK)C="8I%Q?ENW-*9 K/(HX
MZ$+Y5Q3IT(E'8,/_T8QH%*KJ_1B$ ;V'P/N,21?G=A EDXP?!!V>8VG<">-7
MTG7*Z(,2-&A!!IVC<=8IM!(>\46%>ZE5OPW2PTS^C_\9>]JVTM05[E[6M2:>



M#L


M-3 E27M=061>H^X$W%: SH8A+YQWB/CL\5D54B1:W?=&; 3(M:#YMU
MJ$[3_ABWML^VLV.4+K:+=FX3)%W5&U!+`P04````" !&OI Q7]>U9P$!``#Z
M`0``" ```&AA;F]I+G!L94^Q;H,P%-R1^ =GPD O5:DZM9.3 2QXRH:0925.
MB H8Q5:: 8_O,T\X1?5BO[OSW;V3'4Y*>]OS^C =&Q#YQS9-&)XG<P0E< A/
M%4#M^0$1E+ZD29K\<1#TGVUFXN
M 7,.LU4W\ 7X)(\(DY[Z8+X=^?LK/"X/\)9 ;[F 70Q?5ZNSRMX-.[?NFUUN
MMF<9",B8M_C8-63PI0?;! ]04$ M`ON?VX.$X.5RMD1)B:LRN2V YD6\1[E$

M\U]02P,$" ``````BXZ;,0````````````````4```!4:&]R+U!+`P04````

MG+#B5\#H!N("15= 3)P7Z'0NT-!IQ[:#CL9WMT
M)"MMT,,4<W*L,'II6)X+M<1,I(:9*K0V9*S0"I]D=$B:O(7KP>"FYS^WF$A:

M.9;EPK!4$E*MUVC,=49&X:'3P92L6*H&_ 1F>BT  _0>6>')"+*D=BR_8:'M



M13<<3 N&N<O, ^*!C9/PX3'\!U!+`P04````" `JCYLQ*%BJIX<"```8!P``


MD 92IB5JR&L$2U#KI::UAHS*2BID2.O%>.1XTL*:>&E 7:!/YY[L_BN).5!M
MC701> );R%9]!F0+Y+4TZ.DYH='O+)Q'D5.<CD? OJ0 AF.8PSU:43$M6)2E

M,H,YE4+J$&J+"NU6LB"P=!Y"5SIGE%[HE_!#D]7.UA,QB+R4+%*%D!(MX>">
M<F0--T=',$<C%_H`' /N:"E!!=.=Y :^L$2#NM6JF"HR+6[FFBFS`D1F:Z'4
M!BI)&I$QAQ*M..[W0VJ8CT?3T_$H-'?;N9.PFQ=^Q17+E; X'OT)Y659$=L`



M-Z17R-;?Q(2Z>"8T/$**D(4TYF )DD_M&]"J[ I$CW$`^!+A"YNT ^LV/<">
MAW5]\]ZL;;GNI/WKU.M:>WLFKA, P_BBG^_.=4"TLSZF.W(!TDP<HH_YALH%
M_=9,HJ I%,]ZA\639SNHIE \"P/L<$D< ZG35P_)K2Z0_=Y>"X/=79G!32%5
M/G!W&BI<-N=CLA6)3W9Z.HFV8C$<'L(D(-O0+K11\"[_`E!+`P04````" #D
MHIDQ#B=K`JL$``#H(P``#P```%1H;W(O='EP96QI<W0N9,U774_C.!1]1^(_
M7.:I&=*0E,\!C58=NBM6ZK"C';^/3&**11IG$Z<[[(K_OC=VTM*4?)2Z98M,
MJ7WON><<1]7AZ./^'N"+/( $^C""KTS2.!&3A$ZG/)K F-\E-'G253.6I%Q$
M\ ]+A-[I^18,7/>DC[].81BRQY0]P1=Q%['9_IZN^9;=A=R'D9A2'NFM<BB-
M'E.8")#B4F

MDK&$!3!%._HO_> 1C/;W/A[M[TU%D(5,.>?(IYB%/)57N>8XX3,JV?[>OYH`

M11/YT+/TMD+1+U]$J43.LBB!S^ 6S<\%BRK(#S*&RSDG2Y&J ?+ $!S]Z2#O



MRCJ 3N6.X!?L0BRG*)D;;G,X!,^J4E!#AW))DYZ]F)M**KD/-$U9(GMN"T:I


MFW]E:(SB,['S5LLJD.L&DO)&<1+4#L+#M7!>]4IMUN+<BE$6I_H:VO6BW/(+
MTM&=A?&6K4XMJP"LF]/"LJ9;$>/!MX1'LI;J3/! J7 UB$AUJH583JRKKA;G
MSHOV4MB\X+F9U-N(%"RZ#EG$E_9IY:QEX")JJRN52>9+Q07RV CWB9C"`Z.!

M-ZB"J*I]<5SQKGQ<%!CFTNJ^1B^S:4,^K:!V"9?DY;/R7+FP5:GE71F3G*,X
M-W6B'6).]ERR0EY/=B&W5/__OMX.RLBX1]R*"MQLTA"K_S4OJ^2)NZI(F63P
MYAH4'1T!S:3H3UC$$L0/((M!"ABX$-.$3IED25H5;A-O>]H=,C[HX0!S\ <U
M\E=5V62P=6$XPZ"VXW6TV>1X%_)PC$&%)VLJM,G)CD3B)(,Z3]?7:9/3W4G%
M80;5GKU)K4W.=BH8YQG4?/Y6S38YW[5L'&E0^<4&RFUR\0[B<:I!_9\VTV^3



MO5^J[TC09/H?U*3__P!02P$"% `*``````"=CILQ````````````````! ``
M`````````! `````````8W!P+U!+`0(4`!0````(`)IFF3&>"X:FI $``+X%
M```0````````````( ```"(```!C<' O:&%N;VE?8W0N8W!P4$L!`A0`% ``
M`` `R+K4*A,8^JI ` ``.08```X```````````` ````] $``&-P<"].=6QL

M````  0``&-P<"]4>7!E3&ES="YH4$L!`A0`% ```` `R+K4*IFQI(4\! ``
M;A ```\```````````` ````W!(``&-P<"]4>7!E36%N:7 N:%!+`0(4`!0`

M4$L!`A0`% ```` `+;^8,3,.J<'-````XP$```D```````````` ````NQH`

M````( ```*\;``!H86YO:2YP;%!+`0(4``H``````(N.FS$`````````````
M```%````````````$ ```-8<``!4:&]R+U!+`0(4`!0````(`#R5F3%W%P8W

M```(`"J/FS$H6*JGAP(``! '```-````````````( ```'P>``!4:&]R+W1R
M86ET<RYD4$L!`A0`% ```` `Y**9,0XG:P*K! ``Z",```\```````````` 

`
end
Dec 27 2004
next sibling parent reply "Walter" <newshound digitalmars.com> writes:
"Aleksey Bobnev" <uw front.ru> wrote in message
news:cqp7v0$1grl$1 digitaldaemon.com...
 This time it turned out to be a fairly easy task. Though C++
specialization
 is still much more powerful than D's one. Therefore template
 meta-programming code in C++ is declarative by nature, while in D it seems
 to be mostly imperative. But due to unique template syntax introduced in D
 and some other advantages, D code surely looks cleaner, much more compact,
 and doesn't require any preprocessor macros.
Great!
 At this time I have only typelists and related meta functions similar to
 those from famous Loki library, but it already seems to me - D language
has
 a Bright(sorry for a pun) future in area of meta-programming. Possibly
with
 some more improvements to template facility it will beat C++ completely
some
 day.
What do you think it needs? Also, what in particular are you thinking of by saying that C++ specialization is much more powerful? D's is equivalent, if not more powerful.
Dec 27 2004
parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Walter" <newshound digitalmars.com> wrote in message
news:cqpgh1$1qrs$1 digitaldaemon.com...
 "Aleksey Bobnev" <uw front.ru> wrote in message
 news:cqp7v0$1grl$1 digitaldaemon.com...
...
. Possibly
 with
 some more improvements to template facility it will beat C++ completely
some
 day.
What do you think it needs? Also, what in particular are you thinking of
by
 saying that C++ specialization is much more powerful? D's is equivalent,
if
 not more powerful.
I know there are people out there that could answer this better than i but i will try: Here is the example of C++ code: <CODE> #include <iostream> using namespace std; template<class U,class V,class X,class Y> class Four { U i; V j; X k; Y l; }; template<class U,class V,class X,class Y> int WhatFour(const Four<U,V,X,Y>& four) { cout << "general template\n"; } template<class U,class V,class X> int WhatFour(const Four<int,U,V,X>& four) { cout << "specialization:: first int\n"; } template<class U,class V> int WhatFour(const Four<U,U,V,V>& four) { cout << "specialization:: first two equal, second two equal\n"; } int main(int argc, char *argv[]) { WhatFour(Four<int,float,char,bool>()); WhatFour(Four<float,float,char,bool>()); WhatFour(Four<float,float,char,char>()); WhatFour(Four<int,int,float,char>()); /* will print: specialization:: first int general template specialization:: first two equal, second two equal specialization:: first int */ return 0; } </CODE> Is there a way to write this in D? If not (and i haven't found one) here is our problem. Specializations like this are used alot in C++.
Dec 30 2004
parent reply "Walter" <newshound digitalmars.com> writes:
"Ivan Senji" <ivan.senji public.srce.hr> wrote in message
news:cr0f07$2uj7$1 digitaldaemon.com...
 Is there a way to write this in D? If not (and i haven't found one) here
is
 our problem. Specializations like this are used alot in C++.
Ah, I see. What you're asking for is not specialization, but implict instantiation of function templates. You can do the same sort of specialization, however, in D: class Four(U, V, X, Y) { U i; V j; X k; Y l; } template WhatFour(U,V,X,Y) { void func(Four!(U,V,X,Y) four) { printf("general template\n"); } } template WhatFour(U:int,V,X,Y) { void func(Four!(int,V,X,Y) four) { printf("specialization:: first int\n"); } } template WhatFour(U,V:U,X,Y:X) { void func(Four!(U,U,X,X) four) { printf("specialization:: first two equal, second two equal\n"); } } alias WhatFour!(int,float,char,bool).func whatfour; alias WhatFour!(float,float,char,bool).func whatfour; alias WhatFour!(float,float,char,char).func whatfour; alias WhatFour!(int,int,float,char).func whatfour; int main() { Four!(int,float,char,bool) f; Four!(float,float,char,bool) g; Four!(float,float,char,char) h; Four!(int,int,float,char) i; whatfour(f); whatfour(g); whatfour(h); whatfour(i); /* will print: specialization:: first int general template specialization:: first two equal, second two equal specialization:: first int */ return 0; }
Jan 29 2005
parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Walter" <newshound digitalmars.com> wrote in message
news:cti6lg$1o0q$1 digitaldaemon.com...
 Ah, I see. What you're asking for is not specialization, but implict
 instantiation of function templates. You can do the same sort of
 specialization, however, in D:
<snip>
 int main()
 {
   Four!(int,float,char,bool) f;
   Four!(float,float,char,bool) g;
   Four!(float,float,char,char) h;
   Four!(int,int,float,char) i;

   whatfour(f);
   whatfour(g);
   whatfour(h);
   whatfour(i);

   /*
   will print:
 specialization:: first int
 general template
 specialization:: first two equal, second two equal
 specialization:: first int
   */
Thanks for this example, but i get: specialization:: first int general template general template specialization:: first int ?
   return 0;
 }
Jan 30 2005
parent "Walter" <newshound digitalmars.com> writes:
"Ivan Senji" <ivan.senji public.srce.hr> wrote in message
news:ctiav5$1u2e$1 digitaldaemon.com...
 Thanks for this example, but i get:

 specialization:: first int
 general template
 general template
 specialization:: first int
 ?
So did I at first. That's a compiler bug, and I fixed it (will appear in next update). -Walter
Jan 30 2005
prev sibling next sibling parent reply "Zz" <Zz Zz.com> writes:
I could not resist.
As a person who really likes Lisp and D here is a Dylan version.

The code is from the recently released Open Dylan.
I personally used Dylan about 3 years ago for a few projects of my own while
not Lisp it has a small runtime and it statically links.

Module:    hanoi
Synopsis:  The classic Towers of Hanoi puzzle
Author:    Andy Armstrong
Copyright:    Original Code is Copyright (c) 1995-2004 Functional Objects,
Inc.
              All rights reserved.
License:      Functional Objects Library Public License Version 1.0
Dual-license: GNU Lesser General Public License
Warranty:     Distributed WITHOUT WARRANTY OF ANY KIND

define class <disk> (<object>)
  constant slot diameter :: <integer>,
    required-init-keyword: diameter:;
end class <disk>;

define function make-disk
    (integer :: <integer>) => (disk :: <disk>)
  make(<disk>, diameter: integer)
end function make-disk;

define class <tower> (<object>)
  constant slot name :: <string>,
    required-init-keyword: name:;
  constant slot disks :: <deque> = make(<deque>);
end class <tower>;

define method initialize
    (tower :: <tower>,
     #key
 => ()
  next-method();
  for (disk in initial-disks)
    push(tower.disks, disk)
  end
end method initialize;

define method height
    (tower :: <tower>) => (height :: <integer>)
  size(tower.disks)
end method height;

define variable *n-operations* :: <integer> = 0;

define method move-disk
    (from-tower :: <tower>, to-tower :: <tower>)
  *n-operations* := *n-operations* + 1;
  format-out(".");
  let disk = pop(from-tower.disks);
  push(to-tower.disks, disk)
end method move-disk;

define method hanoi
    (from-tower :: <tower>, to-tower :: <tower>, with-tower :: <tower>,
     #key count :: <integer> = from-tower.height)
 => ()
  if (count >= 1)
    hanoi(from-tower, with-tower, to-tower, count: count - 1);
    move-disk(from-tower, to-tower);
    hanoi(with-tower, to-tower, from-tower, count: count - 1)
  end
end method hanoi;
Dec 27 2004
parent Norbert Nemec <Norbert Nemec-online.de> writes:
Zz wrote:

 The code is from the recently released Open Dylan.
I know this is drifting off-topic, but still: what is "Open Dylan"? I know of Gwydion and FunctionalDeveloper. The news page of Gwydion mentiones that FD might become OpenDylan one day, but information generally seems rather confusing.
Jan 07 2005
prev sibling parent M <M_member pathlink.com> writes:
Think the Lisp wins this on ;)

In article <cqp7v0$1grl$1 digitaldaemon.com>, Aleksey Bobnev says...
Yesterday I tried to get back to idea of using D templates for
meta-programming. Last time I tried it there were some serious bugs which
made meta-programming if not impossible at all, still very hard to achieve.

This time it turned out to be a fairly easy task. Though C++ specialization
is still much more powerful than D's one. Therefore template
meta-programming code in C++ is declarative by nature, while in D it seems
to be mostly imperative. But due to unique template syntax introduced in D
and some other advantages, D code surely looks cleaner, much more compact,
and doesn't require any preprocessor macros.

At this time I have only typelists and related meta functions similar to
those from famous Loki library, but it already seems to me - D language has
a Bright(sorry for a pun) future in area of meta-programming. Possibly with
some more improvements to template facility it will beat C++ completely some
day.

I ported a simple lisp program, which finds a solution to hanoi tower
problem, both to C++ and D.
Here's an original code(slightly modified code from xlisp examples):
(defun hanoi(n)
 (eval (cons 'progn (transfer "A" "B" "C" n ))))

(defun print-move ( from to )
  (princ "Move Disk From ")
  (princ from)
  (princ " to ")
  (princ to)
  (princ "\n")
  nil)

(defun transfer ( from to via n )
  (cond ((equal n 1) (list (cons 'print-move (list from to))))
    (t (append
            (append (transfer from via to (- n 1)) (list (cons 'print-move
(list from to))))
            (transfer via to from (- n 1))))))

Here's C++ meta-program "port"(via Loki):
#include <iostream>
#include <typeinfo>
#include "TypeList.h"

using namespace std;

struct A
{
    static const char * name()
    {
        return "A";
    }
};

struct B
{
    static const char * name()
    {
        return "B";
    }
};

struct C
{
    static const char * name()
    {
        return "C";
    }
};

template <typename From,typename To>
struct print_move
{
    static void exec()
    {
        cout<<"Move Disk From "<<From::name()<<" to "<<To::name()<<endl;
    }
};

template <typename From,typename To,typename Via, int n>
struct transfer
{
    typedef typename Loki::TL::Append<typename
transfer<From,Via,To,n-1>::type,Loki::Typelist<print_move<From,To>,Loki::Nul
lType> >::Result type0;
    typedef typename Loki::TL::Append<type0,typename
transfer<Via,To,From,n-1>::type>::Result type;
};

template <typename From,typename To,typename Via>
struct transfer<typename From,typename To,typename Via, 1>
{
    typedef Loki::Typelist<print_move<From,To>,Loki::NullType> type;
};

template <typename FnList>
struct eval
{
};

template <typename Fn,typename Fns>
struct eval <Loki::Typelist<Fn,Fns> >
{
    static void exec()
    {
        Fn::exec();
        eval<Fns>::exec();
    }
};

template <>
struct eval <Loki::NullType>
{
    static void exec()
    {
    }
};

int main()
{
    eval<typename transfer<A,B,C,3>::type>::exec();
}

And here's D port (via my crazy little library):
import Thor.typelist;
import Thor.meta;
import std.stdio;

class A{}
class B{}
class C{}

template PrintMove(From,To)
{
    struct PrintMove
    {
        static void eval()
        {
            writef("Move Disk From %s to
%s\n",typeid(From).toString(),typeid(To).toString());
        }
    }
}

template Transfer(From,To,Via,int n : 1)
{
    alias TL!(PrintMove!(From,To)) Transfer;
}

template Transfer(From,To,Via,int n)
{
    alias
Append!(Append!(.Transfer!(From,Via,To,n-1),TL!(PrintMove!(From,To))),
                  .Transfer!(Via,To,From,n-1)) Transfer;
}

template Eval(TL_ : TypeList)
{
    void Eval()
    {
        TL_.H.eval();
        .Eval!(TL_.T)();
    }
}

template Eval(T : NullT)
{
    void Eval()
    {
    }
}

void main()
{
    Eval!(Transfer!(A,B,C,3))();
}

Now to implementation details. Here is how my TypeList looks and
works(complete code may be found in attachment along with hanoi sample in
C++,
lisp and prolog):

// end of list marker type
class NullT
{
}

// common base type for all typelists
class TypeList
{
    alias NullT H;
    alias NullT T;
    template Length()
    {
        const int Length = 0;
    }
}

// 1-type typelist constructor
template TL(T0)
{
    class TL : TypeList
    {
        public:
        alias T0 H;
        alias NullT T;
        template Length()
        {
            const int Length = 1;
        }
    }
}

// 2-type length typelist
template TL(T0,T1)
{
    class TL : TypeList
    {
        public:
        alias T0 H;
        alias .TL!(T1) T;
        template Length()
        {
            const int Length = 2;
        }
    }
}

// generated constructors for any arbitary number of types
// ...
//

//  Cons is similar to cons in lisp
/*
    Construct type list from head and tail
    typical use :
    Cons!(A,Cons!(B,Cons!(C,NullT)))
*/
template Cons(_Head, _Tail : TypeList)
{
    class Cons : TypeList
    {
        alias _Head H;
        alias _Tail T;
        template Length()
        {
            const int Length = 1 + .Length!(T);
        }
    }
}

template Cons(_Head : NullT, _Tail : TypeList)
{
    class Cons : TypeList
    {
        alias _Tail.H H;
        alias _Tail.T T;
        template Length()
        {
            const int Length = .Length!(_Tail);
        }
    }
}

template Cons(_Head, _Tail : NullT)
{
    class Cons : TypeList
    {
        alias _Head H;
        alias _Tail T;
        template Length()
        {
            const int Length = 1;
        }
    }
}

/*
       General meta-functions
*/

template Equal(T0,T1)
{
    const bool Equal = false;
}

template Equal(T0,T1 : T0)
{
    const bool Equal = true;
}

template SelectType(bool c, T0,T1)
{
    alias T0 SelectType;
}

template SelectType(bool c : false, T0,T1)
{
    alias T1 SelectType;
}

template SelectAlias(bool c, alias T0,alias T1)
{
    alias T0 SelectAlias;
}

template SelectAlias(bool c : false, alias T0, alias T1)
{
    alias T1 SelectAlias;
}

/*
    typelist manipulation
*/
template Length(_TL : TypeList)
{
    const int Length = 1 + .Length!(_TL.T);
}

template Length(_TL : NullT)
{
    const int Length = 0;
}


template RemoveAll(_TL : TypeList, T)
{
    alias SelectType!(Equal!(_TL.H,T),.RemoveAll!(_TL.T,T),
                                      .Cons!(_TL.H,.RemoveAll!(_TL.T,T))
                     ) RemoveAll;
}

template RemoveAll(_TL : NullT, T)
{
    alias NullT RemoveAll;
}

template RemoveAll(_TL, T : NullT)
{
    alias _TL RemoveAll;
}

template Remove(_TL : TypeList, T)
{
    alias SelectType!(Equal!(_TL.H,T),_TL.T,
                                      .Cons!(_TL.H,.Remove!(_TL.T,T))
                     ) Remove;
}

template Remove(_TL : NullT, T)
{
    alias NullT Remove;
}

template Remove(_TL, T : NullT)
{
    alias _TL Remove;
}

template IndexOf(_TL : NullT, T, int i = 0)
{
    const int IndexOf = -1;
}

template IndexOf(_TL : TypeList, T, int i = 0)
{
    const int IndexOf = .Equal!(_TL.H,T) ? i  : .IndexOf!(_TL.T,T,i + 1);
}

template TypeAt(_TL : NullT, int i)
{
    static assert(0);
}

template TypeAt(_TL : TypeList, int i : 0)
{
    alias _TL.H TypeAt;
}

template TypeAt(_TL : TypeList, int i)
{
    alias .TypeAt!(_TL.T,i - 1) TypeAt;
}

template TypeAtNonStrict(_TL : NullT, int i, _Default = NullT)
{
    alias _Default TypeAtNonStrict;
}

template TypeAtNonStrict(_TL : TypeList, int i : 0, _Default = NullT)
{
    alias _TL.H TypeAtNonStrict;
}

template TypeAtNonStrict(_TL : TypeList, int i, _Default = NullT)
{
    alias .TypeAtNonStrict!(_TL.T,i - 1,_Default) TypeAtNonStrict;
}

template Append(_TL0 : TypeList, _TL1: TypeList)
{
    alias Cons!(_TL0.H,.Append!(_TL0.T,_TL1)) Append;
}

template Append(T: NullT, _T : TypeList)
{
    alias _T Append;
}

template Append(T: NullT, _T : NullT)
{
    alias NullT Append;
}

template NoDups(_TL : TypeList)
{
    alias Cons!(_TL.H,Remove!(.NoDups!(_TL.T),_TL.H)) NoDups;
}

template NoDups(_T : NullT)
{
    alias NullT NoDups;
}

template TypeidPrint(_TL : TypeList)
{
    void TypeidPrint()
    {
        typeid(_TL.H).print();
        .TypeidPrint!(_TL.T)();
    }
}

template TypeidPrint(_T)
{
    void TypeidPrint()
    {
        typeid(_T).print();
    }
}

template TypeidPrint(_TL : NullT)
{
    void TypeidPrint()
    {
    }
}

/*
    and finally a little sanity test
*/
alias TL!(int,float,char,double) tl0;
alias TL!(double,char,float,uint) tl1;
alias Append!(tl0,tl1) tl2;
alias NoDups!(tl2) tl3;

template TypeidPrint(_TL : TypeList)
{
    void TypeidPrint()
    {
        typeid(_TL.H).print();
        .TypeidPrint!(_TL.T)();
    }
}

template TypeidPrint(_T)
{
    void TypeidPrint()
    {
        typeid(_T).print();
    }
}

template TypeidPrint(_TL : NullT)
{
    void TypeidPrint()
    {
    }
}

void main()
{
    static assert(IndexOf!(tl0,char) == 2);
    static assert(IndexOf!(tl0,TypeAt!(tl0,IndexOf!(tl0,char))) == 2);
    static
assert(IndexOf!(tl0,TypeAtNonStrict!(tl0,IndexOf!(tl0,uint),char)) == 2);
    printf("tl0.l == %d\ntl1.l == %d\ntl2.l == %d\ntl3.l = %d\n",
            tl0.Length!(),tl1.Length!(),tl2.Length!(),tl3.Length!());
    printf("types in tl0\n");
    TypeidPrint!(tl0)();
    printf("types in tl1\n");
    TypeidPrint!(tl1)();
    printf("types in tl2\n");
    TypeidPrint!(tl2)();
    printf("types in tl3\n");
    TypeidPrint!(tl3)();
}


begin 666 Thor.zip

M9IDQG N&IJ8!``"^!0``$ ```&-P<"]H86YO:5]C="YC<'"E4TU/ S 8OI/P

M,BN:G ,52IN:LS(-`P\B).3'#F2^*R[D4 UXN5"WJVTL6B!Q+K2Y745A$ :-

M;II:0C2)D [<A,%FVW5ZCNMTG^OL'-?9R-7PLBJ8Z6=KY?!4JS)V_Q8J==E5
M+:1Y+]6:#TNLE<B!?_%L'(X%&T-I](PR>!3ZLPV B%+[2TA7&0E E$47RF-<






M^FAK%/WOH[340;L>&\& ;>KQZ>F1TLDKC^GDY 0N.X25W1*LJ/;"#R5X;MW 
MJ>TBO)7OX.ST] /4`RR-\DBPU' G\F>0:4=!`:15"$)*VSMA" -$)JZMW2XR
MYDG2?,=4P>P79WD#Y\?'\!4#M68!W]& )PD;;ULO^IY,"YRYFX?"EL=&Q,BY
M`9;.:4(UJUZ07<%2*0K6O/^-0>-0E?0-^IY"(&L 6D !YR Y=0Z]5=3PFU.B
MISI%+$L'U!IBWF6P3;P5'J&QGJ>&O1R7O+,! 4$=>F2[6+V)J."68F=3A 9Y


M3 P>G<?P2!#R#E/9ZUY)2!1%39KB`+9YV=M'2RNXB$!A;]U,!/Z?C6RCPWB7
M%PY9(O6E*8 )<QE*X5]Y3"=%P$J$",DI$7$!/Y)!;KQY:;X,>$.-4=C ^FJU


M,_EP__!E.GF83 ZQ8+X..V%:!&W;<ID]K?("\KE!E6_(-<DMGY7DR\722 EG
MU>=/U<<*?B9EP[P`CHZ.#J

MM&O)\9N2YL:-TS9WKB\3R].YF9OI0"0D84(1.I!TXNODO]\N(!*B24007Q39

M?X_T#P][9'1/+J) ,DXN0O:)XF'LI]74SY$:R<C/8A2Q\7 AB<?$%P$CU/?%
M;$XCSF*2 /R1$!\&2%/ [2T$'I"=WZ&7C,CK'WX ERSFDVA ?F41D]PG[Z28
M2#J;\6A"H.?B.E'<\/6.) GTC<G%?!YR%NP<5&AW0"Z" ,<BVO^#Q2

MD'#IWL"9IW(N8D: :,HD`SL!^BAA`?G(DZE($S)F(&<NQ1T/6 #L:*)L1$?B
MCA$_ VXX1B+A/ER?SQF5A$>$AB'2H7%IM. P$LE4'QD.NB/2:- &H]&[Q#Q.
MYW,A$[1V(/QTQJ*$)D!YD#L334
M&8,8-4R5K 9)G/*$CGC(DWLBQM6VS4QZ0-XF8%9CNAT:P^<=PRVS,/N$ F.$
MR&?**0 PQ&%0`]_RZ]MG"L 5C1.2S .:L 'Y1QHQ<#Q

M\UUH!3K-J"]%;-#U

MH_N#O_$(_-?X!08,$H#OT
M2)SLE20O2T4RC#FD[,C;2E[3VQWV]LA  'E^,! N;/%RV//RDYD;O2HP,-HA




M.[4ARZ+,<4O*8'/LJM'S%C12`JUJG;2I%C8GKKH=MZ6;DFI5\+1U!;$Y==7R
MI%4ME6BKJF?=J(K-F:N^I^WKJ^1;E3[O4&ELSETU/^M(\P4(R]3XL&OUD?FA

M \V1JX7Z&[20`F8U4UMSN+708//<U59MS/IJH+,9K-5YXEJ0L#EVM5IK,TL;
MQ$)G&UJK%=N?EM:%B,V)JU7;G=,V FPU;4<3XKHXL3EUM6\'L^E&N*U&[G(J
M7A<L-F>NENYJ'M\(O-7<G2\"ZB+&YMS5YIVN(!II8*VJ;V;Y41<VHCITM7[W
M:Y=&:EB'8%,+GP;8L7%=-1UM8M747!?+8&QJR=54`6SZKB.RB?5:2PI9AF53
MB[U6M,#FR
ML#EV';KM6" W4M4ZE%NVRJZK'S8GKN.Y14OT1OI:!W4;U_=UE<3FU'5DMZTX
MT$AIZ_!N;66AKJ;8G+F.\5:6)1II;AWH[:YIU%47FW/7T=[> D C]:W?*WP$

M77UAZ\M/+5G#XA"/HG;5B FP.7+UBJTO?+5I$HMK/(JJ67MVP.:YJW]L?<FM
M=;M8G.2)U.MLQBAV+ML%&^<_H7D"Q;Y&=K(ZT5.J%-8U#C8GKI[T5,J,K7O2
MDRM/UO4D;$Y=W>E)U38;6<SJ6$^S,%K73-B<N7K7TZNJ-C*;U<6><$FVKJVP
M.7?ULR=:SVUD.^M? C_U8G!= Z$=#ET][BE7DIL94+N=VKAB3GV]"\^WS_[J
M8D\(V++"#VD
MDJGJ<1LSPG&S%BG2R13^9X6M-_3&((KR4D553."=L$ QC0?YUAN_,1J0W3&7


ME::+\Y]?9&*-\PRO])D-N<^5<8778C9/$[V3T\)%E,, =N-B;Z,[X5,</+([


MS'FT=5Y4D3^ >9GA77A?[FSFQ:)T1OXBRL3D)W)(/AO&A6-]Y.3D^"KB(.:N
MX $9<<;3(S]D/&XS3W `L;-MC2I2Y87VXE]X%"A'UTF))H22"0<_(7"!?8)V


M2CR21KCS&PO0;AIJ'A7:4$Y.C?DW\VO,N277SJR>>[;JH6D]<FCS<)/+D9[H
M02KYLRNJA]JNB9*O1HG_X^TE8Z2E<K)/>KF/+;3XBE%Y+:*;1'*_>7C&'<0G
MW6LY1#TB9
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
M<\-$CC#BJ

MC&5+UL'MT:/YTNDED,WJFT*MA) 655QNJ8>M86!=XBF--!D=[]9O[T6RL 'Z

M:!7+E81N[^+-9;=W='QVV.TN7ZL79UM'"9RTPZ^D(__B*G:I#OC+L5?3F78>
MN7X3TF(O]>Z:?Y* 5'XZAF$EIVE-\[,7*E%D.]^*RH:W'TNILY+8AM\]MZTT
MM>\_YI7SP/WN -Z3!/Q3]H3$) I1\-Q9ZYE-/5U=/IEK<NW_9P5]VP5QU<TN


MA)LQ(8\F6%$!``!"`P``!P```&AA;F]I+F2-44U+`S$0O2_L?\ 6A 1BH'BS
MI[8J'JH(!D^"A&ZJP6RR)-.*E/YWDZ:[V?H]L)MA/MZ;-Z.:UCI _,4Z!N^M
MU,K#I
MXBMG&\HM*8MM6:! 'MQZ";DB10_)5"! +='&JAK)C="8I%Q?ENW-*9 K/(HX
MZ$+Y5Q3IT(E'8,/_T8QH%*KJ_1B$ ;V'P/N,21?G=A EDXP?!!V>8VG<">-7
MTG7*Z(,2-&A!!IVC<=8IM!(>\46%>ZE5OPW2PTS^C_\9>]JVTM05[E[6M2:>



M#L


M-3 E27M=061>H^X$W%: SH8A+YQWB/CL\5D54B1:W?=&; 3(M:#YMU
MJ$[3_ABWML^VLV.4+K:+=FX3)%W5&U!+`P04````" !&OI Q7]>U9P$!``#Z
M`0``" ```&AA;F]I+G!L94^Q;H,P%-R1^ =GPD O5:DZM9.3 2QXRH:0925.
MB H8Q5:: 8_O,T\X1?5BO[OSW;V3'4Y*>]OS^C =&Q#YQS9-&)XG<P0E< A/
M%4#M^0$1E+ZD29K\<1#TGVUFXN
M 7,.LU4W\ 7X)(\(DY[Z8+X=^?LK/"X/\)9 ;[F 70Q?5ZNSRMX-.[?NFUUN
MMF<9",B8M_C8-63PI0?;! ]04$ M`ON?VX.$X.5RMD1)B:LRN2V YD6\1[E$

M\U]02P,$" ``````BXZ;,0````````````````4```!4:&]R+U!+`P04````

MG+#B5\#H!N("15= 3)P7Z'0NT-!IQ[:#CL9WMT
M)"MMT,,4<W*L,'II6)X+M<1,I(:9*K0V9*S0"I]D=$B:O(7KP>"FYS^WF$A:

M.9;EPK!4$E*MUVC,=49&X:'3P92L6*H&_ 1F>BT  _0>6>')"+*D=BR_8:'M



M13<<3 N&N<O, ^*!C9/PX3'\!U!+`P04````" `JCYLQ*%BJIX<"```8!P``


MD 92IB5JR&L$2U#KI::UAHS*2BID2.O%>.1XTL*:>&E 7:!/YY[L_BN).5!M
MC701> );R%9]!F0+Y+4TZ.DYH='O+)Q'D5.<CD? OJ0 AF.8PSU:43$M6)2E

M,H,YE4+J$&J+"NU6LB"P=!Y"5SIGE%[HE_!#D]7.UA,QB+R4+%*%D!(MX>">
M<F0--T=',$<C%_H`' /N:"E!!=.=Y :^L$2#NM6JF"HR+6[FFBFS`D1F:Z'4
M!BI)&I$QAQ*M..[W0VJ8CT?3T_$H-'?;N9.PFQ=^Q17+E; X'OT)Y659$=L`



M-Z17R-;?Q(2Z>"8T/$**D(4TYF )DD_M&]"J[ I$CW$`^!+A"YNT ^LV/<">
MAW5]\]ZL;;GNI/WKU.M:>WLFKA, P_BBG^_.=4"TLSZF.W(!TDP<HH_YALH%
M_=9,HJ I%,]ZA\639SNHIE \"P/L<$D< ZG35P_)K2Z0_=Y>"X/=79G!32%5
M/G!W&BI<-N=CLA6)3W9Z.HFV8C$<'L(D(-O0+K11\"[_`E!+`P04````" #D
MHIDQ#B=K`JL$``#H(P``#P```%1H;W(O='EP96QI<W0N9,U774_C.!1]1^(_
M7.:I&=*0E,\!C58=NBM6ZK"C';^/3&**11IG$Z<[[(K_OC=VTM*4?)2Z98M,
MJ7WON><<1]7AZ./^'N"+/( $^C""KTS2.!&3A$ZG/)K F-\E-'G253.6I%Q$
M\ ]+A-[I^18,7/>DC[].81BRQY0]P1=Q%['9_IZN^9;=A=R'D9A2'NFM<BB-
M'E.8")#B4F

MDK&$!3!%._HO_> 1C/;W/A[M[TU%D(5,.>?(IYB%/)57N>8XX3,JV?[>OYH`

M11/YT+/TMD+1+U]$J43.LBB!S^ 6S<\%BRK(#S*&RSDG2Y&J ?+ $!S]Z2#O



MRCJ 3N6.X!?L0BRG*)D;;G,X!,^J4E!#AW))DYZ]F)M**KD/-$U9(GMN"T:I


MFW]E:(SB,['S5LLJD.L&DO)&<1+4#L+#M7!>]4IMUN+<BE$6I_H:VO6BW/(+
MTM&=A?&6K4XMJP"LF]/"LJ9;$>/!MX1'LI;J3/! J7 UB$AUJH583JRKKA;G
MSHOV4MB\X+F9U-N(%"RZ#EG$E_9IY:QEX")JJRN52>9+Q07RV CWB9C"`Z.!

M-ZB"J*I]<5SQKGQ<%!CFTNJ^1B^S:4,^K:!V"9?DY;/R7+FP5:GE71F3G*,X
M-W6B'6).]ERR0EY/=B&W5/__OMX.RLBX1]R*"MQLTA"K_S4OJ^2)NZI(F63P
MYAH4'1T!S:3H3UC$$L0/((M!"ABX$-.$3IED25H5;A-O>]H=,C[HX0!S\ <U
M\E=5V62P=6$XPZ"VXW6TV>1X%_)PC$&%)VLJM,G)CD3B)(,Z3]?7:9/3W4G%
M80;5GKU)K4W.=BH8YQG4?/Y6S38YW[5L'&E0^<4&RFUR\0[B<:I!_9\VTV^3



MO5^J[TC09/H?U*3__P!02P$"% `*``````"=CILQ````````````````! ``
M`````````! `````````8W!P+U!+`0(4`!0````(`)IFF3&>"X:FI $``+X%
M```0````````````( ```"(```!C<' O:&%N;VE?8W0N8W!P4$L!`A0`% ``
M`` `R+K4*A,8^JI ` ``.08```X```````````` ````] $``&-P<"].=6QL

M````  0``&-P<"]4>7!E3&ES="YH4$L!`A0`% ```` `R+K4*IFQI(4\! ``
M;A ```\```````````` ````W!(``&-P<"]4>7!E36%N:7 N:%!+`0(4`!0`

M4$L!`A0`% ```` `+;^8,3,.J<'-````XP$```D```````````` ````NQH`

M````( ```*\;``!H86YO:2YP;%!+`0(4``H``````(N.FS$`````````````
M```%````````````$ ```-8<``!4:&]R+U!+`0(4`!0````(`#R5F3%W%P8W

M```(`"J/FS$H6*JGAP(``! '```-````````````( ```'P>``!4:&]R+W1R
M86ET<RYD4$L!`A0`% ```` `Y**9,0XG:P*K! ``Z",```\```````````` 

`
end
Dec 28 2004