in reply to Calling subroutine in a package from other perl sub.

Here is an example.

test1.pl
sub hello_world { print "Hello World!\n"; } 1;
test2.pl
#!/usr/bin/perl -w use strict; require 'test1.pl'; &hello_world;
Output
Hello World!

I havent ever used this practice in my own code. I believe it is better to use as a module. Otherwise if Im not wrong, they will be in the same package and you are more likely to clobber your data in one file with data in the other file.

You could ofcourse declare them in seperate packages. But then you might as well make it a module.

zzSPECTREz

Replies are listed 'Best First'.
Re (tilly) 2: Calling subroutine in a package from other perl sub.
by tilly (Archbishop) on Jan 16, 2001 at 17:37 UTC
    It is a dangerous style to call functions with the
    &hello_world;
    notation because (as perlsub mentions) you get an implicit argument list passed that you probably did not intend.

    Also note that just calling something a module doesn't give you any protection if it doesn't use a package statement internally. When loading stuff from a file that doesn't use package you can always do it yourself by declaring a package and then using do to load it.

    # Loads a file into a package. sub load_lib { my $file = shift; my $pkg = shift; my $ret = eval "package $pkg; do '$file';"; if (not defined($ret)) { $@ and confess("Cannot parse '$file': $@"); $! and confess("Cannot load '$file': $!"); warn("Loading '$file' did not return a defined value"); } $ret; }
    Note that the semantics here are slightly more generous than Perl's requirements of a module. I only warn if you don't get a defined value back. But the reason that I do this is that if it doesn't return something defined I cannot tell the difference between a system error caused executing the file and a system error caused by trying to read the file.

    If that restriction bothers you, you can explicitly read the file's contents into a string with the package prepended and do your own eval of that. You may wish to look at the advice at the end of perlsyn on how to control the output of the error message though. (Put the package before the preprocessor message. There is a bug in 5.005 that causes a preprocessor message on the first line of an eval to be ignored. Besides which you need to do this to make the line-number you get be reasonable. :-)

    Note that none of these solutions will help much if you have a script that does an exit somewhere. There are ways to override that, but if you are getting to this kind of detail, you probably wanted to make stuff into a module. :-)

      I never quite understood why this is considered dangerous style. This is the old style of calling subroutines. If you do not predeclare you subs then you either have to &sub or sub() to not get a bareword error with use strict

      When you call a subroutine like &sub I understand that you are passing the value of @_ to the sub or the equivalent of sub(@_). If you call sub(), you instead are passing a null list. But exactly how is passing @_ dangerous if the sub is not using any passed variables?

      I think not knowing the following is more dangerous.

      #!/usr/bin/perl -w use strict; my @test = ("one","two","three"); my $x = "one"; my $y = "two"; my $z = "three"; test1($x,$y,$z); print "$x\n$y\n$z\n\n"; test2($x,$y,$z); print "$x\n$y\n$z\n"; test1(@test); print join "\n", @test, "\n"; test2(@test); print join "\n", @test, "\n"; sub test1 { my $x1 = shift; my $y1 = shift; my $z1 = shift; $_[0] = "test1: 1"; $_[1] = "test1: 2"; $_[2] = "test1: 3"; } sub test2 { my ($x2,$y2,$z2) = @_; $_[0] = "test2: 1"; $_[1] = "test2: 2"; $_[2] = "test2: 3"; }
      Output:
      one two three test2: 1 test2: 2 test2: 3 one two three test2: 1 test2: 2 test2: 3

      Someone mind explaining this? In more detail than " '@_' is a local array, but its elements are aliases for the actual scalar paramters." What really gets me is how useing shift changes the behavior! Why?

      zzSPECTREz

        First of all it is dangerous because the possibility for confusion is high. Sure, you may know to do it only when the called subroutine is unwilling to take arguments, but will the person who learns from your code know that?

        As for your cute test function, it is really simple. Perl scalars are always references to data, not the actual data. So if you want to convert a list of scalars into a list, it is substantially more efficient to just make a list of pointers to the data than really copy. And that is what Perl does when passing data into a function. However when you assign in Perl you assign by value, not reference.

        So your 3 variables coming in are really passed in by reference, so in test2 you are able to change the original variables (whether the originals were from a scalar or an array) through the references. (ie @_ is just a list of pointers back to the original variables.) In test1 you threw away the three references and then assigned to new variables. Well if you no longer have the three variables, then assigning to new ones won't change a thing.

        And as you note this works just as well if you have the original argument list being 3 variables or an array with 3 things.

        So the rule is that assignment is by value, and arguments are passed into functions by reference. You probably understand this correctly if you can puzzle out the following example:

        ($x, $y, $z) = 'x'..'z'; print "Original values.\n"; show_vals(); print "This rotates them.\n"; rotate($x, $y, $z); show_vals(); print "Why doesn't this?\n"; rotate_not($x, $y, $z); show_vals(); sub rotate { @_[-1..($#_-1)] = @_; } sub rotate_not { @_ = @_[-1..($#_-1)]; } sub show_vals { print "\$x: $x\n\$y: $y\n\$z: $z\n\n"; }

        A bit of a different explanation...

        Let's pretend we are in Perl4 so there are no \ and -> operators to deal with references so we can use them to talk about how Perl itself deals with aliases.

        Then calling test($x,$y,$z) sets @_ to (\$x,\$y,\$z). So if you do $_[0]= "new val" without having modified @_ then you end up doing ${\$x}= "new val" because Perl will see that $_[0] currently contains a reference to (alias of) $x and so modifying $_[0] also modifies $x.

        Well if you do my $x1= shift then you are left with @_ containing (\$y,\$z). Do that two more times and @_ is empty. So $_[0]= "new val" ends up putting a value into @_ where no value was before. So there is no reference (alias) for Perl to implicitly dereference so, of course, $x is not changed in that case. So you end up with @_ having ("new val") or ("x2","y2","z2") and @_ just gets thrown away in the end.

        Also, when @_ is empty, doing $_[0]= "x" finds $_[0] not being an alias to anything and so creates a new scalar and sets $_[0] to be an alias to it (the only alias at that point).

        I hope that helps some.

        Update: And calling test(@v) sets @_ to (\$v[0],\$v[1],\$v[2]) (if @v has three elements) (which could be written as \(@v) in Perl5). But doing @_= @v copies the values rather than making aliases.

                - tye (but my friends call me "Tye")
Re: Re: Calling subroutine in a package from other perl sub.
by eg (Friar) on Jan 16, 2001 at 14:40 UTC

    and if you use do rather than require, you don't even need the first file to return true.

    But I agree with zzSPECTREz, it's probably best to make it a module and import whatever you need.