Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

list return from Inline::Perl5 gives a count of items, not the list

Tags:

perl

raku

Some simple Inline::Perl5 code returns a list, but it seems to return the count of the items rather than the actual list.

Changing the number of items involved changes the count.

use Inline::Perl5;                                             
my $p5 = Inline::Perl5.new;                                    
                                                               
my $perl5_code = q:to/END/;                                    
   sub p5_data {                                               
      my @monsters = qw( godzilla blob tingler kong dorisday );
      return @monsters;                                        
   }                                                           
                                                               
   p5_data();                                                  
END                                                            
                                                               
my @stuff = $p5.run: $perl5_code;                              
say @stuff; # [5]                                              

I thought I'd get the list of strings stored in the array, but instead it acts like something is switching it to scalar context.

Update:

ikeami points out that it works better to return the reference to the array:

return \@monsters;

Though, then you end up with an array in the first element of the @stuff array when you do this:

my @stuff = $p5.run: $perl5_code;                              

An alternate approach (from reading the Inline::Perl5 docs), is after doing a $p5.run to define the perl5 sub, to call it from perl6:

my @stuff = $p5.call('p5_data');  

Then the list return (return @monsters;) gets loaded into the array as I expected:

[godzilla blob tingler kong dorisday]

This is a recently installed Inline::Perl5 of version 0.40, on "Rakudo Star version 2019.03.1 built on MoarVM version 2019.03 implementing Perl 6.d".

Update2: So, it seems that "run" implies a scalar context and "call" is a list context.

use Inline::Perl5;
my $p5 = Inline::Perl5.new;

my $perl5_defsub = q:to/END/;
   sub whadaya_want {
       wantarray() ? 'LIST' : 'SCALAR';
   }
END

$p5.run: $perl5_defsub;

my $run_context  = $p5.run(  'whadaya_want' );
my $call_context = $p5.call( 'whadaya_want' );  

say "run: ", $run_context;
say "call: ", $call_context;
# run: SCALAR
# call: LIST
like image 979
Joseph Brenner Avatar asked Jul 02 '19 02:07

Joseph Brenner


2 Answers

Perl5::Inline puts return values into scalar context.

As background, in Perl 5, context flows inwards into routines, so a routine always knows which context it's in.

In Perl 6, context flows outwards, so a routine returns an object that can behave differently in different context.

This impedance mismatch between Perl 5 and Perl 6 means that Inline::Perl5 has to decide to call Perl 5 routines in one context, and that's scalar.

As ikegami pointed out, the proper solution is to return a proper scalar, aka reference (in Perl 5 speak). Limitations in Inline::Perl5 might mean you need to explicitly dereference on the Perl 6 side.

like image 126
moritz Avatar answered Oct 22 '22 10:10

moritz


Moritz's answer is excellent and explains IP5's dilemma. But niner is ingenious, so IP5 provides all the variations one needs:


  • Call a Perl sub in list context:

    Inline::Perl5.new.call: 'subname', arg1, arg2 ...
    

    See IP5: Call a Perl function.


  • Call a Perl sub in scalar context:

    Inline::Perl5.new.run: 'subname arg1, arg2 ...'
    

    or

    EVAL 'subname arg1, arg2 ...', :lang<Perl5>
    

    See IP5: Run arbitrary Perl code.


  • Call a Perl method in list context:

    Use regular Raku syntax:

    $perl-object .foo: arg1, arg2 ...
    

    to call the foo method on a Perl object held in $perl-object passing it arg1 and arg2 as its first two arguments (ignoring the invocant).

    See IP5: Invoke a method on a Perl object.


  • Call a Perl method in scalar context:

    Use regular Raku syntax but insert Scalar as the first positional argument (ignoring the invocant):

    $perl-object .foo: Scalar, arg1, arg2 ...
    

    to call the foo method on a Perl object held in $perl-object passing it arg1 and arg2 as its first two arguments.

    IP5 removes the Scalar before calling the Perl method.

    See IP5: Invoking a method in scalar context.


Dealing with the Inlines

I think Moritz's answer was a solid resolution of the question, and that mine has rounded it out.

But what if you're reading this and are interested in, or dealing with, other Inline issues?

The sections starting at What to expect when using foreign language adaptors of my answer to Raku: getting array ref for Perl Module are an attempt to outline a mini generic guide on what to expect, and how to deal with problems, relative to Raku's Inlines.

like image 31
raiph Avatar answered Oct 22 '22 10:10

raiph