Magic References

james on 2003-06-10T10:38:45

I've been playing around with Perl over the last couple of days to see what I can do with references. I really get annoyed with having to test everything to see if it is blessed before testing to see if it matches the interface that I'm expecting: if (blessed( $arg ) && $arg->isa('Some::Class')) { # ... } So what I've been trying to do is get it so that references are automagically blessed into a class that shares the name of their reference type: % perl -Mmagicrefs -MData::Dumper -e 'print Dumper( {} )' $VAR1 = bless( {}, 'HASH' ); And it all works, so now I can do: use lib './lib'; use strict; use magicrefs; ## turn on magic references

my $c = { Auto => 'blessed', refs => 'are', fun => '.' };

print $c->keys->join(','),"\n";

## or ##

if ($c->keys->grep( sub { /^[A-Z]/ } )->size == 1) { print "right\n"; } else { print "wrong\n"; }

## or ##

my %hash = $c->deref;

## or with the magic of deparse

print sub { 1; }->code(), "\n";
I'm guessing the chances of this going into the core are pretty slim however :-)


UNIVERSAL::isa

rafael on 2003-06-10T11:21:54

The "blessed( $arg ) && $arg->isa('Some::Class')" idiom is not necessary. You can do

#!perl -l
$x = {};
print UNIVERSAL::isa($x,"Foo::Bar") ? 1 : 0;
print UNIVERSAL::isa($x,"HASH") ? 1 : 0;
__END__
0
1

(as documented in the UNIVERSAL manpage)

Re:UNIVERSAL::isa

james on 2003-06-10T11:36:55

I know, I was using it as a small, trite example. The actual problem is that its easier to refactor away conditions if everything is an object - which is my real dislike. I felt going into why I like to refactor away conditions was probably beyond the scope of the journal entry, which was more about having HASH/ARRAY/SCALAR/... objects, and the nice things that you can do once you have them.

Re:UNIVERSAL::isa

rafael on 2003-06-10T11:50:37

And by the way are you going to upload magicrefs to some comprehensive perl archive network ?

Re:UNIVERSAL::isa

james on 2003-06-10T11:54:01

It's essentially a patch against pp.c in the perl source. I could put it on CPAN, but it seems like a strange place to put a patch. I think it might be possible to do something similar with optimizer.pm, but I need to talk to sky a little about that.

Re:UNIVERSAL::isa

rafael on 2003-06-10T12:14:59

Ah. You're evil, then ;-) If this is a core patch, then I don't understand what's in magicrefs.pm -- is it a lexical pragma ? What core function(s) are you patching, and to do what ?

Re:UNIVERSAL::isa

james on 2003-06-10T12:26:28

magicrefs.pm is a pragma similar to sort, ie, not lexical.

Essentially it alters S_refto in pp.c. magicrefs.pm sets a hint that is examined in S_refto to determine whether or not we should bless all references that are created (with the exception of those that are SvREADONLY). magicrefs also use's the various reftype modules.

Re:UNIVERSAL::isa

rafael on 2003-06-10T12:49:27

OK, I can now see how optimizer.pm can help -- by inserting a bless op before the refgen/srefgen ops.

Re:UNIVERSAL::isa

malte on 2003-06-10T15:04:43

You could probably do this by overloading the dereferencing operators.

Obviously, at the expend of acceptable performance.

Newfangled

acme on 2003-06-10T12:36:50

Now all you need to do is make sure that it works with Acme::Dot and then we have Ruby in Perl!

Possible breakage

2shortplanks on 2003-06-10T13:42:16

Quite a lot of code needs to know if what it's passed is a object (which it shouldn't go inside) or a hash (which it can.) To do this it uses blessed which you've just broken.

Let's fix that

sub BasicType::a_sub_not_likely_to_be_here { 0 }
@HASH::ISA=qw(BasicType);
@ARRAY::ISA=qw(BasicType);
...
(untested code, of course)