CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Intermediate:
Non-package functions inside the .pm file

 



rpaskudniak
User


Jul 13, 2010, 1:35 PM

Post #1 of 14 (2774 views)
Non-package functions inside the .pm file Can't Post

Greetings.

Consolidating the help I have received on my previous questions, I am putting together a package to perform my task in an OO manner. In the processing of the data, I have a need for some specialized string functions that do not lend themselves to the package itself. Although they could be written that way - to accept the object reference - they are better represented as independent functions that I will be calling from within my object methods.

I would like to keep these functions inside the .pm file - so that all my stuff stays in one not-too-big source file - but outside the package itself. (ie. After the return 1; in the .pm file.)

Does this violate any protocol or standard within the Perl universe? Would this confuse matters when the caller issues the "use mypackage;" directive?

I'm inclined to think it would be no harm done but some stuff I have read about the difference between "use" and "require" gives me pause.

Guidance needed.

Thank you.
--------------------
-- Rasputin Paskudniak (In perpetual pursuit of undomesticated, semi-aquatic avians)


rovf
Veteran

Jul 14, 2010, 2:16 AM

Post #2 of 14 (2759 views)
Re: [rpaskudniak] Non-package functions inside the .pm file [In reply to] Can't Post


Quote
I would like to keep these functions inside the .pm file - so that all my stuff stays in one not-too-big source file - but outside the package itself. (ie. After the return 1; in the .pm file.)
Does this violate any protocol or standard within the Perl universe?


Except that it is not possible to put a non-lexical *outside* a package (every symbol resides in a package, even if it is just the ::main package), I think the Perl language is anarchic enough to escape any protocol ;-) With other words, it is more a matter of taste than a matter of "standards".

I, personally, put often functions into other packages than "the" package which "belongs" to the .pm file (and some standard modules, such as Class::Struct, even encourage it). Just think where it should go.

However, I would hesitate to put such a function in a completely unrelated package. For exmple, if I have a file Foo/Bar.pm, with package Foo::Bar, I would not put my function f into Baz::f(), but maybe into Foo::Bar::f.

Of course the question is why it doesn't fit into your package. A package doesn't need to have only "object methods". To compare with, say, C++, you can have member functions and non-member functions (i.e. class functions), and both would go well into your package.

Finally, you have, as always, the possibility to inject non-member functions into the name space of the caller. In this case, you would define them inside your package too, but use the exporter to make them available to the calling package without the need of prefixing them with the package name.

Ronald


rpaskudniak
User


Jul 14, 2010, 8:35 AM

Post #3 of 14 (2750 views)
Re: [rpaskudniak] Non-package functions inside the .pm file [In reply to] Can't Post

Ronald,

Thanks for the response. A friend of mine (mainly a C++ programmer) just gave me the name of what I am doing: A helper function - a function meant to be used by the object's methods but not itself a method. It just seemed reasonable to group them all together in the same source file.

I have not tested it it in running but so far it gets a clean compile.

BTW, Is there a way, in this forum, to mark a thread "solved"?
--------------------
-- Rasputin Paskudniak (In perpetual pursuit of undomesticated, semi-aquatic avians)


BillKSmith
Veteran

Jul 14, 2010, 11:27 AM

Post #4 of 14 (2746 views)
Re: [rpaskudniak] Non-package functions inside the .pm file [In reply to] Can't Post


In Reply To


BTW, Is there a way, in this forum, to mark a thread "solved"?



I think you just didSmile.
Good Luck,
Bill


winfinit
User

Jul 14, 2010, 3:30 PM

Post #5 of 14 (2742 views)
Re: [rpaskudniak] Non-package functions inside the .pm file [In reply to] Can't Post

hello,

in perl there are couple of ways to do this, one is just to append _ to the beginning of your "private" method

sub _internal_method { ... }

but that will not stop someone to use it anyways, if you really want to make it private, you can use namespace::clean

use namespace::clean;

no namespace::clean;
sub _error { ... }

##############

so if you do that, then _error will not be available to other users as a part of your module.

-winfinit


rpaskudniak
User


Jul 18, 2010, 9:57 PM

Post #6 of 14 (2703 views)
Re: [rovf] Non-package functions inside the .pm file [In reply to] Can't Post

More growing pains. I'll get this right yet!

Ronald et al,
I'm afraid I need to revisit this issue. I am now testing my new classes (two packages in one .pm file) where the method calls the helper function that is in the same .pm file (but past the return 1;). The constructor (new()) calls helper function matches_meta():

Code
$self->{in_split} = (matches_meta($self->{in_delim})) 
? quotemeta($self->{in_delim}) : $self->{in_delim};

Since matches_meta is not a class method, I am calling it the way one would call a regular subroutine. I get this error:

Quote
Undefined subroutine &UNLbeautifier::matches_meta called at UNLbeautifier.pm line 48.
at UNLbeautifier.pm line 48
UNLbeautifier::new('UNLbeautifier') called at ./beautify-unl.pl line 80


