Hi all :-),
I recently decided to convert one of my more complex library classes over to the outside-in class model. I'm using Perl 5.8 and rather than use say Class::Std (does that even work with early 5.8?) and add another dependency to my library for the sake of 10 lines of code, I have implemented it directly. I used XDG's posting Threads and fork and CLONE, oh my! as the basis.
Anyway, it's all working as it should :-). However one thing I did differently was to cache the address inside the blessed object rather than `recompute/fetch' it with refaddr() each time I needed it. So instead of doing something like:
my %class_records;
my $class_objects;
.
.
sub new($)
{
my $class = (ref($_[0]) ne "") ? ref($_[0]) : $_[0];
my $this = {attr1 => "Hello World"};
my $self = bless({}, $class);
my $id = refaddr($self);
$class_records{$id} = $this;
$class_objects{$id} = $self;
weaken($class_objects{$id});
return $self;
}
sub some_method($)
{
my $self = $_[0];
my $this = $class_records{$refaddr($self)};
...
}
I did:
my $class_name = __PACKAGE__;
my %class_records;
my $class_objects;
.
.
sub new($)
{
my $class = (ref($_[0]) ne "") ? ref($_[0]) : $_[0];
my $this = {attr1 => "Hello World"};
my $self = bless({}, $class);
my $id = refaddr($self);
$self->{$class_name} = $id;
$class_records{$id} = $this;
$class_objects{$id} = $self;
weaken($class_objects{$id});
return $self;
}
sub some_method($)
{
my $self = $_[0];
my $this = $class_records{$self->{$class_name}};
...
}
Note: The %class_objects hash is used to keep track of objects and refiling them during cloning. It is equivalent to XDG's %REGISTRY hash.
Since I never use refaddr() again on an object once it is created do I need to bother with the refiling that goes on in his CLONE() method when it comes to threading (ithread)? I think not... My reasoning is this:
- refaddr() returns the memory address associated with that object.
- Threads within a process all share the same address space. Therefore the address returned from creating a new object and using refaddr() on it will not clash with any existing object.
- There would be no clash between the main or parent thread and a newly created child thread as %class_records and %class_objects are cloned as are the items that they point to. Although the keys will remain unchanged, what they point to will be unique.
- The only issue I can see is that if an object that existed in the parent thread when the child thread was created, was then subsequently destroyed in the parent and then the child creates a new object then it could theoretically get the same address as the one destroyed in the parent and clash with the entry inside the child's %class_records and %class_objects maps because the child still has the clone of the object destroyed in the parent.
This issue can easily be overcome with a simple clash detector and then there is no need for CLONE() nor %class_objects. After all refaddr is being used to generate unique ids cheaply.
Is my thinking sound or have I got inadvertently eaten some dodgy mushrooms! :-)
Anyway, many thanks in advance.
Tony.