Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

List::MoreUtils and require

by Tanktalus (Canon)
on Jun 27, 2006 at 23:19 UTC ( [id://557894]=perlquestion: print w/replies, xml ) Need Help??

Tanktalus has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to make some changes to a module, and thought that for version comparison, I could take advantage of List::MoreUtils's each_array function. However, not needing List::MoreUtils in all cases, I thought I'd just require it only when needed. No go. First, the code. The original is a mess, and not even mine, so I'm not going to finger the guilty party. However, I did get it down to a nice, small test case.

#!/usr/bin/perl use strict; use warnings; require List::MoreUtils; # use List::MoreUtils (); my @v1 = qw(4 0 0 3); my @v2 = qw(4 0 0 3); my $ea = List::MoreUtils::each_array(@v1, @v2); while (my ($v, $t) = $ea->()) { }
If you run this, and your system has the same problem as mine, you'll get:
$ perl ./tst.pl Segmentation fault
If, however, you switch it to use, even explicitly importing nothing (which I think is the default anyway), the seg fault goes away.

Switching to use the pure-perl implementation may fix this as well - but that seems like as much of a work-around as just using use.

Can anyone confirm that this is a general problem, and not just my machine?

Replies are listed 'Best First'.
Re: List::MoreUtils and require
by Sidhekin (Priest) on Jun 27, 2006 at 23:50 UTC

    Prototype and late loading don't run well together. Add XS into the mix, and you get a segfault instead of an error message. Bug? Anyway, workarounds for the original problem:

    (1) Bypass prototype (ugly):

    my $ea = &List::MoreUtils::each_array(\@v1, \@v2);

    (2) Late compilation w/string eval (somewhat ugly, unnecessary compilation):

    my $ea = eval q{ use List::MoreUtils; List::MoreUtils::each_array(@v1, @v2) };

    (3) Declare the prototype yourself (might break(?) if List::MoreUtils upgrades behind your back):

    sub List::MoreUtils::each_array(\@;\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\ +@\@\@\@\@\@\@); my $ea = List::MoreUtils::each_array(@v1, @v2);

    print "Just another Perl ${\(trickster and hacker)},"
    The Sidhekin proves Sidhe did it!

      Could you also call import() after the require as a workaround ?
      require List::MoreUtils; List::MoreUtils::import(); # or List::MoreUtils->import() ?

      ...reality must take precedence over public relations, for nature cannot be fooled. - R P Feynmann

        Could you also call import() after the require as a workaround ?

        Not as such, since import just aliases the symbols in your own namespace. Doing that at runtime means it is too late to get the prototype checking. But ... ouch ... you could use that as a way to implicitly bypass prototype checking:

        List::MoreUtils->import('each_array'); my $ea = each_array(\@v1, \@v2);

        I prefer being explicit when bypassing prototype checking though -- the flip side to not using that '&' sigil unless you mean it, is to make sure you do use it when you finally do mean it!

        print "Just another Perl ${\(trickster and hacker)},"
        The Sidhekin proves Sidhe did it!

Re: List::MoreUtils and require
by shmem (Chancellor) on Jun 27, 2006 at 23:34 UTC
    Did do segfault on Linux & *BSD... setting the environment variable LIST_MOREUTILS_PP to 1 gives:
    each_arrayref: argument is not an array reference at 557894.pl line 11
    XS code chokes. hmm. unsetenv LIST_MOREUTILS_PP and then...
    #!/usr/bin/perl use strict; use warnings; require List::MoreUtils; # use List::MoreUtils (); my @v1 = qw(4 0 0 3); my @v2 = qw(4 0 0 3); my $ea = List::MoreUtils::each_array(\@v1, \@v2); while (my ($v, $t) = $ea->()) { print "$v => $t\n"; }
    yields
    4 => 4 0 => 0 0 => 0 3 => 3

    cheers,
    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: List::MoreUtils and require
by ioannis (Abbot) on Jun 27, 2006 at 23:41 UTC
    The require loads the module at runtime, yet you were trying to reference one of its functions before INIT. Here is one solution:
    use warnings; my @v1 = qw(4 0 0 3); my @v2 = qw(4 0 0 3); INIT { require List::MoreUtils; my $ea = List::MoreUtils::each_array(@v1, @v2); while (my ($v, $t) = $ea->()) { } }
Re: List::MoreUtils and require
by GrandFather (Saint) on Jun 27, 2006 at 23:27 UTC

    I reproduced the problem using AS Perl 5.8.7 under Windows XP (it didn't say segmentation fault, but that's what it meant :).


    DWIM is Perl's answer to Gödel
Re: List::MoreUtils and require
by ethan (Initiate) on Jul 04, 2006 at 12:39 UTC
    As others have pointed out, this is indeed a problem with prototypes and loading the module at runtime via 'require'. There is no fix for it. What I can possibly do is add some argument checking to each_array making sure that it actually receives references to arrays. However, this is error-prone in a case like this, where the arrays contain array-refs themselves:
    my @ary1 = ( [1, 2], [3, 4]); my @ary2 = ( [4, 5], [6, 7]); my $ea = List::MoreUtils::each_array(@ary1, @ary2);
    The correct solution for this problem here is to use each_arrayref, and passing in explicit references: my $ea = List::MoreUtils::each_arrayref(\@ary1, \@ary2); This is no longer as idiomatic, unfortunately. I will add a note to the documentation about this in the next reAs others have pointed out, this is indeed a problem with prototypes and loading the module at runtime via 'require'. There is no fix for it. What I can possibly do is add some argument checking to each_array making sure that it actually receives references to arrays. However, this is error-prone in a case like this, where the arrays contain array-refs themselves:
    my @ary1 = ( [1, 2], [3, 4]); my @ary2 = ( [4, 5], [6, 7]); my $ea = List::MoreUtils::each_array(@ary1, @ary2);
    The correct solution for this problem here is to use each_arrayref, and passing in explicit references:
    my $ea = List::MoreUtils::each_arrayref(\@ary1, \@ary2);
    This is no longer as idiomatic, unfortunately. I'll add a warning about this problem in the next release.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://557894]
Approved by GrandFather
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (6)
As of 2024-03-28 19:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found