- Perl ›
- Subroutine ›
- here
Dynamic generation of subroutine
Perl also allows you to dynamically generate subroutine.
Function generator
A function generator is a subroutine that creates a subroutine. Function generators are one of the techniques used when you want to dynamically generate subroutine.
It's called a function generator according to its general name, but in Perl terms it's a subroutine generator. In this discussion, functions and subroutine have the same meaning.
Creating and calling a function generator
# Call my $func = func_generator (); $func->(); # Definition sub func_generator { my $func = sub { print "This is a subroutine generated at runtime.\n"; }; # Returns a reference to the subroutine. return $func; }
To create a generator for it, create an anonymous subroutine and return its reference as a return value.
When you call the function generator (func_generator ()), you can get a reference to the generated subroutine as a return value. Dereference ($func->()) the reference of the generated subroutine and call the subroutine.
Generate multiple subroutine that are slightly different
# Function generator call my $create_safe_msg = message_factory ("is safe."); my $create_danger_msg = message_factory ("is danger."); # Call the generated subroutine my $safe_msg1 = $create_safe_msg->("cat"); my $danger_msg1 = $create_danger_msg->("mamushi"); # Function generator that creates a subroutine that allows you to specify the message to convey sub message_factory { my $message = shift; return sub { my $word = shift; return $word.'''. $Message; } }
It can be used in a subroutine that receives an argument in a function generator and generates that argument. This allows you to generate multiple subroutine that are slightly different.
Dynamically name subroutine using typeglobs
This is an example that dynamically names a subroutine using a typeglob.
Name an anonymous subroutine
* sum = sub { return $_[0]+$_[1]; };
Subroutines can be aliased by using typeglobs. The left side is the type glob(* name) and the right side is the reference to the subroutine (\&subroutin).
In the case of this example, the right-hand side is a reference to the anonymous subroutine, which means that the anonymous subroutine is given an alias.
You might think that it's better to name the anonymous subroutine from the beginning than to name it. The advantage of naming anonymous subroutine is that you can give the subroutine a name at run time. The subroutine name can be determined dynamically.
Dynamically name subroutine
my $word = 'cat'; my $func_name = "${word} _repeat"; no strict'refs'; * {$func_name} = sub { return "$word $word"; };
You can use variable in the typeglob name. The subroutine name changes depending on the value entered in $func_name.
The description * {$name} will result in an error if you use use strict ;. no strict Disables symbolic link restrictions as'refs'. (By the way, why is the description * {$name} a symbolic reference?) In this case, the name cat_repeat is dynamically assigned.
Let's write a little better.
BEGIN { my $word = 'cat'; my $func_name = "${word} _repeat"; my $code = sub { return "$word $word"; }; no strict'refs'; * {$func_name} = $code; }
Use BEGIN to dynamically determine the subroutine name at compile time. Store the reference to the anonymous subroutine in a variable with the description my $code = sub {} ;, and finally name it as * {$func_name} = $code ;. In this way, you should keep the scope of no strict'refs' as narrow as possible.
Function template
Function template is a programming technique that dynamically creates multiple subroutine. Instead of naming the subroutine before the program starts, name the subroutine after the program starts.
By using anonymous subroutine and typeglobs, you can dynamically generate subroutine and name them dynamically. You can use a function template to create a process according to the subroutine name.
How to write a function template
my %numbers = ( one => 1, two => 2, three => 3, four => 4, ); for my $num (keys %numbers) { # Repeat reference to anonymous subroutine my $code = sub { # Returns the return value corresponding to the name of the number return $numbers{$num}; }; # Remove restrictions on symbolic reference no strict'refs'; # Name an anonymous subroutine using a type glob. * {$num} = $code; }
The point to note is that there is a relationship between "subroutine name" and "subroutine processing". If the subroutine name is one, the corresponding $numbers{'one'}, or 1, is returned as the return value.
To create a function template, first pass an array of subroutine names to foreach statement and call it repeatedly. Next, create an anonymous subroutine and perform processing using the function name. Finally, we'll use a typeglob to name the anonymous subroutine.
In actual use, it is used in the part of creating accessors in modules such as Class::Accessor.
Let's write a little better.
BEGIN { my %numbers = ( one => 1, two => 2, three => 3, four => 4, ); for my $num (keys %numbers) { # Repeat reference to anonymous subroutine my $code = sub { return $numbers{$num}; # Returns the return value corresponding to the name of the number }; # Remove restrictions on symbolic reference no strict'refs'; # Name an anonymous subroutine using a type glob. * {$num} = $code; } }
It is better to enclose it in a BEGIN block and dynamically create a subroutine at compile time. Otherwise, you will not be able to call the subroutine until you make this statement.
A better way is to create it as a module in a separate file and use use to load it at compile time.
Example code
Function generator
Example code for the function generator.
I will explain the function generator using code.
use strict; use warnings; print "1: Generate a subroutine with a function generator\n"; my $func = func_generator (); $func->(); print "\n"; # Function generator sub func_generator { my $func = sub { print "This is a subroutine generated at runtime.\n"; }; # Returns a reference to the subroutine. return $func; } print "2: Generate multiple subroutine with function generator.\n"; # A reference to the subroutine is returned my $create_safe_msg = message_factory ("is safe."); my $create_danger_msg = m essage_factory ("is danger."); print "Subroutine generated with'is safe'\n"; # Dereference and call my $safe_msg1 = $create_safe_msg->("cat"); my $safe_msg2 = $create_safe_msg->("dog"); print "${safe_msg1}\n ${safe_msg2}\n\n"; print "Subroutine generated with'is danger'\n"; my $danger_msg1 = $create_danger_msg->("mamushi"); my $danger_msg2 = $create_danger_msg->("suzumebachi"); print "${danger_msg1}\n ${danger_msg2}\n\n"; # Function generator that creates a subroutine that allows you to specify the message to convey sub message_factory { # You can dynamically change the generated subroutine by the argument of function generator. my $message = shift; return sub { my $word = shift; return $word.'''. $Message; } }
Name dynamically generated subroutine
This is an example to name a dynamically generated subroutine using a typeglob.
use strict; use warnings; # Determine the name of the subroutine at run time. # This can be achieved by using type globs and anonymous subroutine. print "1: Name the anonymous subroutine.\n"; * sum = sub { # * sum is a function called type blog, and you can create an alias. # Here, the unnamed subroutine is named sum. return $_[0]+$_[1]; }; print "The sum of 1 and 2 is" .sum (1, 2). ".\n\n"; print "2: Dynamically name the subroutine.\n"; my $word = 'cat'; my $func_name = "${word} _repeat"; no strict'refs'; * {$func_name} = sub { # When executing the cat_repeat name in an anonymous subroutine # Can be given. return "$word $word"; }; my $repeat_word = cat_repeat (); print $repeat_word . "\n";
Function template
This is an example using a function template.
use strict; use warnings; # Function template print "1: Dynamically create multiple subroutine using function templates.\n"; # Make sure that 1 is returned when the subroutine one is called. # Make sure that 2 is returned when the subroutine two is called. my %numbers = ( one => 1, two => 2, three => 3, four => 4, ); for my $num (keys %numbers) { # Repeat reference to anonymous subroutine my $code = sub { # Returns the return value corresponding to the name of the number return $numbers{$num}; }; # Remove restrictions on symbolic reference no strict'refs'; # Name an anonymous subroutine using a type glob. * {$num} = $code; } print one (), two (), three (), four (), "\n";