GithubHelp home page GithubHelp logo

cxw42 / sub-multi-tiny Goto Github PK

View Code? Open in Web Editor NEW
0.0 3.0 1.0 102 KB

Multisub/multimethod (multiple-dispatch subroutine) implementation for Perl

Home Page: https://metacpan.org/pod/Sub::Multi::Tiny

License: Other

Perl 100.00%
multimethods perl multimethod multisub multisubs multiple-dispatch perl5 perl5-module

sub-multi-tiny's Introduction

Build Status

NAME

Sub::Multi::Tiny - Multisubs/multimethods (multiple dispatch) yet another way!

SYNOPSIS

{
    package main::my_multi;     # We're making main::my_multi()
    use Sub::Multi::Tiny qw($foo $bar);     # All possible params

    sub first :M($foo, $bar) {  # sub's name will be ignored,
        return $foo ** $bar;    # but can't match the one we're making
    }

    sub second :M($foo) {
        return $foo + 42;
    }

}

# Back in package main, my_multi() is created just before the run phase.
say my_multi(2, 5);     # -> 32
say my_multi(1295);     # -> 1337

The default dispatcher dispatches solely by arity, and only one candidate can have each arity. For more flexible dispatching, see Sub::Multi::Tiny::Dispatcher::TypeParams.

DESCRIPTION

Sub::Multi::Tiny is a library for making multisubs, aka multimethods, aka multiple-dispatch subroutines. Each multisub is defined in a single package. Within that package, the individual implementations ("impls") are subs tagged with the :M attribute. The names of the impls are preserved but not used specifically by Sub::Multi::Tiny.

Within a multisub package, the name of the sub being defined is available for recursion. For example (using where, supported by Sub::Multi::Tiny::Dispatcher::TypeParams):

{
    package main::fib;
    use Sub::Multi::Tiny qw(D:TypeParams $n);
    sub base  :M($n where { $_ <= 1 })  { 1 }
    sub other :M($n)                    { $n * fib($n-1) }
}

This code creates function fib() in package main. Within package main::fib, function fib() is an alias for main::fib(). It's easier to use than to explain!

FUNCTIONS

import

Sets up the package that uses it to define a multisub. The parameters are all the parameter variables that the multisubs will use. import creates these as package variables so that they can be used unqualified in the multisub implementations.

A parameter D:Dispatcher can also be given to specify the dispatcher to use --- see "CUSTOM DISPATCH".

Also sets "$VERBOSE" in Sub::Multi::Tiny::Util if the environment variable SUB_MULTI_TINY_VERBOSE has a truthy value. If the SUB_MULTI_TINY_VERBOSE value is numeric, $VERBOSE is set to that value; otherwise, $VERBOSE is set to 1.

CUSTOM DISPATCH

