How to define a sub on the fly?

K

kj

Can someone please show me how to define a sub Foo::Bar::baz on
the fly (i.e. when the module is loaded)?

Thanks!

kj
 
W

Walter Roberson

:Can someone please show me how to define a sub Foo::Bar::baz on
:the fly (i.e. when the module is loaded)?

Try constructing it inside a BEGIN block. BEGIN blocks are executed
as the module is loaded.
 
U

Uri Guttman

WR> :Can someone please show me how to define a sub Foo::Bar::baz on
WR> :the fly (i.e. when the module is loaded)?

WR> Try constructing it inside a BEGIN block. BEGIN blocks are executed
WR> as the module is loaded.

that won't help much. the module itself is executed at compile time when
it is loaded by the use statement so the BEGIN block gains little there.

but i would ask the OP what they mean by creating a sub on the fly and
why does he think it is needed? it isn't hard to do but i won't help if
it is not even needed.

uri
 
M

Malcolm Dew-Jones

kj ([email protected]) wrote:
: Can someone please show me how to define a sub Foo::Bar::baz on
: the fly (i.e. when the module is loaded)?

Since that's the normal case, I'll assume you mean you want to define it
in an unusual manner. The following probably defines two subs called baz
and boz, though I can't test it while using this computer.


foreach $baz (qw(baz boz))
{ eval qq{
sub Foo::Bar::$baz
{ print "This is sub Foo Bar $baz\n";
}
};
}