Can anyone tell me what I am doing wrong? The function is clearly defined later in the .pm file, after the definitions of both class. (I did a string search in vi; there is no typo there.)

Thanks much.
--------------------
-- Rasputin Paskudniak (In perpetual pursuit of undomesticated, semi-aquatic avians)


rpaskudniak
User


Jul 19, 2010, 3:16 PM

Post #7 of 14 (2687 views)
Re: [rpaskudniak] Non-package functions inside the .pm file [In reply to] Can't Post

Looking at some instances I have been able to find on the 'net, I realize what the engine thinks I am doing. Let's have another look at that error message:


Quote
Undefined subroutine &UNLbeautifier::matches_meta called at UNLbeautifier.pm

I believe that syntax means it is looking for method matches_meta, a method of class UNLbeautifier. However, as I have stated, matches_meta is just a vanilla subroutine, not a class method.

This refines my question to:
  • Why does the Perl engine think I am calling a method? (Would it make the same mistake if I called substr?)

  • How can I tell Perl this is a vanilla function, not a class method?

  • Thanks much for any help here. I don't see how I could word ths for a search of the perldoc.
    --------------------
    -- Rasputin Paskudniak (In perpetual pursuit of undomesticated, semi-aquatic avians)


    rovf
    Veteran

    Jul 21, 2010, 4:33 AM

    Post #8 of 14 (2653 views)
    Re: [rpaskudniak] Non-package functions inside the .pm file [In reply to] Can't Post

    Be careful not to take C++ concepts literally into Perl. C++ has namespace and class as different concepts, while Perl has only package for both purposes. In C++, I could choose between making the helper function a private static member of the class, or put it in a separate namespace, but in the same source file as the class (and I could think of good arguments for doing it either way). In Perl, the best place of a helper function is to put it into the same package. Just make it clear in your documentation, that it is not intended to be used outside.

    If you are really paranoid about someone misusing your helper function, you could bind it to a lexical:

    my $helperfun = sub { .... }
    ....
    $x = $helperfun->(....);


    rpaskudniak
    User


    Jul 21, 2010, 9:37 AM

    Post #9 of 14 (2649 views)
    Re: [rovf] Non-package functions inside the .pm file [In reply to] Can't Post

    Ronald,

    Having the "helper" used outside the class is the least of my worries; it is unlikely anyone else would have use for these functions. My problem here is that I can't call it from inside the class! The function, as I have placed it, is inaccessible to the class; the engine thinks I am calling an undefined class method (Undefined subroutine) when I'm simply trying to call a function that happens to be outside the confines of the class definition (albeit in the same source file).

    If I have to mess with name spaces to make this work, so be it and I will have learned something valuable (provided someone is willing to show me how). I could cave in and make it a class method but then I will have learned nothing from this setback. I really want to be able to do these things as I see fit.

    My next brainstorm will be to place the function within the confines of the class definition - before the

    Code
    1;

    though I think I'll start with placing a prototype in there first. It still won't be the way I like it because IMO it does not belong there, but it's worth a try. But if its first parameter comes in as a class reference - like a class method - I'll know it was the wrong approach.

    Thanks for the helpful advice so far. Once I have my first package successfully running, you will have created a monster! [:--|]=| (That's my attempt at a Frankenstein smiley.)
    --------------------
    -- Rasputin Paskudniak (In perpetual pursuit of undomesticated, semi-aquatic avians)


    rpaskudniak
    User


    Jul 21, 2010, 5:02 PM

    Post #10 of 14 (2636 views)
    Re: [rpaskudniak] Non-package functions inside the .pm file [In reply to] Can't Post

    (Sighhh...) Well, that blew up plenty fast. Placing the function within the confines of the class definition helped not at all. I did do something a bit more interesting, however: I added these three lines into the main of my program:

    Code
    use Data::Dumper; 
    ...
    print Data::Dumper->Dump([\%main::], ["main"]), "\n==============\n";
    print Data::Dumper->Dump([\%UNLbeautifier::], ["UNLbeautifier"]), "\n";

    Now, the output of the second dump() is more relevant (and mercifully, much shorter).

    Quote
    $UNLbeautifier = {
    'print' => *UNLbeautifier::print,
    'UNL_add_line' => *UNLbeautifier::UNL_add_line,
    'import' => *UNLbeautifier::import,
    '()' => *{'UNLbeautifier::()'},
    '(%=' => *{'UNLbeautifier::(%='},
    '(+=' => *{'UNLbeautifier::(+='},
    'UNL_add_parsed_line' => *UNLbeautifier::UNL_add_parsed_line,

    'BEGIN' => *UNLbeautifier::BEGIN,
    'matches_meta' => *UNLbeautifier::matches_meta,
    'new' => *UNLbeautifier::new,
    'UNLbeautifier_line' => *UNLbeautifier::UNLbeautifier_line,
    'OVERLOAD' => *UNLbeautifier::OVERLOAD
    };

    This confirms my theory: The symbol matches_meta has been defined as part of the UNLbeautifier package but the subroutine just ain't there.

    Brainstorm: When I define the subroutine in UNLbeautifier.pm, as well as calling it, use this form:

    Code
    sub main::matches_meta {...} 
    ...
    $self->{in_split} = (main::matches_meta($self->{in_delim}))
    ? quotemeta($self->{in_delim}) : $self->{in_delim};

    With many expressions of grumpiness Frown, IT WORKED! Cool No crash!!

    This is soooo nuts! Tongue (And, apparently, so am I to even think of this.)

    There has got to be a cleaner way to accomplish this. Still, I can't dispute success too much.

    Thoughts?
    --------------------
    -- Rasputin Paskudniak (In perpetual pursuit of undomesticated, semi-aquatic avians)


    rpaskudniak
    User


    Jul 21, 2010, 8:41 PM

    Post #11 of 14 (2628 views)
    Re: [rpaskudniak] Non-package functions inside the .pm file [In reply to] Can't Post

    Better solution to this problem: leave the call without qualification but when I define the subroutine, use:

    Code
    sub UNLbeautifier::matches_meta {...}

    Though not perfect IMO, it is cleaner and less kludgey that my previous solution. However, now that I have passed this hurdle, this thread's brother, Multiple packages in one module file (.pm) is having a similar problem with a class method calling the constructor of the other class. I will post the problem there, if I don't work around it.

    Looks like if y'all allow me to rant alone for a while, I'll figure something out..
    --------------------
    -- Rasputin Paskudniak (In perpetual pursuit of undomesticated, semi-aquatic avians)


    rpaskudniak
    User


    Jul 22, 2010, 10:43 PM

    Post #12 of 14 (2521 views)
    Re: [rpaskudniak] Non-package functions inside the .pm file [In reply to] Can't Post

    Ever get the feeling you're talking to yourself? Crazy Still, I seem to be giving myself sound advice. Cool

    OK, I've got it working but I don't know why. There was one subroutine I was forced to qualify when I defined it:

    Code
    sub UNLbeautifier::matches_meta {...}

    That way, I was able to call it from within the method. However, another non-packaged subroutine, also called from within that same method, did not require this extra qualification. (And a function that it called certainly did not require qualification.) I would like to examine this apparent inconsistency.

    Any ideas out there?

    Thanks much.

    I have it working now, though there is some rather involved code I would like to move out of one method and into another (to be called by this one).
    --------------------
    -- Rasputin Paskudniak (In perpetual pursuit of undomesticated, semi-aquatic avians)


    rovf
    Veteran

    Jul 23, 2010, 3:54 AM

    Post #13 of 14 (2502 views)
    Re: [rpaskudniak] Non-package functions inside the .pm file [In reply to] Can't Post


    Quote
    I can't call it from inside the class!


    Can't be. If you have defined it within your package, it will be accessible. Maybe you made a mistake at the call site? Can you post a minimal code example which demostrates the error? Actually, from Perl's viewpoint, there is no difference between a "helper function" and a "member function". You just have functions, and the way of calling them distinguishes whether or not a reference to the class (i.e. what is called
    this in C++) is passed to the function.


    rpaskudniak
    User


    Jul 30, 2010, 9:29 AM

    Post #14 of 14 (2400 views)
    Re: [rovf] Non-package functions inside the .pm file [In reply to] Can't Post

    Ronald,
    I wish to thank you for your help in guiding me out of my hole. Your explanations have been a great help to me.

    For the public record:
    I had envisioned my module in 3 parts:
  • Package UB

  • Package UB::line

  • Utility Functions to be called from either package


  • My main stumbling block was the mistaken impression that there I could end a package declaration with the "1;" . The correct meaning of the 1; is to return to the module that invoked this module; only one "1;" is needed and that is at the end of the module, after all packages have been declared.

    Thus, because my utility subroutines were physically located after the declaration of the second package [in the .pm file], they were all automatically located in namespace of that second package. Hence, when I called one of them from package UB it could not be found; Perl was looking for UB::first_function when, as far as Perl could see, first_function resides in package UB::Line.

    Solution: Create a third package for my utility functions. Now my module is 3 packages:
  • Package UB

  • Package UB::line

  • Package UB::_util, the aforementioned Utility Functions


  • I am not out of the woods yet; in order to be able to access the utility functions I need to either:
  • Qualify every call, like UB::_util::my_func()

  • Use the exporter to inject the functions into the caller's name space.

  • The first option is obviously not clean.
    The second option should be the way to go but it's giving me problems. I'll get into that in a different thread.

    I'd now like to close this thread, since the misunderstanding that inspired it has now been eliminated (making room for bigger and better misunderstandings). Pirate

    Again, thanks much for all the help.
    --------------------
    -- Rasputin Paskudniak (In perpetual pursuit of undomesticated, semi-aquatic avians)

     
     


    Search for (options) Powered by Gossamer Forum v.1.2.0

    Web Applications & Managed Hosting Powered by Gossamer Threads
    Visit our Mailing List Archives