I'm trying to figure out how to make a function reference work for a Perl module. I know how to do it outside of a module, but inside one? Consider code like this:
==mymodule.pm==
1 sub foo { my $self = shift; ... }
2 sub bar { my $self = shift; ... }
3 sub zip {
4 my $self = shift;
5 my $ref = \&foo;
6 $self->&$foo(); # what syntax is appropriate?
7 }
==eof===
Look at lines 5-6 above. What's the correct syntax for (1) defining the function reference in the first place, and (2) dereferencing it?
TMTOWTDI
Defining a function reference:
$ref = \&subroutine;
$ref = sub { BLOCK };
$ref = "subroutineName"; # or $ref = $scalarSubroutineName
Dereferencing:
$ref->(#args);
&$ref;
&{$ref}(#args);
If $ref is a method (expects $self as first argument) and you want to call it on
your $self, the syntax is:
$self->$ref(#args)
Use the following:
$self->$ref();
With this syntax, $ref can be a reference to a subroutine or even a string with the name of the method to call, e.g.,
my $ref = "foo";
$self->$ref();
Be aware that the two have slightly different semantics with respect to inheritance.
When you aren't passing explicit arguments, the parentheses are optional:
$self->$ref; # also flies
Otherwise, use
$self->$ref($arg1, \%arg2, #others);
Related
I'm writing some code where I am using a subroutine as both an lvalue and an rvalue to read and write database values. The problem is, I want it to react differently based on whether it is being used as an lvalue or an rvalue.
I want the subroutine to write to the database when it is used as an lvalue, and read from the database when it is used as an rvalue.
Example:
# Write some data
$database->record_name($subscript) = $value;
# Read some data
my $value = $database->record_name($subscript);
The only way I can think of the make this work is to find a way for the subroutine to recognize whether it is being used as an lvalue or an rvalue and react differently for each case.
Is there a way to do this?
Deciding how to behave on whether it was called as an lvalue or not is a bad idea since foo(record_name(...)) would call it as an lvalue.
Instead, you should decide how to behave on whether it is used as an lvalue or not.
You can do that by returning a magical value.
use Variable::Magic qw( cast wizard );
my $wiz = wizard(
data => sub { shift; \#_ },
get => sub { my ($ref, $args) = #_; $$ref = get_record_name(#$args); },
set => sub { my ($ref, $args) = #_; set_record_name(#$args, $$ref); },
);
sub record_name :lvalue {
cast(my $rv, $wiz, #_);
return $rv;
}
A little test:
use Data::Dumper;
sub get_record_name { print("get: #_\n"); return "val"; }
sub set_record_name { print("set: #_\n"); }
my $x = record_name("abc", "def"); # Called as rvalue
record_name("abc", "def") = "xyz"; # Called as lvalue. Used as lvalue.
my $y_ref = \record_name("abc", "def"); # Called as lvalue.
my $y = $$y_ref; # Used as rvalue.
$$y_ref = "xyz"; # Used as lvalue.
Output:
get: abc def
set: abc def xyz
get: abc def
set: abc def xyz
After seeing this, you've surely learned that you should abandon the idea of using an lvalue sub. It's possible to hide all that complexity (such as by using sentinel), but the complexity remains. The fanciness is not worth all the complexity. Use separate setters and getters or use an accessor whose role is based on the number of parameters passed to it ($s=acc(); vs acc($s)) instead.
For this situation you might like to try my Sentinel module.
It provides a function you can use in the accessor, to turn it into a more get/set style approach. E.g. you could
use Sentinel qw( sentinel );
sub get_record_name { ... }
sub set_record_name { ... }
sub record_name
{
sentinel get => \&get_record_name,
set => \&set_record_name,
obj => shift;
}
At this point, the following pairs of lines of code are equivalent
$name = $record->record_name;
$name = $record->get_record_name;
$record->record_name = $new_name;
$record->set_record_name( $new_name );
Of course, if you're not needing to provide the specific get_ and set_ prefixed versions of the methods as well, you could inline them as closures.
See the module docs also for further ideas.
In my opinion, lvalue subroutines in Perl were a dumb idea. Just support ->record_name($subscript, $value) as a setter and ->record_name($subscript) as a getter.
That said, you can use the Want module, like this
use Want;
sub record_name:lvalue {
if ( want('LVALUE') ) {
...
}
else {
...
}
}
though that will also treat this as an LVALUE:
foo( $database->record_name($subscript) );
If you want only assignment statements to be treated specially, use want('ASSIGN') instead.
I try to create an object inside my perl Script. Therefore I have a constructor
new(;#)
{
my $class = shift;
my $self = {};
bless $self, $class;
$self->_init(#_);
return $self;
}
And my _init(;#) Function, to initialise the object
my $self = shift;
if( #_ )
{
my %extra = #_;
#$self{keys %extra} = values %extra;
}
return;
Am I using this two functions the wrong way? I am starting every other sub with the two lines
my $self = shift;
croak "instance method called for class" unless ref $self;
But I get only syntax / String found where operator expected errors in return for every single time I am using it.
Therefore my Question: Am I using the two functions the right way? I always thought I only need to initialise $self once, like I did, and can point everything I want to it for the rest of the Script.
croak is not loaded by default. You must use Carp in the package to be able to use it (see Carp).
BTW, prototypes are ignored with method calls. Don't use them. Don't use them for functions, either.
You might use something like Class::Declare::Attributes to save some typing:
sub new :class {
...
}
My code is pretty simple. I have a subroutin getModemHost under a package named smconfig.
sub getModemHost {
print 'Modem-'.$_[0].'.Host';
}
when Im calling this subroutin with an argument, I see strange values rather than what I passed. The below line prints Modem-smconfig=HASH(0x9433968).Host. I am expecting Modem-1.Host
$smconfig->getModemHost(1)
The first argument to a method is the invocant, i.e. the object. Use $_[1] for the real first argument. Or, more readable:
sub getModemHost {
my ($self, $modem_number) = #_;
print "Modem-$modem_number.Host";
}
See perlobj for details.
Or something very common:
sub myObjectMethod {
my $self = shift;
...
# do here what you like to do with $_[0]
# for we have removed the first parameter
...
};
I am trying to undestand OO in Perl. I made the following trivial class:
#/usr/bin/perl
package Tools::Util;
use strict;
use warnings;
my $var;
sub new {
my ($class, $arg) = #_;
my $small_class = {
var => $arg,
};
return bless $small_class;
}
sub print_object {
print "var = $var\n"; #this is line 20
}
1;
And this is a test script:
#!/usr/bin/perl
use strict;
use warnings;
use Tools::Util;
my $test_object = new Tools::Util("Some sentence");
$test_object->print_object();
use Data::Dumper;
print Dumper($test_object);
The result I get is:
Use of uninitialized value $var in concatenation (.) or string at Tools/Util.pm line 20.
var =
$VAR1 = bless( {
'var' => 'Some sentence'
}, 'Tools::Util' );
I can not understand this. I thought that objects in Perl are hashes and so I could access/initialize the member variables using the same names without a $. Why in this case the $var is not initialized but the hash that I Dump contains the value?
How should I use/initialize/handle member variables and what am I misunderstanding here?
$var is lexical class variable, and undefined in your example.
You probably want:
sub print_object {
my $self = shift;
print "var = $self->{var}\n";
}
Perl doesn't handle object methods in quite the same way that you're used to.
Are you familiar with the implicit this argument that many object-oriented languages use? If not, now would be a great time to read up on it.
Here's a five-second introduction that glosses over the details:
//pretend C++
//this function signature
MyClass::MyFunction(int x);
//is actually more like the following
MyClass::MyFunction(MyClass this, int x);
When you access instance members of the class, my_var is equivalent to this.my_var.
In Perl, you get to do this manually! The variable $var is not equivalent to $self->{var}.
Your blessed object is actually a hash reference, and can be accessed as such. When you call $test_object->print_object(), the sub gets the value of $test_object as its first argument. Most Perl programmers handle this like so:
sub my_method {
my $self = shift; #shift first argument off of #_
print $self->{field};
}
With that in mind, you should probably rewrite your print_object sub to match mpapec's answer.
Further reading: perlsub, perlobj
I'm making a Perl module and I am still getting to grips with how Perl deals with objects.
This is the new sub that I wrote to create an object and I have no problem updating elements:
sub new {
my $class = shift;
my ($self) = {
name => undef
};
bless($self, $class);
return $self;
}
sub get_name {
my $self = shift;
$self->{name} = 'Eve';
return $self->{name};
}
I can use the object fine when I call the module and access it from another file, but I want to use the data in the object at other areas in the module code.
So I have no problem doing this:
my $new_object = new ProgramTest; # ProgramTest being the module/package
my $name = get_name();
But I want to use the $self elements in a 'module-internal' method which is never accessed by an outside script. So I want to have something like this:
sub get_variables {
return (name); # I don't know how to get the name here
# (I plan to have other variables, too)
}
I am probably missing something obvious (I'm sure I'll kick myself when I see the solution), so any help appreciated!
I want this so that the rest of the module can use the variables (without changing) as there are conditions that rely on their values.
There's no such thing as internal/private methods in perl objects. Common practise is to start any methods which should not be used publicly with an underscore, but this is not enforced in any way. Also have a look at moose - it takes a lot of the hassle out of OO perl.
With regards to your question the below shows how one module method can call another module method, with both having access to the object data. Again I woulds really recommend you use Moose!
sub publicSub{
my ( $self ) = #_;
return $self->_privateSub();
}
sub _privateSub{
my ( $self ) = #_;
return $self->{name};
}
I think you want class-variables. They are global to a class and all instances of the class (i.e. all the objects you created) can see them. Global in this case means that they are at the ouside-most lexical scope, so all subs can see them.
package ProgramTest;
my $everyone_can_see_this = 1; # lexical scope, but 'global' to the package
sub new {
my $class = shift;
my ($self) = {
name => undef
};
bless($self, $class);
return $self;
}
sub get_var {
my $self = shift;
return ++$everyone_can_see_this;
}
package Main;
my $o1 = ProgramTest->new;
my $o2 = ProgramTest->new;
say $o1->get_var;
say $o2->get_var;
say $o1->get_var;
__END__
2
3
4
But I don't see why you would want to do that. It doesn't make sense (unless you want an object-counter). Don't use it for config values, or you cannot really have objects for different purposes of the same class.
Maybe you want something else. If so, please try to rephrase your question.