I wanted different instances of a particular class to have different overloaded methods. The way I originally did this was:

use overload; sub new { my $class = shift; overload->import( %{shift()} ); return bless {}, $class; }

I wasn't too surprised to find that this didn't work. Since I'm not telling overload anything about the instance I'm working on, it must be doing something to the package it's about to be blessed into. Because of that, subsequent instances change the overloading of previous instances (not what I want).

My solution was to generate a new package for each instance. It now looks like this (with tests):

use strict; use warnings; package SelectiveOverload; use overload; my $package_suffix = 'a'; sub new { my $class = shift; my $overload = shift; my $package = __PACKAGE__; my $new_package = join '::', $package, $package_suffix++; my $mkpackage = <<"SELECTIVE_OVERLOAD"; package $new_package; overload->import( \%{\$overload} ); \@$new_package\::ISA = ( '$package' ); SELECTIVE_OVERLOAD eval $mkpackage; die $@ if $@; return bless {}, $new_package; } package main; use Test::More 'tests' => 9; use Scalar::Util qw( reftype ); my $over_array_called = 0; my $over_array = SelectiveOverload->new( { '@{}' => sub { $over_array_called = 1; [] } } ); isa_ok( $over_array, 'SelectiveOverload' ); ok( !$over_array_called, 'array overload sub not called' ); my @x = @{$over_array}; ok( $over_array_called, 'array overload sub was called' ); ok( !eval { my $test = ${$over_array}; 1 }, 'dereference scalar on $over_array fails' ); $over_array_called = 0; my $over_scalar_called = 0; my $over_scalar = SelectiveOverload->new( { '${}' => sub { $over_scalar_called = 1; \my $x } } ); isa_ok( $over_scalar, 'SelectiveOverload' ); ok( !$over_scalar_called, 'scalar overload sub not called' ); my $x = ${$over_scalar}; ok( $over_scalar_called, 'scalar overload sub was called' ); ok( !eval { my @test = @{$over_scalar}; 1 }, 'dereference array on $over_scalar does not work' ); ok( !$over_array_called, 'array overload sub not called' );

The last two tests are the ones that failed in my initial implementation.

One thing I haven't done (but maybe could do) is memoize the package names based on the overload options presented. That would be difficult to do generally, though, since I have to match the sub refs to each other.

I'm wondering if any other monk has any experience to share about this. My understanding over overloading is a bit hazy, so I wonder if I've just shot myself in the foot somehow.


In reply to Overloading different instances differently. by kyle

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.