Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

perl module structure

by pwagyi (Monk)
on Mar 30, 2018 at 03:09 UTC ( [id://1212015] : perlquestion . print w/replies, xml ) Need Help??

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

Hi wise monks!

I am not totally new to perl and modules. Mostly I've been a user of modules and I am writing some modules and planning to upload to CPAN. I have some experience writing simple perl module (.pm) files and using them straightaway in my own application. Now I'm learning to use tools like h2xs, module-maker to develop proper (standard) way of doing things. I have read module tutorials on 'perlmonks'. So the question is how do I structure my module if I would like to separate interface and implementations?

Let's say I've Foo::Bar and client will only use Foo::Bar. but Foo::Bar is just interface and there may be multiple concrete implementations. (maybe something like DBI, IOHandle?) So Foo::Bar::Implementation1 and Foo::Bar::Implementation2 maybe developed by different developers. Does that mean one developer will be writing his/her own h2xs Foo::Bar::Implementation ?

Replies are listed 'Best First'.
Re: perl module structure (Façade choosing backend)
by LanX (Saint) on Mar 30, 2018 at 10:52 UTC
    That's a rather abstract question. More concrete examples would be nice.

    I was thinking bout examples which do "similar" things, and Term::ReadLine or JSON come to mind, which can switch between different backends.

    My (maybe naive) approach would be to have a 2 modules for the start, a default implementation Foo::Bar::Standard for fall back and a façade Foo::Bar which exports the API functions which call those standard implementation functions.

    Something like use Foo::Bar "Other"; would first import the functions of Foo::Bar::Other into package Foo::Bar instead of those from Standard before exporting the interface.

    Another approach to access the implementation from Foo::Bar is of course to manipulate @ISA. The interface functions would access the implementation by inheritance.

    I'm sure there are even more OOP patterns to do this and curious to read more replies.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Wikisyntax for the Monastery

    update

    Your mention of h2xs is puzzling me. Are you talking about C implementations?

      Yes it’s rather abstract because I’m looking for general solution. I think what I’d like to do is something similar to java collection. List is an interface and there are multiple concrete implementations. So I might have pure perl and xs backend implementations. I just remember there’re some Perl modules if xs is available it’ll use xs backend implementation otherwise using pure perl.

      Update

      Design pattern wise, I am thinking of abstract factory pattern. There’ will be factory, products interfaces and of course actual concrete implementations.

        > I’m looking for general solution

        Sorry, this sounds like you are looking for a way to do Java in Perl. Many answers in the Java world don't apply to Perl because the questions don't arise.

        And it's not clear for me HOW the implementation should be chosen. automatically or by users choice.

        > List is an interface and there are multiple concrete implementations.

        Not an issue in Perl because it doesn't have static typing of the list elements.

        > I think what I’d like to do ...

        Please think harder what you want and show some Perl code exemplifying it.

        Most of us don't "speak" Java... ;-)

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Wikisyntax for the Monastery

Re: perl module structure
by trippledubs (Deacon) on Mar 30, 2018 at 14:20 UTC

    There's Java's collections as an example where interface List could represent an AbstractList, AbstractSequentialList, ArrayList, CopyOnWriteArrayList, LinkedList, RoleList, RoleUnresolvedList, Stack, Vector, or something else that implements what a list does, add(), and remove() and whatever else.

    Tree::Binary uses Visitor_pattern to separate interface and implementation. You have Visitor::BreadFirstTraversal and Visitor::InOrderTraversal. Both are called with the visit method.

    You could just pass in a sub reference to your interface containing the implementation.

    #!/usr/bin/env perl use strict; use warnings; use feature 'say'; sub multiply { my ( $x, $y, $implementation ) = @_; $implementation->( $x, $y ); } sub whateverthedefaultis { my ( $x, $y ) = @_; return $x * $y; } # https://blogs.msdn.microsoft.com/matthew_van_eerde/2009/07/23/bad-pe +rl-russian-peasant-multiplication-algorithm/ sub peasant { my ( $a, $b ) = @_; my $c; map { $c += $_ * $b } grep { $a & $_ } map { 1 << $_ } ( 0 .. log($a) / log 2 ); return $c; } say multiply( 7, 3, \&whateverthedefaultis ); say multiply( 7, 3, \&peasant );
    Well I guess multiply should use the default.. by default if a third param is not passed in. Like how sort uses standard string comparison order by default. A whole lotta ways to do it.
Re: perl module structure
by Anonymous Monk on Mar 30, 2018 at 13:20 UTC

      Thanks! this is helpful. I'm familiar with File::Spec. Indeed there are different underlying implementations for different OSes.

Re: perl module structure
by karlgoethebier (Abbot) on Mar 31, 2018 at 13:35 UTC
    "...Does that mean one developer will be writing his/her own ... Foo::Bar::Implementation?"

    I skip the h2xs part because of no clue. Anyway: He/she might think of it (the implementation ) as a kind of plugin. A very simple example - but i think it shows the basic idea. Some say Perl is different. A anon monk linked already to roles...

    Best regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

    perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Re: perl module structure
by Anonymous Monk on Mar 30, 2018 at 13:54 UTC
    Yes, the Java environment is so fundamentally different from Perl that concepts will not transfer easily nor directly from one to another. I would look instead at venerable Perl implementations – DBI very specifically comes to mind. But also, "keep your boots on the ground," which means always knowing what and where the ground is. There is such a thing as over-abstraction, and so your design decisions need to keep concrete implementations in mind. Also consider the many ways in which JSON functionality have been tackled – notice how there are both XS and Pure Perl implementations of things. Also notice how sometimes the onus is upon the individual package consumer to choose a concrete package, whose API might merely be similar among several different concrete alternatives. It is rarely productive to go so far as to say that apples and oranges are abstracted-away as fruits. Perhaps it is good enough to implement several packages with a mostly-identical API and leave it to the consumer to decide which one to use, expecting him also to perhaps take advantage of the slight-differences that you have thoughtfully provided.
    A reply falls below the community's threshold of quality. You may see it by logging in.