http://qs1969.pair.com?node_id=489566

Greets,

In Java, there are four levels of access: public, package, protected, and private. In Perl, there are effectively two: public, and leading-underscore-private. Unfortunately, the leading underscore is generally understood to mean won't-be-used-outside-this-file, and just because you can break this convention doesn't mean it's a good idea.

In putting together multi-module distros, I have lots of methods, variables, and whole classes which have to be accessed by other classes, and so shouldn't get the leading-underscore treatment -- but they aren't part of the public API. In Java, these would get tagged as package or protected as part of the declaration, making the code self-documenting. Since Perl imposes fewer rules, the only way to indicate that such a component isn't public is to document it as such explicitly.

I'd like to use POD to document these components, but if something's in POD and it doesn't have a leading underscore, the implication is that it's public. So what are the alternatives?

Mark every single component with its access level in the POD? That's verbose, messy and hackish. Nobody does this, for good reason.

Document only with comments? But POD is so much better for long explanations.

Surround =headX tags with =begin comment and =end comment? What a waste of space.

The only thing that seems to make sense is to use =begin comment and =end comment to surround the docs and omit =headX ... =cut. This breaks POD::Coverage, which I don't like at all. Also, this stuff really does belong in extracted documentation -- just with an indication that the documentation is for developers, not users.

Who's got a better way?

--
Marvin Humphrey
Rectangular Research ― http://www.rectangular.com

Replies are listed 'Best First'.
Re: Documenting non-public OO components
by Zaxo (Archbishop) on Sep 06, 2005 at 15:59 UTC

    You can place your internal methods in a Foo::Devel package which acts as a helper module and has its own pod. That will seperate both them and their documentation from the public, while leaving them accessible to all.

    From the sound of it, your modules seem pretty tightly bound to each other. Could a redesign produce a more natural split of responsibilities?.

    After Compline,
    Zaxo

      Well, the big project I'm working on is an overhaul of Plucene, the perl port of the Java Lucene search engine library http://lucene.apache.org/. I'm moving a couple things around, but for the most part it should stay as is, and Lucene's pretty well designed.

      Beyond that, I'm not sure that it makes sense to constrain development via a severe public-class-all-things-public / devel-class-all-things-devel split. You could do that, but there are bound to be occasions when you wish you could add a protected method to that public class. For sure, it's a good idea to divide responsibility, but unless you take draconian measures, the problem still exists.

      --
      Marvin Humphrey
      Rectangular Research ― http://www.rectangular.com
Re: Documenting non-public OO components
by xdg (Monsignor) on Sep 06, 2005 at 16:14 UTC

    Read the docs for Pod::Coverage. You can easily specify additional items to consider private and not needing coverage with also_private. If you don't want to take that extra step, just document them as public or private in the pod, either inline -- or better yet -- in sections marked "PUBLIC METHODS", "PRIVATE METHODS" etc.

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

      in sections marked "PUBLIC METHODS", "PRIVATE METHODS"

      This, I like. :)

      I will be adopting your suggestion. It solves 90% of the problem, since methods occupy most of the protected/package OO terrain.

      --
      Marvin Humphrey
      Rectangular Research ― http://www.rectangular.com
Re: Documenting non-public OO components
by japhy (Canon) on Sep 06, 2005 at 15:52 UTC
    I put my POD at the end of all my code, so I can document things in an order not necessarily found in my code. To this end, I would document the public methods in one group, then the protected in another.

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart

      How would you label a helper/devel class? Here's one technique I've seen:

      =head1 SYNOPSIS No public interface

      However, it would be nice to put something in the SYNOPSIS section, even for a devel class. PRIVATE SYNOPSIS / PUBLIC SYNOPSIS ?

      --
      Marvin Humphrey
      Rectangular Research ― http://www.rectangular.com
        In the synopsis, I would probably be just about as terse as your example; but perhaps a small example would help. I would at least explain the class's purpose in its description, though.

        Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
        How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re: Documenting non-public OO components
by siracusa (Friar) on Sep 07, 2005 at 02:26 UTC

    I recently faced a similar problem: methods that are meant to be used by subclasses, but not by "the public." You can see my solution on CPAN. I created a separate "PROTECTED API" section, and I explained what I meant by "protected" in the "DESCRIPTION" section. I'm not particularly happy with this solution, but at least it's explicit.

      I may end up doing something akin to that. Since Plucene is a large library, I can put the explanation in one central place (probably the main module), then hew to the convention elsewhere. That's way better than what I was considering before; it's nice to see your example.

      --
      Marvin Humphrey
      Rectangular Research ― http://www.rectangular.com
Re: Documenting non-public OO components
by lachoy (Parson) on Sep 06, 2005 at 16:53 UTC

    I don't think private methods should be documented in POD at all, otherwise they're not really private. Inline comments for people actually working on the code should be sufficient.

    I tend to group 'protected' methods in a POD heading called 'SUBCLASSING' or something similar -- basically, "Here's what you can use and what you need to know to write a subclass", which is what protected methods are really for.

    Chris
    M-x auto-bs-mode

      If I see the heading "SUBCLASSING", that indicates to me that all the information below is public, so I can write my own subclass. Am I missing something?

      --
      Marvin Humphrey
      Rectangular Research ― http://www.rectangular.com

        In Java speek 'private' means only the class that declaired it can use it, 'public' means any one of any class can use it. Java also has the notion of 'protected' and 'package', basicly any subclass has access and any class in the same package has access respectivly.

        The "SUBCLASSING" section would declair 'protected' (by convention only) methods. So it would not truely be 'public' in the sense of any class may call them, but it could be seen as 'public' in the sense that you have published their specs for all to see.

