Corion has asked for the wisdom of the Perl Monks concerning the following question:
I'm currently implementing an object/application bridge between Perl and Javascript, using the MozRepl plugin for Mozilla FireFox and the MozRepl module. The goal is to implement a transparent bridge that lets you work with the Javascript objects as if they were native Perl objects, just like you can treat Win32::OLE objects as if they were native Perl objects.
The setup to achieve this is very simple. The bridge module I wrote is tentatively named MozRepl::RemoteObject. For the purpose of this discussion, the JS side of the bridge returns an integer when it would return an object. It looks like this in Javascript:
repl.link = function(obj) { if (! repl.linkedVars) { repl.linkedVars = {}; repl.linkedIdNext = 1; }; if (obj) { repl.linkedVars[ repl.linkedIdNext ] = obj; return repl.linkedIdNext++; } else { return undefined }
It could be written like this in Perl:
sub link { my ($repl,$obj) = @_; if (! $repl->{linkedVars}) { $repl->{linkedVars} = {}; $repl->{linkedIdNext} = 1; }; if (defined $obj) { $repl->{linkedVars}->{ $repl->{linkedIdNext} } = obj; return $repl->{linkedIdNext}++; } else { return undef }; };
The Perl implementation of the objects is very simple:
package MozRepl::RemoteObject; sub new { my ($class, $id) = @_; my $self = { id => $id, }; bless $self, $class; }; sub expr { my ($class, $js) = @_; return $class->new( javascript_eval($js)); # assuming that it retu +rns an object };
Releasing objects is easily done by making the DESTROY method of the object release the Javascript object of the same id:
sub DESTROY { my ($self) = @_; if ($self->{id}) { $self->expr("repl.breakLink($self->{id})"); }; };
and the JS side of the bridge implements repl.breakLink() as:
repl.breakLink = function(id) { delete repl.linkedVars[ id ]; }
which can be translated to Perl as
sub breakLink { my ($repl,$id) = @_; delete $repl->{linkedVars}->{id}; };
This all works fine and dandy, objects get created, handed around within Perl space, and released once all Perl code is done with them.
But (and you knew there was this small niggle), there is one small problem:
my $doc_a = MozRepl::RemoteObject->expr('window.document'); # id 42 my $doc_b = MozRepl::RemoteObject->expr('window.document'); # id 43
creates two different references to the same object, and refaddr claims I have two different objects. During the writing of this node, I've come up with three solutions, one I find good, one I find bad and one I find ugly. I'd like your input on the three solutions and potentially other solutions that allow me to emulate checking the object identity in Perl without having to reimplement reference counting.
My current plan is to go with the first option resp. to leave object identity well alone, as I currently see few reasons to actually use object identity. Of course, this stance makes it impossible to "inherit" from such a Javascript object by using an inside-out object approach, because the object identity is not maintained.
PS: If you want to look at the real code instead of my mock example,
it lives in a github repository,
and the main code I write this for is WWW::Mechanize::FireFox.
Both are WWW::Mechanize::FireFox is not yet on CPAN because they haven't even reached CPAN release quality.
Update: Linked to released module, fixed markup
|
|---|