Passing argument to a Perl class subroutin - perl

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
...
};

Related

How to forward arguments to a super function in perl?

I'm a very perl beginner, but I have (more or less) this code:
package Base;
sub foo{
my ($self, $first, $second, $third) = #_;
# do some magic here!
}
package Subclass;
use base qw(Base);
sub foo{
my ($self, $first, $second, $third) = #_;
#do something with $first only
return $self->SUPER::foo($first, $second, $third);
}
And the method is called with: $self->foo("Hey", "what's", "up");
Is there a more concise way to call SUPER::foo(), without repeating the list of all args again?
you can re-use #_ to pass the arguments like this
$self->SUPER::foo(#_);
Since the first element of #_ is the "object" used to call the class method, you don't want to pass that into the parent class method twice, so you should use shift to remove it first.
sub foo{
my $self=shift;
my ($first, $second, $third) = #_;
#do something with $first only
return $self->SUPER::foo(#_);
}
This might actually be one of the valid uses of the &function; call.
E.g.
&SUPER::foo;
As documented in perlsub - this makes #_ visible to the called sub.
It should be used with care, because it's deviating from what you might normally expect to happen - it's not passing args, it's making the same set 'visible'.

Perl. Access caller arguments (like shift, pop, etc)

In perl there is the shift function that can act on the #_(arguments of a function in scope of which it was called) if no arguments supplied.
Can I write a custom function in perl with the same behavior(some kind of my_shift)?
I tried this:
use Data::Dumper;
sub get_caller_args (;$) {
my $n = shift;
$n = defined $n? $n:1;
my $ret;
package DB {
my($t,$t1) = caller($n);
};
$ret = \#DB::args;
return $ret;
}
sub test ($#) {
my $self = shift;
print "Self: $self.\n";
print Dumper(get_caller_args()), "\n";
}
It kind of works, but
test(1,2,3)
outputs:
Self: 1.
$VAR1 = [
1,
2,
3
];
So it doesn't see changes made by shift (though it can see changes made by pop).
But I want it to act like this:
sub test {
my $self = shift;
print my_function;
}
Here the my_function called without arguments must act on the #_, in this case on the rest of the arguments, without the first as it was shifted(actually I need only to read arguments, not to do changes).
Ok, I found an answer:
use feature 'say';
sub my_shift {
say "Arguments before shift: ", #_;
shift;
say "Arguments after shift: ", #_;
}
sub test {
say "Arguments before my_shift: ", #_;
&my_shift;
say "Arguments after my_shift: ", #_;
}
The 'tricky' thing here is to call the my_shift with an ampersand(&) before the function name -- then the function gets arguments of the calling function as it's input.
However I'll not accept this self-answer, because I'm still interested if it possible to do this without that ampersand magic and what if i need to pass other arguments and access the calling function arguments at the same time, etc.

Using Perl's Method::Signatures, why can't I invoke methods on an object instance?

I followed what friedo said here.
Now, when I try to call the method testScript I get the error global symbol $obj requires explicit package name and it fails to call testScriptTwo.
use strict;
use warnings;
package Test;
use Method::Signatures;
method new {
my $obj = bless {}, $self;
return $obj;
}
method testScript {
$obj->testScriptTwo(); # Error happens here
}
method testScriptTwo { ... }
Test script:
use Test;
my $class = Test->new();
$class->testScript();
How do I make use of $obj to call methods within the package itself?
Use this instead:
method testScript {
$self->testScriptTwo();
}
The first argument is in the variable $self, not $obj
Your questions seem to indicate you do not understand the basics of scope, and how plain Perl objects work.
In Perl, when you use the ->method syntax on a package name or blessed reference, the subroutine method in that package is invoked. The first argument to the subroutine is the thing on which you invoked method.
So, if you do
My::Friend->new('Alfred');
the new subroutine in the package My::Friend receives two arguments. My::Friend and Alfred.
In a new method, it is customary to refer to the first argument as $class, but that is completely up to you. You could use $basket_case if you were so inclined:
sub new {
my $basket_case = shift;
my $basket = shift;
my $obj = bless { name => $basket } => $basket_case;
return $obj;
}
If you then invoke a method on the returned reference, that method will receive said reference as its first argument, allowing you to access data stored in that reference:
sub blurb {
my $schmorp = shift;
print $schmorp->{name}, "\n";
return;
}
Putting it all together:
#!/usr/bin/env perl
package My::Package;
use strict;
use warnings;
sub new {
my $basket_case = shift;
my $basket = shift;
my $obj = bless { name => $basket } => $basket_case;
return $obj;
}
sub blurb {
my $schmorp = shift;
print $schmorp->{name}, "\n";
return;
}
sub derp {
my $herp = shift;
printf "%s derp derp\n", $herp->{name};
return;
}
package main;
my $x = My::Package->new('Alfred');
$x->blurb;
$x->derp;
Output:
Alfred
Alfred derp derp
You need to understand these basics. Trying to put another layer of abstraction on top of the basics before understanding what is underneath will not make things any easier.
Now, if you are using Method::Signatures, it, by convention, puts that implicit first argument in a lexically scoped variable which, by default, it calls $self.
You can override that name in specific methods, and doing so in new might be a good idea to convey the fact that it doesn't expect an object instance; instead it returns a new instance.
Whatever you called that lexically scoped instance variable in one sub does not affect what it is called in another sub. For example:
#!/usr/bin/env perl
use strict;
use warnings;
sub a_number {
my $number = int(rand(10));
return $number;
}
sub square_that_number {
my $x = shift;
return $x * $x;
}
my $bzzzt = a_number();
my $trrrp = square_that_number($bzzzt);
print $trrrp, "\n";
Output:
$ ./zt.pl
36
OK, you need to backtrack a bit - you're new method is broken in the first place, which indicates that you don't really understand what's going on with OO perl.
A very simple object looks like this:
package Foo;
sub new {
#when Foo -> new is called, then 'Foo' is passed in as the class name
my ( $class ) = #_;
#create an empty hash reference - can be anything, but $self is the convention
my $self = {};
#tell perl that $self is a 'Foo' object
bless ( $self, $class );
#return the reference to your `Foo` object
return $self;
}
sub set_name {
my ( $self, $new_name ) = #_;
$self -> {name} = $new_name;
}
sub get_name {
my ( $self ) = #_;
return $self -> {name};
}
When you call this in your code:
use Foo;
my $new_instance = Foo -> new();
The class is passed into the new method, which you then use bless to create an instantiated object.
Then you can 'do stuff' with it - when you 'call' a method using -> then the first argument into the subroutine is the object reference.
So
$new_instance -> set_name ( "myname" );
print $new_instance -> get_name();
Is equivalent to:
Foo::set_name($new_instance, "myname" );
print Foo::get_name($new_instance);
You act on $new_instance which is a sort of magic hash that allows you to include code.
Method::Signatures is largely irrelevant until you understand the basics of OO. But what that does is 'simply' expand the functions within a module, such that you don't have to extract self/class etc.
By default, a method defined as method provides $self automatically. no $obj like you're using. That's a variable that's local to you new method, and simply doesn't exist outside that.

In Perl, how do I ensure that a sub is invoked as a method from methods of the same object?

I have a class that has a new method and uses that object to call method X. When I call X from the object the first value of the parameters is $self and the rest are the values I sent in. Now when I call that same method from another method on the object the first value is no longer $self and its just the values being sent in. How do I address this situation?
Sample:
my $p = TEST->new;
$p->mymethod(1,2,3); # #_ = 'self, 1, 2, 3'
but if in 'mymethod' is called by another method:
sub anothermethod{
my ($self, $a) = #_;
mymethod(1,2,3); # #_ = '1,2,3'
}
How do I write 'mymethod' so it handle both situations? Or am I fundamentally doing something incorrect?
Just as you did this:
$p->mymethod(1,2,3);
you need to be explicit about what object you are calling the method on (even within the class):
$self->mymethod(1,2,3);
This is Not A Good Idea (you ought to decide whether a subroutine is a method or not and use it in a consistent way), but in moments of weakness I have used constructions like:
sub subroutine_that_may_get_called_like_a_method {
shift if ref $_[0] eq __PACKAGE__;
my ($param1, $param2) = #_;
...
}
sub method_that_may_get_called_like_a_subroutine {
unshift #_, __PACKAGE__ if ref $_[0] ne __PACKAGE__
my ($self, $param1, $param2) = #_;
...
}
Usually I can only stare at this code for a few hours before the shame pools in my gut and I have to fix it.

How to write a function reference in a Perl module?

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);