<?xml version="1.0" encoding="windows-1252"?>
<node id="33029" title="Speeding-up OO accessor methods" created="2000-09-18 21:03:59" updated="2005-08-15 09:27:44">
<type id="115">
perlquestion</type>
<author id="9346">
mirod</author>
<data>
<field name="doctext">
&lt;p&gt;This is half a question (how can this technique be improved?) 
and half craft (but with too many comments to fit in the 
craft mold!)&lt;/p&gt;

&lt;p&gt;I thought you might one day need this crude-but-efficient
   (albeit dangerous) technique to speed-up OO modules
   without compromising the cleaness of the code.&lt;/p&gt;
&lt;p&gt;I usually define accessor methods to every attribute
   of my objects, even those which are implemented as simple
   hash fields. Thus I have usually a &lt;tt&gt;field&lt;/tt&gt; and a
   &lt;tt&gt;set_field&lt;/tt&gt; method for each field. I use those 
   accessor methods even within the module, just in case
   one day I change the implementation and I move the 
   attribute from a simple field to... something else.&lt;/p&gt;
&lt;p&gt;Then in order to get back the speed lost in those
   method calls, when I install the module I pre-process it
   and replace the methods by hash access through a simple
   script:&lt;/p&gt;
&lt;code&gt;#!/bin/perl -p

# basic substitution

# processing the field method is easy
s/((\$\w+)-&gt;field\b/$1\-&gt;\{field\}/g;
# the set_field method has an argument, capture it
s/s/(\$\w+)-&gt;set_field\(([^)]*)\)/$1\-&gt;\{field\}= $2/g
&lt;/code&gt;
&lt;p&gt;The actual code I use is improved to process several fields at once,
   to allow the object 
   to be an array element (hash element is left as an
   exercice for the reader), and to perform the replacement
   only if no other argument is passed to the &lt;tt&gt;field&lt;/tt&gt;
   method:&lt;/p&gt;

&lt;code&gt;#!/bin/perl -p
BEGIN { $FIELD="field1|field2|field3"; }
s/(\$\w+(?:\[\d\])?)-&gt;($FIELD)\b(?!\()/$1\-&gt;\{$2\}/g;
s/(\$\w+(?:\[\d\])?)-&gt;set_($FIELD)\(([^)]*)\)/$1\-&gt;\{$2\}= $3/g;&lt;/code&gt;

&lt;p&gt;Then I just add a &lt;tt&gt;depend&lt;/tt&gt; item in Makefile.PL&lt;/tt&gt;;&lt;/p&gt; 
&lt;code&gt;    'depend' =&gt; { 'oo.pm' =&gt; "oo.pm.slow\n\tperl speedup oo.pm.slow &gt; oo.pm\n"},&lt;/code&gt;
&lt;p&gt;Where &lt;tt&gt;oo.pm.slow&lt;/tt&gt; is the code I edit and maintain
   while &lt;tt&gt;oo.pm&lt;/tt&gt; is the module that gets installed.&lt;/p&gt;
&lt;p&gt;One caveat is that you can't use parenthesis in an argument
   to the set_field method, although this could be fixed
   using the latest regexp extensions.&lt;/p&gt;
&lt;p&gt;Once that script is written you can also use it to speedup
   scripts that use the module, with the important drawback
   that when the implementation changes you will have to re-run
   the speedup script on all such scripts.&lt;/p&gt;</field>
</data>
</node>