Re: Documenting non-public OO components
by educated_foo (Vicar) on Sep 07, 2005 at 05:03 UTC
    Perl actually has infiniti levels of access -- just name them and document them! Access control is no substitute for documentation and self-discipline.
      Freedom isn't free.

      It's a PITA to figure out how to convey public/package/protected/private when the code CAN'T self-document because access control levels aren't part of the language. Not having those constraints in Perl allows all kinds of wacky OO structures (for better and worse), but there's no easy, efficient, widely understood ACL-documenting convention in Perl besides the leading underscore, and that's totally inadequate for large systems consisting of dozens of classes.

      It would be nice if I didn't have to reinvent this wheel. I strive to be one of those people who can assess the strengths and weaknesses of various languages without descending into polemics and bigotry; I humbly submit that while the straight-jacket Java imposes causes other problems, it sure does make documenting ACLs a lot easier than good-ol'-anything-goes Perl. As a consequence, I have less time to spend on other things, and I don't like that.

      --
      Marvin Humphrey
      Rectangular Research ― http://www.rectangular.com
Re: Documenting non-public OO components
by dragonchild (Archbishop) on Sep 08, 2005 at 13:14 UTC
    Should private methods be documented in the test suite and public methods documented in the POD? Or, am I missing something?

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
      I assume that you refer to the technique of documenting the functionality of a module indirectly by providing tests which double as example code, labeled by a message which indicates what the test is for. That is certainly useful as a supplement, but not as a substitute for the summary of functionality that typically appears in POD or javadocs.

      If you were trying to grok the flow of data through several classes, and through perhaps 10 or 20 methods, would you prefer dredging the intended use for each method out of the test code over consulting a purpose-built summary? I think you would have a hard time achieving the level of confidence required by the second test in your sig. Bad software! Bad! :)

      --
      Marvin Humphrey
      Rectangular Research ― http://www.rectangular.com
        If you were trying to grok the flow of data through several classes, and through perhaps 10 or 20 methods, . . .

        Lord and Lady preserve us! How complicated are you making your code?! If I have to do what you're suggesting, that is a CodeSmell and needs to be addressed immediately, preferably through refactoring the living #$E*! out of it. I should be able to look at a test and see exactly how I'm supposed to use any portion of your code. Period, end of story. Otherwise, either your tests or your design sucks. (Or both, but if that's the case, then you're better off starting from scratch.)

        Remember - we're talking about the non-public portions of your API. This is the stuff that you don't want the average client using. Since the intended audience is a developer, they should be looking through the tests, anyways, to understand the assumptions you've made that your code won't document. In addition, they probably are looking through your tests in order to figure out how to test their modifications to or subclass of your stuff.

        Furthermore, I'll point at DRY (Don't Repeat Yourself). A purpose-built summary is, by definition, a repetition. It has to be kept in sync by hand and thus, by definition, won't be in sync. The tests, on the other hand, are part and parcel of the code in question. If the test suite passes (as it always should), then I know that the tests are the best possible form of documentation the developer could have provided. (They're even better than any comments that might be in the code.)

        While we're on the topic, the documentation for the public API should consist of the following:

        • What is this thing (NAME)
        • Basic usage (SYNOPSIS)
        • Ideas behind it (DESCRIPTION)
        • Details about the names of the methods and the various options (METHODS)
        • Common uses (EXAMPLES)
        • Anything else the client should know (BUGS/CAVEATS)
        • How to get more help (CONTACTS/AUTHORS)

        No more and no less. (Any similarity to the standard POD skeleton is completely intentional.) At no time should any reference be made to implementation details, save when one public method calls another public method within the same module (and that should be done sparingly). Private methods should never appear, save when they violate some community contract (such as having "new" or "clone" be a private method) or some Perlism (such as having "print" be a private method). And, frankly, if you have to document a private method in your public API, that's a DesignSmell and should be addressed ASAP.


        My criteria for good software:
        1. Does it work?
        2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: Documenting non-public OO components
by petdance (Parson) on Sep 09, 2005 at 00:44 UTC
    Pod::Coverage gives you ways to specify that certain methods are internal (and Test::Pod::Coverage will pass them in, too). The easiest way, and the one I wholeheartedly endorse, is to simply prepend your internal methods with an underscore. Then you don't have to do ANYTHING.

    There is no clearer way to tell the caller "hands off this method!"

    xoxo,
    Andy

      What about methods, typically called "package" or "protected", which are not part of the public API, but must be called by other classes that are part of the distro? Those should not have leading underscores, IMO, because it contradicts standard practice. From perlstyle:

      You can use a leading underscore to indicate that a variable or function should not be used outside the package that defined it.

      The Pod::Coverage problem is solvable with minimal effort, as both you and xdg have pointed out (thanks). However, there is still the need to document these methods while indicating clearly that they are not available to users.

      There seems to be a range of opinion on as to the best solution. The ones that I like best for this project at least are the ones closest to javadoc, but I can appreciate the merits of the document-by-test and the bury-private-docs-deeply schools as well.

      --
      Marvin Humphrey
      Rectangular Research ― http://www.rectangular.com
        =head1 Public methods =head2 $obj->wango =head2 $obj->doofus =head1 Internal-only methods =head2 $obj->whatever

        xoxo,
        Andy