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.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Overloading different instances differently.
by tilly (Archbishop) on Feb 22, 2008 at 22:12 UTC | |
by plobsing (Friar) on Feb 23, 2008 at 01:40 UTC | |
by tilly (Archbishop) on Feb 23, 2008 at 03:48 UTC | |
by lodin (Hermit) on Feb 23, 2008 at 15:51 UTC | |
by kyle (Abbot) on Feb 22, 2008 at 22:23 UTC | |
|
Re: Overloading different instances differently.
by Fletch (Bishop) on Feb 22, 2008 at 22:08 UTC | |
by tilly (Archbishop) on Feb 22, 2008 at 22:18 UTC | |
by Fletch (Bishop) on Feb 22, 2008 at 22:54 UTC |