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

Is there any way to force List::Util::shuffle to use the srand() & rand() functions from Math::Random::MT?

(The why: I'm trying to analyse a random algorithm that uses shuffling, but would like to get reproducable results and avail myself of a full 32-bit rand.)


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re: Pursuading an XS module to use a routine from another XS module.
by ikegami (Patriarch) on Sep 02, 2008 at 18:48 UTC

    No, there's doesn't appear to be. In some circumstances and probably all circumstances, it calls a C function directly. At the very least, it would require a recompile.

    Your best bets would be to override List::Util::shuffle with your own (XS or PP) version or to provide your own local (XS or PP) version List::Util.

      I've been using a perl shuffle routine, but it is so slow compared to List::Util's version.

      I can re-compile util.xs easily enough, but I'm unsure about how to call a routine located in another XS module from within an XS module. Any thoughts, or examples?


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        Math::Random::MT's rand is actually a Perl function.

        srand is an XS function, so it expects to be called from Perl.

        You'll need to use one of the methods in perlcall in both cases.

        If you wanted to bypass Perl, you'd have to convert MT.pm and MT.xs to C, then compile and link MT.c, the converted code and your version of List/Util.c together.

        I'm unsure about how to call a routine located in another XS module from within an XS module

        One solution - if, in Foo.xs, we want to access a function (let's call it 'bar') from Bar.xs, then we have the Bar module make available a pointer to the bar function. The Foo.xs functions then access the bar function via that pointer.

        I have a full but minimal working demo of this principle on this machine. I could put copies of the files (Foo.pm, Bar.pm, Foo.xs, Bar.xs, Makefile.PL's and test.pl's) on my scratchpad if that's going to serve any purpose. Note that, with this approach, you'll probably be making significant alterations to both source distros. I think it's the best approach to calling xsubs in one extension from xsubs in another extension .... but I'm not so sure that this is the best way for you to achieve your ends in this particular case.

        For a basic demo of passing functions by pointer, here's an Inline::C script that creamygoodness posted a while back:
        use strict; use warnings; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'END_C'; typedef void (*hello_func_t)(SV * x); typedef SV * (*sv_func_t)(SV * x); void hola_mundo(SV * x) { printf("Hola, mundo! %d\n", (int)SvIV(x)); } SV * hola_mundo2(SV *x) { printf("Hola, mundo2! %d\n", (int)SvIV(x)); return newSViv((int)SvIV(x) * 2); } SV* get_hola_mundo_func_ptr() { return newSViv( PTR2IV(hola_mundo) ); } SV* get_hola_mundo2_func_ptr() { return newSViv( PTR2IV(hola_mundo2) ); } void do_hello(SV *sv_with_func_ptr, SV * x) { IV temp = SvIV(sv_with_func_ptr); hello_func_t hello = INT2PTR(hello_func_t, temp); hello(x); } SV * do_hello2(SV *sv_with_func_ptr, SV * x) { IV temp = SvIV(sv_with_func_ptr); sv_func_t hello = INT2PTR(sv_func_t, temp); return hello(x); } END_C my $num = 123458; my $func_ptr = get_hola_mundo_func_ptr(); do_hello($func_ptr, $num); my $func_ptr2 = get_hola_mundo2_func_ptr(); my $ret = do_hello2($func_ptr2, $num); print $ret;
        Cheers,
        Rob