Passing variables through functions - perl

When I pass a variable through a couple of subs, it always turns up empty. Why is this ?
sub Main {
my $myVariable = "Test string";
firstSub($myVariable);
}
sub firstSub {
my($myVariable) = #_;
my #array = `some command`;
secondSub(#array, $myVariable);
}
sub secondSub {
my(#array, $myVariable) = #_;
print $myVariable;
}
echo will be undef.

echo is not a valid Perl function. You're confusing shells with Perl here. Try "print" or "say" (the latter with Perl 5.10 and newer).
Also you cannot assign an array & a scalar variable to another array & scalar variable. Meaning this won't work because all of the elements of the right-hand side will be assigned to the array on left-hand side, and nothing will be assigned to the scalar: my (#array, $myVariable) = #_; Either swap the order of the elements my ($myVariable, #array) = #_; (also when calling the function) or use array references instead of full arrays.

Your code doesn't do anything because you have defined three subroutines, but you have never called them.
Just add Main(); to actually run your main sub.
Also, you need print instead of echo.
Also, the passing of variables is incorrect, as Moritz Bunkus explained.

When you call secondsub() the #array and the $myVariable is being sent as a list(a single element) and is been assigned to #array in the secondsub function. You can see both the #array and $myVariable values when you print #array in secondsub.
You have to pass the array as a reference and receive it as a scalar value in secondsub. The below code will work.
&Main();
sub Main {
my $myVariable = "Test string";
firstSub($myVariable);
}
sub firstSub {
my($myVariable) = #_;
my #array = `some command`;
secondSub(\#array,$myVariable);
}
sub secondSub {
my($ref,$myVariable) = #_;
print $myVariable;
}

Passing varibles:
my $txt = "this text for sample";
Function_Passing_varible($txt);
sub Function_Passing_varible{
my $text = shift;
print $text;
}
I think you like this answer......

Related

How to access hash from object

I have written a small class which just got some getter and setter methods. One of those Properties is a hash.
sub getMyData
{
my $objekt = shift;
return $objekt->{MYDATA};
}
sub setMyData
{
my $objekt = shift;
my %myData= shift;
$objekt->{MYDATA} = \%myData;
}
If i set the value like this in another skript which access my class:
my %test;
$test{'apple'}='red';
$objekt = MYNAMESPACE::MYCLASS->new;
$objekt->setMyData(%test);
I thought i can access this value easy via:
my $data = $objekt->getMyData;
print $data{'apple'};
I just get undef value.
Output from Dumper:
Can someone tell me what's wrong here and how i can access getMyData and print the value 'red'?
shift removes and returns the first element of an array. Inside of a subroutine a bare shift operates on #_, which contains a copy of all arguments passed to that subroutine.
What is really happening here is that setMyData is being passed this data:
setMyData($objekt, 'apple', 'red');
The first shift in setMyData removes $objekt from #_
The second shift in setMyData removes 'apple', but since you assign the result of this shift to a Hash it creates a Hash that looks like this: 'apple' => undef
You take a reference to this Hash and store it in the MYDATA key of $objekt
What you really want is to assign the remainder of #_ to your Hash:
sub setMyData {
my $objekt = shift;
my %myData = #_;
# my ($objekt, %myData) = #_; (alternative)
$objekt->{MYDATA} = \%myData;
}
Another option is to instead send a Hash reference to setMyData, which would work with shift:
sub setMyData {
my $objekt = shift;
my $myData_ref = shift
$objekt->{MYDATA} = $myData_ref;
}
$objekt->setMyData(\%test);
You are missing the dereference arrow. Because you put a hashref (\%myData) in, you also get a reference out.
my $data = $objekt->getMyData;
print $data->{'apple'};
# ^
# here
You also need to change the assignment, because you are passing a list to the setter, not a reference. shift is for scalar (single) values, but %test gets turned into a list (many values).
sub setMyData
{
my $objekt = shift;
my %myData = #_;
$objekt->{MYDATA} = \%myData;
}
However, there are a few more issues with your code.

Passing argument to a Perl class subroutin

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

Trouble passing hash and variable to subroutine

I want to pass a hash and a variable to a subroutine:
%HoA = {'1'=>'2'};
my $group_size = 10;
&delete_unwanted(\%HoA,$group_size);
sub delete_unwanted {
my (%HoA,$group_size) = #_;
print "'$group_size'\n"
}
But, this prints nothing.
You're passing a hash reference (as you should), so therefore assign it to a scalar in your parameter catching:
sub delete_unwanted {
my ($hashref, $group_size) = #_;
print "'$group_size'\n"
}
If you later want to dereference it, you can my %newHoA = %$hashref;, but that will be a copy of the original hash. To access the original structure, just use the reference: print $hashref->{a_key};.
Your problem is in:
my (%HoA,$group_size) = #_;
You can solve it by saying, for example:
sub delete_unwanted {
my $hashPointer = shift;
my $group_size = shift
Note that you can retrieve the original hash inside the subroutine by either: de-referencing the hashPointer (my %HoA = %$hashPointer), or you can access the hash contents directly using the pointer directly (eg, $hashPointer->{'key'})

Creating a dynamic Perl function which uses a variable's value at time of function declaration

I'd like to create a dynamic function that uses (evaluates?) the value of a variable at the time the function is declared.
The example below requires $var to exist as a global variable so it can be used when the function is invoked:
my $var = 'something';
someFunction(sub { return $_[0] eq $var; });
but I'm guessing there is some way to create the dynamic function so it is declared like this:
someFunction(sub { return $_[0] eq 'something'; });
How can I do that!? :)
A little sloppy, but it works:
#!/usr/bin/env perl
use warnings;
use strict;
my $var = 'something';
my $f1 = sub { my $v = $_[0]; return sub { return $_[0] eq $v } };
my $f2 = $f1->($var);
$var = 'other thing';
print $f2->('something');
With lambda, all things are possible.
How about capturing a local copy of it?
someFunction( do { my $v = $var; sub { $_[0] eq $v } } );
That way, even if $var is later modified, the anonymous sub is still using its local copy of it from with the original value.
What's wrong with an old, simple, straight closure?
sub genf { my $v = shift; sub { shift eq $v } }
my $f = genf('something'); # Or genf($var)
print &$f('something');
print &$f('another thing');
Like the others, I think that a closure is fine for this purpose. I wouldn't even be surprised if the compiler can optimize it down to what you expect, though I don't have the guru-ness to prove it.
Still, I can attempt what you asked, though I don't recommend it.
my $var = 'something';
my $sub = eval 'sub { return $_[0] eq \'' . $var . '\'}';
someFunction( $sub );
You build up the code reference as strings, using the value of $var and then when you eval it, it is compiled to Perl code. Notice that you have to include extra quotes since by the time the code is evaluated, the contents of $var will be a bare string.
Again though, this isn't recommended. Why? Because its dangerous, especially if the content of $var comes from the outside world.

Is there a better way to pass by reference in Perl?

I am doing pass-by-reference like this:
use strict;
use warnings;
sub repl {
local *line = \$_[0]; our $line;
$line = "new value";
}
sub doRepl {
my ($replFunc) = #_;
my $foo = "old value";
$replFunc->($foo);
print $foo; # prints "new value";
}
doRepl(\&repl);
Is there a cleaner way of doing it?
Prototypes don't work because I'm using a function reference (trust me that there's a good reason for using a function reference).
I also don't want to use $_[0] everywhere in repl because it's ugly.
Have you looked at Data::Alias? It lets you create lexically-scoped aliases with a clean syntax.
You can use it to create pass-by-reference semantics like this:
use strict;
use warnings;
use Data::Alias;
sub foo {
alias my ($arg) = #_;
$arg++;
}
my $count = 0;
foo($count);
print "$count\n";
The output is 1, indicating that the call to foo modified its argument.
There are a couple of ways to do this. Explicitly pass a scalar ref to $foo, or take advantage of Perl's built-in pass by reference semantics.
Explicit reference:
my $foo = "old value";
doRepl( \&repl, \$foo );
print $foo; # prints "new value";
sub repl {
my $line = shift;
$$line = "new value";
}
sub doRepl {
my ($replFunc, $foo) = #_;
$replFunc->($foo);
}
Pass by reference:
my $foo = "old value";
doRepl( \&repl, $foo );
print $foo; # prints "new value";
sub repl {
$_[0] = "new value";
}
sub doRepl {
my $replFunc = shift;
$replFunc->(#_);
}
Even fancier pass by reference:
my $foo = "old value";
doRepl( \&repl, $foo );
print $foo; # prints "new value";
sub repl {
$_[0] = "new value";
}
sub doRepl {
my $replFunc = shift;
&$replFunc;
}
The first one use normal perl hard references to do the job.
The first pass by ref method uses the fact that Perl passes arguments to all functions as references. The elements of #_ are actually aliases to the values in the argument list when the subroutine is called. By altering $_[0] in foo(), you actually alter the first argument to foo().
The second pass by ref method use the fact that a sub called with an & sigil and no parens gets the #_ array of its caller. Otherwise it is identical.
Update: I just noticed you desire to avoid $_[0]. You can do this in repl if you want:
sub repl {
for my $line( $_[0] ) {
$line = 'new value';
}
}
sub repl {
my $line = \$_[0]; # or: my $line = \shift
$$line = "new value";
}
I don't think there is anything wrong with using local to create the alias in this case.
Dynamic scope is of course a powerful feature, but so long as you are aware of the side effects (new value is visible in functions called from its scope, if a lexical of the same name is in scope, it can't be localized, ...) then it is a useful addition to the already overflowing Perl toolbox.
The main reason for the warnings in the Perl docs about local are to keep people from inadvertently using it instead of my and to ease the transition from perl4. But there are definitely times when local is useful, and this is one.
Using for to create your alias is also an option, but I find the explicit syntax with local clearer in its intent. It is also a bit faster if performance is a concern.