This module includes a default dispatcher (implemented in Sub::Multi::Tiny::Dispatcher::Default. To use a different dispatcher, define or import a sub MakeDispatcher() into the package before compilation ends. That sub will be called to create the dispatcher. For example:

{
    package main::foo;
    use Sub::Multi::Tiny;
    sub MakeDispatcher { return sub { ... } }
}

or

{
    package main::foo;
    use Sub::Multi::Tiny;
    use APackageThatImportsMakeDispatcherIntoMainFoo;
}

As a shortcut, you can specify a dispatcher on the use line. For example:

use Sub::Multi::Tiny qw(D:Foo $var);

will use dispatcher Sub::Multi::Tiny::Dispatcher::Foo. Any name with a double-colon will be used as a full package name. E.g., D:Bar::Quux will use dispatcher Bar::Quux. If Foo does not include a double-colon, Sub::Multi::Tiny::Dispatcher:: will be prepended.

DEBUGGING

For extra debug output, set "$VERBOSE" in Sub::Multi::Tiny::Util to a positive integer. This has to be set at compile time to have any effect. For example, before creating any multisubs, do:

use Sub::Multi::Tiny::Util '*VERBOSE';
BEGIN { $VERBOSE = 2; }

RATIONALE

  • To be able to use multisubs in pre-5.14 Perls with only built-in language facilities. This will help me make my own modules backward compatible with those Perls.
  • To learn how it's done! :)

SEE ALSO

I looked at these but decided not to use them for the following reasons:

  • Class::Multimethods

    I wanted a syntax that used normal sub definitions as much as possible. Also, I was a bit concerned by LPALMER's experience that it "does what you don't want sometimes without saying a word" ("Semantics" in Class::Multimethods::Pure).

    Other than that, I think this looks pretty decent (but haven't tried it).

  • Class::Multimethods::Pure

    Same desire for sub syntax. Additionally, the last update was in 2007, and the maintainer hasn't uploaded anything since. Other than that, I think this also looks like a decent option (but haven't tried it).

  • Dios

    This is a full object system, which I do not need in my use case.

  • Logic

    This one is fairly clean, but uses a source filter. I have not had much experience with source filters, so am reluctant.

  • Kavorka::Manual::MultiSubs (and Moops)

    Requires Perl 5.14+.

  • MooseX::MultiMethods

    I am not ready to move to full Moose!

  • MooseX::Params

    As above.

  • Sub::Multi

    The original inspiration for this module, whence this module's name. Sub::Multi uses coderefs, and I wanted a syntax that used normal sub definitions as much as possible.

  • Sub::SmartMatch

    This one looks very interesting, but I haven't used smartmatch enough to be fully comfortable with it.

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc Sub::Multi::Tiny

You can also look for information at:

BUGS

  • It's not as tiny as I thought it would be!
  • This isn't Damian code ;) .

AUTHOR

Chris White [email protected]

LICENSE

Copyright (C) 2019 Chris White [email protected]

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

sub-multi-tiny's People

Contributors

cxw42 avatar

Watchers

 avatar  avatar  avatar

Forkers

manwar

sub-multi-tiny's Issues

Benchmark results

Not really an issue, but thought I'd send you these.

Benchmark source

use v5.16;
use warnings;
use Benchmark 'cmpthese';
use Test::More;

package SMT::test {
	use Sub::Multi::Tiny qw( $foo $bar );
	sub first :M($foo, $bar) {
		return $foo ** $bar;
	}
	sub second :M($foo) {
		return $foo + 42;
	}
}

package M {
	use Kavorka qw(multi fun);

	multi fun test ($foo, $bar) {
		return $foo ** $bar;
	}
	multi fun test ($foo) {
		return $foo + 42;
	}
}

is(M::test(8,2), 64);
is(M::test(3,3), 27);
is(M::test(58), 100);
is(SMT::test(8,2), 64);
is(SMT::test(3,3), 27);
is(SMT::test(58), 100);

cmpthese -1, {
	M    => q{   M::test(3,3);  SMT::test(0); },
	SMT  => q{ SMT::test(3,3);  SMT::test(0); },
};

Results on my laptop:

ok 1
ok 2
ok 3
ok 4
ok 5
ok 6
        Rate  SMT    M
SMT 255999/s   -- -11%
M   286959/s  12%   --

I had expected a bit of a slow down from your use of guards and global variables, but it actually performs at a pretty decent rate.

As you use a stringy eval to build your dispatcher, you could probably speed things up a little by avoiding the hashtable arity lookup thing at run time, and putting if(@_==1) {...} elsif(@_==2) {...} into the evaluated string itself. The only advantage in keeping the hash table lookup would be if you wanted to be able to insert new entries into it at run-time, but right now the hash is a lexical variable, so short of some PadWalker tricks, can't be altered by runtime code anyway.

Permit impls to redispatch to other impls

Maybe add main::my_multi::me that is redirected to the dispatcher at INIT time?

Edit Within a function, let the name the outside world uses as the dispatcher also be available as the dispatcher.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.