in reply to Missing object reference in sub

Perl 5 doesn't make a strong distinction between subroutines and methods. The magic is really at the point of invocation, and that's whether you call the function as a method on an invocant or invoke it directly.

I don't know the particulars of this API, but if the methods are supposed to be callbacks, you may have to create a thunking closure that invokes the method on the object appropriately:

sum => sub { $obj->sum( @_ ) },

Replies are listed 'Best First'.
Re^2: Missing object reference in sub
by Lazarus (Novice) on Sep 26, 2007 at 20:13 UTC

    To quote the documentation:

    Frontier::Daemon takes a `methods' parameter, a hash that maps an incoming RPC method name to reference to a subroutine.

    The Client side code for the example is

    use Frontier::Client; my $url = "http://127.0.0.1/RPC2"; # Server my @args = (2,3); # values to pass to sum() # Create the client my $client = Frontier::Client->new( url => $url, debug => 0, ); print "$args[0] + $args[1] = ", $client->call('sum', @args), "\n";

    So the client doing the calling can't pass the object refefence.

    I can't do what chromatic said because I do not have an $obj at the point. (Remember that the call to the Daemon constructor never returns.)

    I tried looking at the module source myself, but they do some weird stuff in there. Beyond my limited scope. (And they call it 'weird' themselves so they know it.) I'd post some of it here but it's on an innaccessble machine at the moment.

    I didn't expect anyone to be familiar with the Frontier::Daemon, but I was hoping that someone who had used the HTTP::Daemon ran into the same situation as myself. They would have ran into the same problem as me.

      I can't do what chromatic said because I do not have an $obj at the point. (Remember that the call to the Daemon constructor never returns.)

      Sure you can. The closure has to bind to the lexical at compile time, but the object has to be valid at the point of the call, which is after the object creation. Add one line:

      my $id; $id = Frontier::Daemon->new( ... );

      ... then use $id in the closure.

        ... but would $id ever get assigned something, if the constructor doesn't return?

        Tried it. Got back error:

        Can't call method "sum" on an undefined value at line ...
      I tried looking at the module source myself ...

      In case you don't mind modifying the sources... this is what a quick grep turned up (in RPC2.pm / sub serve {...}):

      my $eval = eval { $result = &{ $methods->{$method} }(@{ $call->{'v +alue'} }) }; if ($@) { ... }

      Presuming that the $self available within that serve method is what you need (not sure... but why not try?), you could add it to the argument list yourself, i.e.

      my $eval = eval { $result = &{ $methods->{$method} }($self, @{ $ca +ll->{'value'} }) }; ^^^^^

      Just an idea... (untested)

        I didn't think that this would work but I gave it a shot anyway. As I suspected by looking at the RPC2.pm, the object there is not based on the IO::Socket class, so while I can now get a $self, it isn't one that I can use. Nice try though. Thanks.

      I'm confused. At one point you say the constructor never returns, but the example shows using it in assignment and in code afterward. For my possibly helpful reply, I'm assuming that it does return.

      package Frontier::NotReally; sub new { my $class = shift; my %p = @_; return bless \%p, $class; } sub id { my $self = shift; return "$self"; } sub call { my $self = shift; return $self->{sub}->( @_ ); } package main; my $id; $id = Frontier::NotReally->new( sub => sub { print "insub: ", $id->id( +), "\n" } ); print "outsub: ", $id->id(), "\n"; $id->call( 'sub' ); __END__ outsub: Frontier::NotReally=HASH(0x6f1940) insub: Frontier::NotReally=HASH(0x6f1940)

      I don't know how much my mockup, Frontier::NotReally, matches the actual Frontier::Daemon you're dealing with, but it's close enough by my understanding. The important part of this example is that my lexical declaration of $id comes before its actual assignment.

      my $id; # now $id exists! $id = F::D->new( foo => sub { 'here, $id exists too' } );
      What happens is that at the time you call the constructor, $id is undef. Once the constructor finishes, $id has the object's reference in it, and the anonymous sub you passed into the constructor can use it. This won't work if the constructor itself is calling your callback, but any time after that, you'll have the object ready to work with.

      Update: I see chromatic has explained faster than I have.

        ... I'm assuming that it does return.

        I think it doesn't. The source goes something like this:

        sub new { ... while ($conn = $self->accept) { # serve request } }

        i.e., before returning, it enters an accept loop, as typical for daemons listening on a socket.