On Fri, Jul 19, 2002 at 11:28:04AM +0100, Mark Fowler wrote:
> I think commify would probably be better implemented as a filter plugin.  
> In terms of I18N the way commify acts should probably be different for
> different languages and countries.

Perhaps, yes. 

> Is it easy to add virtual methods with a plugin?  I haven't really given 
> it much thought. 

Trivial.  Just add them to $Template::Stash::XXXX_OPS->{ name };

> What are the actual drawbacks to adding more virtual methods in terms of 
> bloat.

More memory, more time for Perl to parse and load the Stash modules.  
It's not very much for any one virtual method, but they all add up.
But they're still a drop in the ocean compared to the rest of TT.
The Template::Grammar module is 95k, for example (which is why the 
much smaller, hand-crafted recursive descent parser for v3 will be 
a big win) so it's relatively harmless.  

Moore's Law helps, of course.  The average computer speed has probably 
increased by a few percent since we last added any virtual methods :-)

So for anything that's generally useful, and not too large, I generally
think the added convenience is worth a small bit of code bloat.
The functionality and documentation bloat is also worth considering.
Maybe virtual methods now warrant their own manual page?

>  b) Do we risk name clashes with blessed objects.  For example, does
>     my number class that has it's own "commify" operator risk having
>     that overridden by the virtual method?

No, object methods always win.  

But, namespace collision can be a problem.

In fact, one of the gnarliest problems I/we really need to solve for v3 
is a reliable and easy way to:

  * specify at startup which virtual methods should be enabled/disabled

  * add new virtual methods, remove or hide existing ones on the fly,
    even from within templates (if the right "let the meddle" flag is
    set)

  * define some syntax or convention to indicate when you really want 
    a virtual method, and when you really don't.

That last point is the hard one.  I got burnt by this when I added the
'size' virtual method to hashes (and then promptly took it away again).

I hade some code which said:

  <font[% IF font.size %] size="[% font.size %]"[% END %]...etc...>

and suddenly, in the many cases where font.size had previously been 
undefined, it now magically returned a value and messed up all my 
output.

So, being able to disable the 'size' hash virtual method, either
for all templates, a single template, or within a lexical block,
is one solution, but a bit clumsy.

Some syntax solutions I've considered include:

  * using a tt_ prefix to say "I really, really want the TT virtual 
    method", e.g. [% hash.tt_size %]

  * using {key} or maybe 'key' to say "I really want the hash key, or
    object method, no TT magic, thank you very much", e.g. 
    [% hash.{size} %] or [% hash{size} %] or [% hash.'size' %]
    The first two are starting to look a bit Perlish, the second
    doesn't seem obvious enough to me as to what it's doing.  And 
    they're both confusing when it comes to object methods.

  * forget about it, and have people do [% hash.item('size') %] when
    they really want a hash item, but that's not very helpful, and 
    leads to problems as I discovered.

  * make all virtual methods UPPER CASE.  Doesn't solve the problem
    but may avoid conflicts if you warn people that UPPER CASE keys
    might clash with reserver words, e.g. [% hash.SIZE %] vs
    [% hash.size %].  Maybe too much shouting.  My little fingers 
    already hurt from the shift key.

  * use a separator other than '.', e.g. [% hash!size %] or 
    [% hash:size %] or [% hash(size) %] or something else.

Another partial solution is to expose the stash virtual methods
themselves.  This will, I think, be the preferred approach to 
call a virtual method, when you really, really want to call a 
virtual method:

    [% tt.hash.size(myhash) %]

Maybe then we could define oodles of virtual methods that can be 
called directly this way, but restrict the number that are "exported"
and applied automagically to a hash.  So, by not exporting tt.hash.size,
we can safely do this:

   [% IF myhash.size %]

and know that it will only look for the 'size' key in the hash (or 
size() method of an object.  But we can still use the virtual method
explicitly if we want to:

   [% tt.hash.size(myhash) %]

Any other suggestions?

A



Reply via email to