For a little background... I had a module that was a simple TT style variable replacer. All it could handle were things like [% a %] or [% a.0 %] or [% a.a.0 %]. It didn't allow for argument passing, or directives, or operators. All it did was variables. The perldoc made clear the limitations and said to use Template::Toolkit if anything more complicated was desired.
Years went on. I decided it would be useful to have basic IF directive support as well as allowing for argument passed to functions (such as [% a(b) %]). I added these features, played around with things, toyed with tag parsing methods. At first there was no optree - the finished document was built as the parse progressed. But then I discovered that blocks and meta tags can be out of order in the document. It became easier to build an optree. It was relatively easy. It was only 1800 lines and took about 80 hours to write. I then tried it against the TT 2.14 test suite. It took another 20 hours to make it pass the rest of the TT test suite. I was done mostly around late January 2006 - but I've been waiting for the anticipated 2.15 release so I could make sure that the new module is fully compliant with any of the bug fixes that have gone into TT. I'm still waiting - but I'm getting to the point I'd like to release the code. So the first big question: Is there room for two engines that implement the Template Toolkit specification? Obviously there are pros and cons to releasing another module that does the same thing that Template::Toolkit does. Next question. If I do release it - should I go to lengths to support all of the extended options that TT uses? For example, there is no support for V1DOLLAR and there won't be. I've also removed support for the ANYCASE option (Increased the overall string parsing from 339% listed in the example below to 359%. That isn't a major increase. And removing ANYCASE has no effect on compiled templates at all.) Some other options to consider removing in CET: - Direct access to blocks located in other templates. - "References" - PERL and RAWPERL blocks (CET doesn't use perl for execution) I'd still leave the eval_perl option though. The big things missing that won't be implemented are TT2 views, and I may or may not include the new magic TT3 provider namespaces such as "hash:" or "file:" (etc). Whether I release a separate module or not, the TT dev team (mostly Andy) will be welcome to cut out what ever portions of code they may find useful. The CET code base is somewhat different from TT in that TT uses a separate object for each phase of execution while CET uses a separate method. This makes CET either easier or harder to override functionality depending upon which programming camp you come from. Finally - Is releasing this premature? Will TT3's speed increase? Is increasing the speed a factor for anybody else? Does anybody even care if there is another module? I apologize that this letter doesn't include the source code. I'd rather wait until I can see the general feelings of people on the matter. I'm sure there will be split feelings either way. If you have something scathing to say in response, you are certainly welcome to. But please decide if it is appropriate for the entire list to hear. Otherwise just email me directly. Paul Seamons ///----------------------------------------------------------------/// The following three files will be sent as follow-ups to this email (the first time I tried I put them all in the same email and it exceeded the mailing list max). 7_template_00_base.t - The file used to test most of the language constructs of CGI::Ex::Template. If you uncomment the line that says $module = 'Template' it will use Template instead. It is useful for finding edge cases. bench_template.pl - Used to test relative performance. All benchmarks should be taken with a grain of salt. The output of the run on my machine is listed below. The output varies depending upon memory, disk and processor speed. perldoc - This is perldoc CGI::Ex::Template > perldoc - It is the unfinished perldoc for CGI::Ex::Template. Did I mention that it is unfinished. ///----------------------------------------------------------------/// The following results are the output of the bench_template.pl script included in the email. The computer used is a 1.86 Pentium M with 1 Gig of ram running Breezy Kubuntu. All percentages are CGI::Ex::Template vs TT2.14. The first column shows the "template" that is being processed. The second column is both engines using compiled templates that are already in memory. For the third column the engines use a new object each time. In the fourth column the engine is using file side caches (CACHE_EXT is set) (it needs to load a new object each time). The fifth column is passing the template as a scalar ref rather than loading from file. The last column is the number of iterations per second of CET running in memory (iterations used for determining the first column). Copying and pasting this into a fixed width display will make things line up a little better. ### All percents are CGI::Ex::Template vs TT2 ### (The percent that CET is faster than TT) Existing object by string ref # New object with CACHE_EXT set # # New object each time # # # This percent is compiled in memory (repeated calls) # # # # "", # 236% # 645% # 337% # 457% # 19787.6/s # "[% one %]", # 168% # 592% # 421% # 476% # 14355.1/s # "[% one %]"x100, # 31% # 341% # 79% # 348% # 940.2/s # "[% SET one = 2 %]", # 161% # 534% # 419% # 406% # 14121.9/s # "[% SET one = 2 %]"x100, # 12% # 279% # 37% # 276% # 864.5/s # "[% SET one = [0..30] %]", # 42% # 320% # 247% # 211% # 7518.1/s # "[% hash.a %]", # 173% # 619% # 423% # 494% # 13334.4/s # "".((" "x100)."[% one %]\n")x10, # 82% # 517% # 261% # 476% # 5848.1/s # "".((" "x10)."[% one %]\n")x100, # 23% # 432% # 116% # 422% # 867.7/s # "".("[% \"".(" "x100)."\$one\" %]\n")x10, # -15% # 1415% # 102% # 1467% # 2700.5/s # "".("[% \"".(" "x10)."\$one\" %]\n")x100, # -50% # 299% # 2% # 302% # 329.3/s # "[% 2 %]", # 177% # 602% # 459% # 459% # 15838.0/s # "[% 1 + 2 %]", # 87% # 435% # 334% # 299% # 10746.9/s # "[% 1 + 2 + 3 + 5 + 6 + 8 %]", # 67% # 320% # 301% # 218% # 9570.1/s # "[% c.d.0.hee.0 %]", # 171% # 616% # 416% # 527% # 13717.7/s # "[% SET c.d.0.hee.0 = 2 %]", # 156% # 519% # 364% # 413% # 10628.0/s # "[% c.d.0.hee.0 %]"x100, # 54% # 464% # 82% # 467% # 752.8/s # "[% SET c.d.0.hee.0 = 2 %]"x100, # 107% # 341% # 91% # 341% # 342.0/s # "[% t = 1 || 0 ? 0 : 1 || 2 ? 2 : 3 %][% t %]", # 73% # 291% # 256% # 210% # 8674.9/s # "[% a=1 %][% IF a %]Two[% END %]", # 126% # 481% # 347% # 378% # 11166.3/s # " [% IF a %]Two[% END %]", # 161% # 596% # 412% # 492% # 13846.3/s # "[% IF a %]A[% ELSE %]B[% END %]", # 141% # 526% # 378% # 422% # 12728.4/s # "[% IF a %]A[% ELSIF b %]B[% ELSE %]C[% END %]", # 131% # 519% # 359% # 407% # 11386.8/s # "[% FOREACH i = [0..10] ; i ; END %]", # 16% # 230% # 154% # 155% # 2376.1/s # "[% FOREACH i = [0..100] ; i ; END %]", # -15% # 38% # 13% # 18% # 362.5/s # "[% FOREACH [0..10] ; i ; END %]", # 23% # 245% # 162% # 169% # 2463.0/s # "[% FOREACH [0..100] ; i ; END %]", # -4% # 56% # 28% # 32% # 384.9/s # "[% f = 10 %][%WHILE f%][%f=f- 1%][%f%][% END %]", # -14% # 152% # 50% # 102% # 1279.5/s # "[% f = 10; WHILE (g=f) ; f = f - 1 ; f ; END %]", # -18% # 115% # 34% # 75% # 1014.6/s # "[% f = 1; WHILE (g=f) ; f = f - 1 ; f ; END %]", # 38% # 302% # 193% # 223% # 5061.4/s # "[% PROCESS bar.tt %]", # 236% # 592% # 397% # 506% # 10189.6/s # "[% INCLUDE baz.tt %]", # 157% # 427% # 296% # 370% # 6549.1/s # "[% BLOCK foo %]Hi[% END %][% PROCESS foo %]", # 162% # 592% # 422% # 487% # 10030.6/s # "[% BLOCK foo %]Hi[% END %][% INCLUDE foo %]", # 140% # 557% # 387% # 462% # 8555.5/s # "[% MACRO foo BLOCK %]Hi[% END %][% foo %]", # 79% # 413% # 301% # 309% # 7363.9/s # "[% MACRO foo(n) BLOCK %]Hi[%n%][%END%][%foo(2)%]", # 65% # 296% # 265% # 219% # 6081.4/s # "[% MACRO foo PROCESS bar;BLOCK bar%]7[%END;foo%]", # 96% # 449% # 316% # 355% # 5962.3/s # "[% n = 1 %][% n | repeat(2) %]", # 128% # 432% # 370% # 336% # 9705.7/s # "[% n = 1 %][% n FILTER repeat(2) %]", # 91% # 367% # 325% # 256% # 8025.8/s # "[% n=1; n FILTER echo=repeat(2); n FILTER echo%]", # 36% # 317% # 241% # 243% # 5321.4/s # "[% constants.simple %]", # 176% # 617% # 473% # 448% # 15760.8/s # "[%one='ONE'%][% PERL %]print \"[%one%]\"[%END%]", # 66% # 447% # 300% # 357% # 6472.9/s # "[% 'hi' | \$filt %]", # 97% # 517% # 348% # 400% # 9500.9/s # "[% ' ' | uri %]", # 127% # 620% # 402% # 505% # 11498.0/s # "[% foo | eval %]", # 326% # 600% # 498% # 517% # 5022.9/s # "[% b = \\code(1); b(2) %]", # 60% # 270% # 239% # 174% # 6451.9/s # "[% foo = BLOCK %]Hi[% END %][% foo %]", # 105% # 438% # 312% # 326% # 9962.1/s # "$longer_template", # 51% # 305% # 139% # 264% # 1098.6/s # # overall # 94% # 439% # 268% # 359% # # overall (with Stash::XS) # 27% # 371% # 212% # 307% # # Note that TT is faster on for loops and while loops. The opcode tree method of CET can't outperform the low level loops in perl. _______________________________________________ templates mailing list templates@template-toolkit.org http://lists.template-toolkit.org/mailman/listinfo/templates