title: Perl OOP attribute manipulation best practice
body: <p>Assume the following code:</p>
  
  <pre><code>package Thing;
  sub new {
      my $this=shift;
      bless {@_},$this;
  }
  sub name {
      my $this=shift;
      if (@_) {
          $this-&gt;{_name}=shift;
      }
      return $this-&gt;{_name};
  }
  </code></pre>
  
  <p>Now assume we've instantiated an object thusly:</p>
  
  <pre><code>my $o=Thing-&gt;new();
  $o-&gt;name('Harold');
  </code></pre>
  
  <p>Good enough.  We could also instantiate the same thing more quickly with either of the following:</p>
  
  <pre><code>my $o=Thing-&gt;new(_name=&gt;'Harold');  # poor form
  my $o=Thing-&gt;new()-&gt;name('Harold');
  </code></pre>
  
  <p>To be sure, I allowed attributes to be passed in the constructor to allow "friendly" classes to create objects more completely.  It could also allow for a clone-type operator with the following code:</p>
  
  <pre><code>my $o=Thing-&gt;new(%$otherthing);  # will clone attrs if not deeper than 1 level
  </code></pre>
  
  <p>This is all well and good.  I understand the need for hiding attributes behind methods to allow for validation, etc.</p>
  
  <pre><code>$o-&gt;name;  # returns 'Harold'
  $o-&gt;name('Fred'); # sets name to 'Fred' and returns 'Fred'
  </code></pre>
  
  <p>But what this doesn't allow is easy manipulation of the attribute based on itself, such as:</p>
  
  <pre><code>$o-&gt;{_name}=~s/old/ry/;  # name is now 'Harry', but this "exposes" the attribute
  </code></pre>
  
  <p>One alternative is to do the following:</p>
  
  <pre><code># Cumbersome, not syntactically sweet
  my $n=$o-&gt;name;
  $n=~s/old/ry/;
  $o-&gt;name($n);
  </code></pre>
  
  <p>Another potential is the following method:</p>
  
  <pre><code>sub Name :lvalue {  # note the capital 'N', not the same as name
      my $this=shift;
      return $this-&gt;{_name};
  }
  </code></pre>
  
  <p>Now I can do the following:</p>
  
  <pre><code>$o-&gt;Name=~s/old/ry/;
  </code></pre>
  
  <p>So my question is this... is the above "kosher"?  Or is it bad form to expose the attribute that way?  I mean, doing that takes away any validation that might be found in the 'name' method.  For example, if the 'name' method enforced a capital first letter and lowercase letters thereafter, the 'Name' (capital 'N') bypasses that and forces the user of the class to police herself in the use of it.</p>
  
  <p>So, if the 'Name' lvalue method isn't exactly "kosher" are there any established ways to do such things?</p>
  
  <p>I have considered (but get dizzy considering) things like tied scalars as attributes.  To be sure, it may be the way to go.</p>
  
  <p>Also, are there perhaps overloads that may help?</p>
  
  <p>Or should I create replacement methods in the vein of (if it would even work):</p>
  
  <pre><code>sub replace_name {
      my $this=shift;
      my $repl=shift;
      my $new=shift;
      $this-&gt;{_name}=~s/$repl/$new/;
  }
  ...
  $o-&gt;replace_name(qr/old/,'ry');
  </code></pre>
  
  <p>Thanks in advance... and note, I am not very experienced in Perl's brand of OOP, even though I am fairly well-versed in OOP itself.</p>
  
  <p><strong>Additional info:</strong>
  I guess I could get really creative with my interface... here's an idea I tinkered with, but I guess it shows that there really are no bounds:</p>
  
  <pre><code>sub name {
      my $this=shift;
      if (@_) {
          my $first=shift;
          if (ref($first) eq 'Regexp') {
              my $second=shift;
              $this-&gt;{_name}=~s/$first/$second/;
          }
          else {
              $this-&gt;{_name}=$first;
          }
      }
      return $this-&gt;{_name};
  }
  </code></pre>
  
  <p>Now, I can either set the name attribute with</p>
  
  <pre><code>$o-&gt;name('Fred');
  </code></pre>
  
  <p>or I can manipulate it with</p>
  
  <pre><code>$o-&gt;name(qr/old/,'ry');  # name is now Harry
  </code></pre>
  
  <p>This still doesn't allow stuff like $o->name.=' Jr.'; but that's not too tough to add.  Heck, I could allow calllback functions to be passed in, couldn't I?</p>