Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical

Passing a data structure via a dynamically-built subroutine call

by Tanalis (Curate)
on Jun 21, 2004 at 09:17 UTC ( #368391=perlquestion: print w/replies, xml ) Need Help??
Tanalis has asked for the wisdom of the Perl Monks concerning the following question:


I am currently working on a web-based portal-style application that must be capable of importing a number of services (modules) at run-time.

Each service provides different functionality, for example a hook into an existing system to allow data to be aggregated, or providing some completely new functionality.

The portal system under construction makes use of a fixed interface, implemented and extended by each service to allow the portal to dynamically determine each service's interface at run-time. For example, Service X might implement methods get_legacy_data and update_legacy_data, returning a description of these methods via a call to the required get_service_interface method.

For the majority of method calls, a simple list of parameters is passed, using the following code:

sub call_service { my $svc = shift; my $cmd = shift; my @args = @_; foreach ( @args ) { $_ = "\"$_\"" } my $arg = join ",", @args; return eval $svc . "::" . $cmd . "(" . $arg . ")"; }

My problem comes where I need to pass a data structure, rather than a flat list of elements, into some service, for example an array of arrays. The method above simply converts each array in the structure into a string, which obviously isn't the intended result.

Can anyone suggest a way of changing the sub above to allow more complex data structures to be passed?

Thanks in advance,

Replies are listed 'Best First'.
Re: Passing a data structure via a dynamically-built subroutine call
by Corion (Pope) on Jun 21, 2004 at 09:21 UTC

    Don't use eval but get a reference to the code you want to call, and call that like any other subroutine:

    use Carp qw(croak); sub call_service { my $svc = shift; my $cmd = shift; my @args = @_; my $name = "$svc\::$cmd"; my $handler = *{$name}{CODE}; croak "Couldn't find a handler for $name" unless $handler; # maybe log the invocation to your logfile? return $handler->(@args); }

    This code is untested, sorry - maybe you need to take a reference like

    my $handler = \*{$name}{CODE};
    instead - sorry for not testing my stuff out.

      Here's a more slim-line version
      sub call_service { croak "Couldn't find handler for $name" unless my $c = shift->can(shift); goto &$c; }


Re: Passing a data structure via a dynamically-built subroutine call
by hmerrill (Friar) on Jun 21, 2004 at 12:41 UTC
    Good suggestions by previous responders.

    I'll just add that generally when passing parameters to subroutines, get used to passing *references* to data structures instead of the data structures themselves - you'll save yourself a lot of time and headaches :-) Arrays and Hashes get flattened out into a list of parameters which can cause problems if you're not sure exactly how that happens and what to expect in the subroutine. If you always pass references to arrays and references to hashes, then you'll never have a problem - your subroutine will always receive a reference to the array or a reference to the hash, and you know how to work with references, right?

    If not, check out 'perldoc perlref' at a command prompt.


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://368391]
Approved by Corion
Front-paged by edan
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2017-07-25 01:07 GMT
Find Nodes?
    Voting Booth?
    I came, I saw, I ...

    Results (362 votes). Check out past polls.