digitalmars.D - "Modern D Design" :))
- Aleksey Bobnev (660/660) Dec 27 2004 Yesterday I tried to get back to idea of using D templates for
- Walter (10/21) Dec 27 2004 specialization
- Ivan Senji (47/57) Dec 30 2004 ...
- Walter (54/56) Jan 29 2005 is
-
Ivan Senji
(9/31)
Jan 30 2005
- Walter (4/10) Jan 30 2005 So did I at first. That's a compiler bug, and I fixed it (will appear in
- Zz (58/58) Dec 27 2004 I could not resist.
- Norbert Nemec (5/6) Jan 07 2005 I know this is drifting off-topic, but still: what is "Open Dylan"? I kn...
- M (2/662) Dec 28 2004
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 M"GHK*_Z4&]021,;)5 5- 6\Y-FKE'Z^$V 6J-3UY!2Y.N:H]38H#U*YF?#W- M9 Z< ]OS%TI0D_,QIHV<K O3K4P?BP_9I"'3U6TJ7'+;W%29NF MY]GO?J_) MY/[ B_KO:GYJA/Z.S0!7*DK*WE=:GES,(9$%ZHH^S$(68FTYH!.1%436BW_& ML4\E3T *1JS)"573B *2*572M-BQ"$/QD06XZ!ZBV#Q![&<+<Q9T8<JU$X+6 M<X7//Z VX:_4<KLW(663.<30#F*X4GIA-]>]MF[^1JP56E70$P>X%=W:0IT? MV^ [9"HWV(:H:L*:2=.83(2]*G7[LN9=A%$Y([V1-&9X01_I"8&N\0K?3R6+ M7LZG(& Y1ILF+]?IRPJD?0O2TN3&"3)2-J_(Y 8OPSVJAKNI[*&$.22/K[F. MKP*=227UC_2>!.)CI#ZH091L)NZR1T>HP(J*00:C%%%5RK8RV2 KCITWJ'N- M? -PMSSE7(O+=!YR'XYUI?0]&F.1=X+LDE(+GWW4>J19$%+**U^CT)&E P(R MQT5-49NV%C0U5Q%E0&Y+B'+5P![K1?[(SP3[5>^%2Z)X>=7SE")+/?OELH-+ MW0%7Z1;O"C#O>)LE +9F]NN 1B8U )N^*VZQF4"4H 5LZ4U6`\UF]ME'?8\U M'T.ZN6-25Q^SX[C&Q-WTULEBS4* 5'V_RF,+$_L:0\W'E[GZ#QX';,WC`X.O M%):7+%WW=F-8K/NTNJU;C$=<P+7QU912 "[Q+]>47],HX %P<:P9&;8W+&1^ M4G%GN[E]]^;]S>W/KZ\N;FYV<P'ZEK9GF0YJ?3/B[?CRV\)H0_&+%)$.I LI M:311=:G*TBV)A0JI<D!I8OU3UU ;6FNV6$2B ]P>X9()"6)!J"+LY+F\ZSRQ MB'Q%Z! WK^[>6DVXC2EB$5H7U>%2X!8GA>5 &DY9*5F6V%N*/*NXE:K,:Q>9 M'_*[<EK:?M:/F8I_BU8ZB7_=V%E:>#W%F">AF*AHU+^O?GBN?U]]`'?^3V24 M3M0WVJD$2 F3^O&7&)=^Q+Q_1!*Q]/%4<52O71]"ED/&2!G27-([4);>AT+N M(;B&7!8(+,]E53/!48.AP'TIKU-KL^"4A$ =V#TG+R7 ^.E3.$'-AR*%GU" MXCE<*#E4K*JX& )YAGEPT>SG AE#OAH.Z[KD6.QV[H'= <.BX%J*9Q]1ESCI M./<+5!77FDL!1D*C,8&<7!.H9,$'])]<C.+]QJ!;6F-9 K&[U') ;IA"&$A% M(?.F0F&8(<O.K$I80_M00'\QIZ7&"96/&%9,0,6ND0*#PIIXG ;0=H>-VVM$ MHAMN6)^7W$Q #M;D-J2T`Z<&N(ZIVV6:ON_&:-,,XZU=6%N(O')%`130TN"( M_\*?[2T'X(QI`TU=,(,I_-P(I,)+7/%9 ^_X0!0X .S7BS?GAQ].+ZY./QQ? MT3 -<H'+X^0A6(6Z9KD_EMM;=YM 3KCSDFD-!BE1!!U.A=G/)C6&\R_&J(P& M0O 2GQE>88PX7</%.7&YT?!XS,H&'R? !*!H*E_H:$>9H7D",=Y$=K:W`""F M"A/ZJGG-B_NXC+$.LBF7F><R6$?&S A]^%](BKA I74C'T[+5JS6T&?YM>4M MVT0:EGFS2.QQ FR1/ OJ?O:LASNN"QOX3QCL8HFYL3/A48,4Z-3R1CJ -IL: M-9H>,(4>E1MU<9?.: 9\, M-3&#B>Y0D;VEH]1NN<4-"O5 8=B/ \Q!K9.ZY MMU O 8JUQ1)V&\MD:;D'KT'DL%)C8&?M KVPX->IRW=8UJA"Q74K5I:.MB,^ MO0SFLVE06/J[XHC;'H'F!E%$G5M2, VM%=%I>^%B[;E5#X+&X2W7Q =1:!IE M`S SE3:PTM9V>F3UR>H0.NT3_A*9<S,/=:!DY;N7%ZX6WC(RPQ1.D*H/G9X= M,8UM9]-?#VC_(YO\(U!,H;_O1SAZ!0_EQ8_UO.1&?%P8&O*%2%:N%7N0^7T M-:O0-K\'0 R,Q,N_XYB"Q/NAOXJP,3*30C7]J0(W4EW[")%3;AM:[4\S?:'M 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
"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++specializationis 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 languagehasa Bright(sorry for a pun) future in area of meta-programming. Possiblywithsome more improvements to template facility it will beat C++ completelysomeday.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
"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 withbysome more improvements to template facility it will beat C++ completelysomeday.What do you think it needs? Also, what in particular are you thinking ofsaying that C++ specialization is much more powerful? D's is equivalent,ifnot 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
"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) hereisour 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
"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
"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
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
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
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 M"GHK*_Z4&]021,;)5 5- 6\Y-FKE'Z^$V 6J-3UY!2Y.N:H]38H#U*YF?#W- M9 Z< ]OS%TI0D_,QIHV<K O3K4P?BP_9I"'3U6TJ7'+;W%29NF MY]GO?J_) MY/[ B_KO:GYJA/Z.S0!7*DK*WE=:GES,(9$%ZHH^S$(68FTYH!.1%436BW_& ML4\E3T *1JS)"573B *2*572M-BQ"$/QD06XZ!ZBV#Q![&<+<Q9T8<JU$X+6 M<X7//Z VX:_4<KLW(663.<30#F*X4GIA-]>]MF[^1JP56E70$P>X%=W:0IT? MV^ [9"HWV(:H:L*:2=.83(2]*G7[LN9=A%$Y([V1-&9X01_I"8&N\0K?3R6+ M7LZG(& Y1ILF+]?IRPJD?0O2TN3&"3)2-J_(Y 8OPSVJAKNI[*&$.22/K[F. MKP*=227UC_2>!.)CI#ZH091L)NZR1T>HP(J*00:C%%%5RK8RV2 KCITWJ'N- M? -PMSSE7(O+=!YR'XYUI?0]&F.1=X+LDE(+GWW4>J19$%+**U^CT)&E P(R MQT5-49NV%C0U5Q%E0&Y+B'+5P![K1?[(SP3[5>^%2Z)X>=7SE")+/?OELH-+ MW0%7Z1;O"C#O>)LE +9F]NN 1B8U )N^*VZQF4"4H 5LZ4U6`\UF]ME'?8\U M'T.ZN6-25Q^SX[C&Q-WTULEBS4* 5'V_RF,+$_L:0\W'E[GZ#QX';,WC`X.O M%):7+%WW=F-8K/NTNJU;C$=<P+7QU912 "[Q+]>47],HX %P<:P9&;8W+&1^ M4G%GN[E]]^;]S>W/KZ\N;FYV<P'ZEK9GF0YJ?3/B[?CRV\)H0_&+%)$.I LI M:311=:G*TBV)A0JI<D!I8OU3UU ;6FNV6$2B ]P>X9()"6)!J"+LY+F\ZSRQ MB'Q%Z! WK^[>6DVXC2EB$5H7U>%2X!8GA>5 &DY9*5F6V%N*/*NXE:K,:Q>9 M'_*[<EK:?M:/F8I_BU8ZB7_=V%E:>#W%F">AF*AHU+^O?GBN?U]]`'?^3V24 M3M0WVJD$2 F3^O&7&)=^Q+Q_1!*Q]/%4<52O71]"ED/&2!G27-([4);>AT+N M(;B&7!8(+,]E53/!48.AP'TIKU-KL^"4A$ =V#TG+R7 ^.E3.$'-AR*%GU" MXCE<*#E4K*JX& )YAGEPT>SG AE#OAH.Z[KD6.QV[H'= <.BX%J*9Q]1ESCI M./<+5!77FDL!1D*C,8&<7!.H9,$'])]<C.+]QJ!;6F-9 K&[U') ;IA"&$A% M(?.F0F&8(<O.K$I80_M00'\QIZ7&"96/&%9,0,6ND0*#PIIXG ;0=H>-VVM$ MHAMN6)^7W$Q #M;D-J2T`Z<&N(ZIVV6:ON_&:-,,XZU=6%N(O')%`130TN"( M_\*?[2T'X(QI`TU=,(,I_-P(I,)+7/%9 ^_X0!0X .S7BS?GAQ].+ZY./QQ? MT3 -<H'+X^0A6(6Z9KD_EMM;=YM 3KCSDFD-!BE1!!U.A=G/)C6&\R_&J(P& M0O 2GQE>88PX7</%.7&YT?!XS,H&'R? !*!H*E_H:$>9H7D",=Y$=K:W`""F M"A/ZJGG-B_NXC+$.LBF7F><R6$?&S A]^%](BKA I74C'T[+5JS6T&?YM>4M MVT0:EGFS2.QQ FR1/ OJ?O:LASNN"QOX3QCL8HFYL3/A48,4Z-3R1CJ -IL: M-9H>,(4>E1MU<9?.: 9\, M-3&#B>Y0D;VEH]1NN<4-"O5 8=B/ \Q!K9.ZY MMU O 8JUQ1)V&\MD:;D'KT'DL%)C8&?M KVPX->IRW=8UJA"Q74K5I:.MB,^ MO0SFLVE06/J[XHC;'H'F!E%$G5M2, VM%=%I>^%B[;E5#X+&X2W7Q =1:!IE M`S SE3:PTM9V>F3UR>H0.NT3_A*9<S,/=:!DY;N7%ZX6WC(RPQ1.D*H/G9X= M,8UM9]-?#VC_(YO\(U!,H;_O1SAZ!0_EQ8_UO.1&?%P8&O*%2%:N%7N0^7T M-:O0-K\'0 R,Q,N_XYB"Q/NAOXJP,3*30C7]J0(W4EW[")%3;AM:[4\S?:'M 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