(oh dear, ATARI sm125 appears to be toasting, bye bye to an old faithful
companion. I wonder if this will make sense. Better stop typing
 
K

kj

WR> :Can someone please show me how to define a sub Foo::Bar::baz on
WR> :the fly (i.e. when the module is loaded)?
but i would ask the OP what they mean by creating a sub on the fly and
why does he think it is needed? it isn't hard to do but i won't help if
it is not even needed.

OK, here's the situation. The module in question has the simple
task of serving information contained in a *variable* collection
of data flat-files (data/A, data/B, ..., data/X, etc.). For me,
the most natural way to code this would be to have a sub/method
that took a filename as argument (e.g. get_data("$path/data/B")),
but for reasons that have to do with the software framework in
which this module will operate, it is necessary, instead, to have
several separate subroutines named after the data files (e.g. sub
A { ... }, etc., which could simply call get_data("$path/data/A").
And since the names of these files cannot be known until runtime,
these subroutines can only be defined then.

Thanks,

kj
 
U

Uri Guttman

k> In <[email protected]> Uri Guttman

k> OK, here's the situation. The module in question has the simple
k> task of serving information contained in a *variable* collection of
k> data flat-files (data/A, data/B, ..., data/X, etc.). For me, the
k> most natural way to code this would be to have a sub/method that
k> took a filename as argument (e.g. get_data("$path/data/B")), but
k> for reasons that have to do with the software framework in which
k> this module will operate, it is necessary, instead, to have several
k> separate subroutines named after the data files (e.g. sub A { ...
k> }, etc., which could simply call get_data("$path/data/A"). And
k> since the names of these files cannot be known until runtime, these
k> subroutines can only be defined then.

then how do you determine which method to call? i mean how does the
driving code select the method? is based on the filename itself? what is
the class this object is in? could it have an attribute that is the
filename? one way to solve this is via polymophism. you create a set of
classes named for the file (e.g. MyData::A) which all implement the
get_data method. the framework then builds a class name based on the
file name and uses that to create a new object. then it calls get_data
(remember, the same method name in all the classes) and voila, you have
your data. but it all sounds like too much work in any case. what kind
of framework can't handle simple args or a dispatch table.

uri
 
A

Anno Siegel

Uri Guttman said:
k> In <[email protected]> Uri Guttman


k> OK, here's the situation. The module in question has the simple
k> task of serving information contained in a *variable* collection of
k> data flat-files (data/A, data/B, ..., data/X, etc.). For me, the
k> most natural way to code this would be to have a sub/method that
k> took a filename as argument (e.g. get_data("$path/data/B")), but
k> for reasons that have to do with the software framework in which
k> this module will operate, it is necessary, instead, to have several
k> separate subroutines named after the data files (e.g. sub A { ...
k> }, etc., which could simply call get_data("$path/data/A"). And
k> since the names of these files cannot be known until runtime, these
k> subroutines can only be defined then.

then how do you determine which method to call? i mean how does the

I'm not sure the OP's framework is OO at all.
driving code select the method? is based on the filename itself?

That's the question, whether OO or not. Making the names of subroutines
dependent on exterior filenames breaks the program/data separation.
Making the sub calls later may break it again.
the class this object is in? could it have an attribute that is the
filename? one way to solve this is via polymophism. you create a set of
classes named for the file (e.g. MyData::A) which all implement the
get_data method. the framework then builds a class name based on the
file name and uses that to create a new object.

What is the object for? The get_data method doesn't need one, it might
as well be a class method and be called as such. You would need to call
a class method to create the object in any case, it might as well do
the actual job. IOW, instead of doing

my $class = 'MyData::' . $filename;
my $obj = $class->new;
my $data = $obj->get_data;

say

my $class = 'MyData::' . $filename;
my $data = $class->get_data;
then it calls get_data
(remember, the same method name in all the classes) and voila, you have
your data. but it all sounds like too much work in any case. what kind
of framework can't handle simple args or a dispatch table.

I'm wondering that too...

Anno
 
M

Mark Clements

Walter said:
:Can someone please show me how to define a sub Foo::Bar::baz on
:the fly (i.e. when the module is loaded)?

Try constructing it inside a BEGIN block. BEGIN blocks are executed
as the module is loaded.
Sidestepping the rest of the thread (ie the validity of doing this), you
can use the autoloader and/or eval. Creation of subs (or any code on the
fly) can be done with eval $definition.

eg
eval<<EOF;
sub newsub(){
return "from newsub";
};
EOF

You may well want to take this step within a BEGIN block. Bear in mind
prototypes are meaningless when a sub is called as a class or object method.

There are many examples of using the autoloader available so I won't
give one here, but you probably want to use it to intercept calls to eg
get_filename1(), get_filename2() and take it from there.

Mark
 
A

Anno Siegel

Mark Clements said:
Sidestepping the rest of the thread (ie the validity of doing this), you
can use the autoloader and/or eval. Creation of subs (or any code on the
fly) can be done with eval $definition.

....it can, granted, but there's no real need for "eval".
eg
eval<<EOF;
sub newsub(){

Why the prototype? They are the exception with sub definitions, not
the rule.
return "from newsub";
};
EOF

*newsub = sub { return "from newsub" };

has the same effect, but is clearer and simpler.

Anno
 
A

Anno Siegel

Mark Clements said:
Sidestepping the rest of the thread (ie the validity of doing this), you
can use the autoloader and/or eval. Creation of subs (or any code on the
fly) can be done with eval $definition.

....it can, granted, but there's no real need for "eval".
eg
eval<<EOF;
sub newsub(){

Why the prototype? They are the exception with sub definitions, not
the rule.
return "from newsub";
};
EOF

*newsub = sub { return "from newsub" };

has the same effect, but is clearer and simpler.

Anno
 
M

Mark Clements

Anno said:
Why the prototype? They are the exception with sub definitions, not
the rule.
I tend to use them because if used correctly they enable the compiler to
catch attempts to call subs with the wrong number of arguments, though
obviously here they'll have no effect as the compiler can't see the
definition of the new sub. It was therefore misleading of me to use it here.

*newsub = sub { return "from newsub" };
In this case, yes, but I don't see how this enables you to build
subroutines on the fly. eval STRING is relatively inefficient but
extremely powerful (and therefore dangerous).

Mark
 
P

Peter Scott

Anno Siegel wrote:
In this case, yes, but I don't see how this enables you to build
subroutines on the fly.

Closures.

{
my $thing = "foo";
my $method = "${thing}_method";
no strict 'refs';
*$method = sub { ... do something with $thing ... };
}
 
A

Anno Siegel

Mark Clements said:
I tend to use them because if used correctly they enable the compiler to
catch attempts to call subs with the wrong number of arguments,

True, but it also makes your subs behave weirdly, supplying unexpected
context to arguments or even silently taking references. In my view,
prototypes can (sparingly) be used in interface-type functions to
help the user deal with them, or to allow suggestive syntax. The
non-standard behavior must be clearly documented. Few Perl programmers
use prototypes routinely with all subs.
though
obviously here they'll have no effect as the compiler can't see the
definition of the new sub. It was therefore misleading of me to use it here.


In this case, yes, but I don't see how this enables you to build
subroutines on the fly. eval STRING is relatively inefficient but
extremely powerful (and therefore dangerous).

If you actually need to compile a string of code for the new sub, there
is no way around "eval".

Often a closure gives enough flexibility. If the sub needs to read a
particular file, this would do (simplified, untested):

sub create_sub {
my $name = shift;
my $sub = sub {
open( my $f, $name) or die "Can't read file '$name': $!";
# ...
};
no strict 'refs';
*{ 'read_' . $name} = $sub;
}

That creates one named closure per call, each reading the file it is
named after. No need for "eval" here.

Anno
 
K

kj

WR> :Can someone please show me how to define a sub Foo::Bar::baz on
WR> :the fly (i.e. when the module is loaded)?
WR> Try constructing it inside a BEGIN block. BEGIN blocks are executed
WR> as the module is loaded.
that won't help much. the module itself is executed at compile time when
it is loaded by the use statement so the BEGIN block gains little there.
but i would ask the OP what they mean by creating a sub on the fly and
why does he think it is needed? it isn't hard to do but i won't help if
it is not even needed.

The framework I was referring to is a Web services one, in which
clients discover and call a server's available services at runtime.
(I should add that this framework is horribly designed, and even
worse implemented--all out of my hands.) As it turns out, at our
site the menu of services that fit this model is one that is
dynamically changing (the sources of available data, each corresponding
to a different data file, will change from one day to the next,
both in number and in content). In this case, clients "discover"
desired services typically by requesting desired input and output
signatures. The input signature for all these possible services
has no room for a filename, or any other parameter that could be
used to select among all the services provided at our site at any
given time. Likewise, the service dispatching protocol (which I
don't control) matches service names to methods in a 1-to-1 way
(in fact the service names are expected to be identical to the
names of the corresponding methods that the dispatcher calls). I
don't see any way to match this API other than by providing separate
methods for each data source file available at our site on a given
day, even if these methods all end up calling the same core method
with an additional argument (the source file to use). (The
meta-service that describes all the services available at our site
to interested clients would also need to determine these methods
dynamically.)

kj
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top