niner / Inline-Perl5

Use Perl 5 code in a Raku program
Artistic License 2.0
95 stars 30 forks source link

Add syntactic sugar #4

Closed ghost closed 9 years ago

ghost commented 10 years ago

Making Inline::Perl5 into a Callable backed by a multi-method yields some nice sugar:

my &p5 = Inline::Perl5.new;

# run code
p5 'print "hello world\n"';
p5 q{{{
    use DBI;
    DBI->connect('dbi:Pg:database=timemngt');
}}};

# call sub
p5 :print('hello world\n');

# call method
p5 'DBI', :connect<dbi:Pg:database=timemngt>;

# call methods on the interpreter
p5.DESTROY;

The code implementing this:

method invoke($_) { $.dispatch(|.list, |.hash.pairs) }
multi method dispatch(Str $code) { $.run($code) }
multi method dispatch(Pair (:$key, :$value)) { $.call($key, |$value) }
multi method dispatch($obj, Pair (:$key, :$value)) { $.send($obj, $key, |$value) }
multi method dispatch() { self }

Note that instead of invoke, send needs to be used for method calls as the former is used by Rakudo internally.

There are a few things you'd have to keep in mind:

# passing a single array argument flattens
p5 :foo([1, 2, 3]);

# avoid flattening by using a trailing comma
p5 :foo([1, 2, 3],);
moritz commented 10 years ago

Somehow I'm not convinced that this is the right sugar to add. Much of that is only a feeling, but one thing I really don't like is using named arguments, which are inherently unordered, for calling code, which usually cares a great deal about ordering.

I wouldn't reject this entirely, just propose to think of other ways to add syntactic sugar.

This isn't really thought out yet, but maybe one could do

 my $p5 = Inline::Perl5.new;
$p5<DBI>.connect(...);

This would have the advantage of actually mapping a method call to a method call.

I can't think of a good way to map subroutine calls; maybe I'll think of something better in time.

ghost commented 10 years ago

@moritz, what are your thoughts on

$p5.sub<print>("hello world\n");
$p5.pkg<DBI>.connect('...');

or rather

my &print5 = $p5.sub<print>;
print5 "hello world\n";

my \DBI5 = $p5.pkg<DBI>;
DBI5.connect('...');

This would require a more heavy-weight implementation - instead of just using multiple-dispatch, we'd need some objects that act as proxies...

timbunce commented 10 years ago

I know ~zero perl6, and even less about Inline-Perl5, but I'd like to make the observation that it would be helpful to separate compile-time and run-time actions, and try to achieve as much as possible at compile-time. Apart from anything else this is likely to significantly improve performance.

ghost commented 10 years ago

@timbunce, one should of course always be aware of performance implications. However, I don't think there's really all that much you can do at compile time when the perl5 interpreter isn't around. Also keep in mind that arguments are converted between P5 and P6 land on each call, so dispatch will probably be 'heavy' anyway.

timbunce commented 10 years ago

@cygx, I think you've already expressed the kind of thing I was thinking of with your example above, where:

$p5.pkg<DBI>.connect('...');

is purely runtime, whereas the separation of work expressed here:

my \DBI5 = $p5.pkg<DBI>;
DBI5.connect('...');

means that the my \DBI5 = $p5.pkg<DBI>; part could be moved to compile-time. (Where 'compile-time' probably means module-load-time for some hypothetical DBI5 module.)

Essentially I'm just saying that the design of Inline-Perl5 and any sugar layered on top, should enable and emphasise pre-caching as much work as possible.

The saving might seem relatively small at the moment but 'every little helps'. Data conversions between P5 and P6 are bond to get faster over time in which case the relative cost of the overheads goes up.

niner commented 9 years ago

We nowadays have:

!perl6

use DBI:from; my $dbh = DBI.connect(...);

I think it doesn't get any sweeter than that :) Though if there are suggestions, I'd certainly be interested. Is there a concensus that we can close this issue?

niner commented 9 years ago

As a uni professor of mine used to say: silence is acceptance. With use :from and EVAL :lang I think we have all the sugar we can get.