http://www.perlmonks.org?node_id=611306

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

Hello, Monks:

I am new-ish to Perl, and also have great gaping holes in my general programming knowledge due to an overlong detour in the arts. I am searching for a newbie-level intro to the topic of Perl packages, e.g. what uses they serve, how to create one, etc., really basic stuff like that.

The fact that I am posting typically means I will discover the answer to this myself in about five minutes and get really embarrassed, but ... I didn't find anything obvious on the Tutorials page here, and the obvious place in the docs (perlmod) begins kinda in medias res, thusly, about packages:

"Perl provides a mechanism for alternative namespaces to protect packages from stomping on each other's variables. In fact, there's really no such thing as a global variable in Perl."

OK. But what are packages, why would I want to create one and what can I put in one?

To get more specific about this: I am an amateur astronomer and am trying to focus my maturing Perl-ing by playing with astronomical data ... if I have (say - a simplistic example) a big long hash that maps IAU abbreviations for constellation names to their full names, can I pull that aside into a package so that it doesn't obscure the program or script that needs it?

Pointers to tutorials are welcome. Thanks!

UPDATE: while it is often said there are no stupid questions, it did not take long for me to realize that this one was ill-considered, & that I should have dug more before posting it!

  • Comment on overview/tutorial on packages - creation and use

Replies are listed 'Best First'.
Re: overview/tutorial on packages - creation and use
by Fletch (Bishop) on Apr 21, 2007 at 18:06 UTC

    Packages provide namespaces for non-lexical variables (those declared with our or with a fully qualified name). Within any given namespace there may be only one variable (of each datatype) with a given name. Using namespaces is kind of like if you have several friends with the same first name (their last name provides different "packages" for each). Likewise in order to disambiguate when the context is not clear which one you're referring to you name them by their full name which includes the namespace (first and last).

    ## Since we use strict we have to declare the names of our package ## variables with our use strict; package Smith; our $John = 1; package Jones; our $John = 2; # prints 2, because package Jones is the current package; print $John, "\n"; # prints 1 because we explicitly name the other package's var print $Smith::John, "\n"; package main; print $John, "\n"; # Compile time error because there's no $main::Joh +n

    Now as for your question, your hash might presumably be called %names. What if you're writing code which maps constellations to the names of astronomers who discovered some feature therein and you want to call that hash %names as well (and yes, this is against PBP variable naming advice; indulge my hypothetical :).

    You could put the constellation names hash in a package Constellations, while the other goes in Astronomers. Then your code would use $Constellations::names{ "Big Dipper" } or keys %Astronomers::names or what not to access them. You also could use Exporter to import the variables into other package's namespaces and refer to them with an unqualified %names instead to save yourself some typing.

      (those declared with our or with a fully qualified name)

      According to the docs, variable symbols declared with our are lexical symbols (although the symbol table entry they refer to is a package global):

      our associates a simple name with a package variable in the current package for use within the current scope. When use strict 'vars' is in effect, our lets you use declared global variables without qualifying them with package names, within the lexical scope of the our declaration. In this way our differs from use vars , which is package scoped.

      What makes them look like non-lexicals is their auto-vivification of package globals.

      --shmem

      _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                    /\_¯/(q    /
      ----------------------------  \__(m.====·.(_("always off the crowd"))."·
      ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      Thank you! The emphasis on disambiguation has helped clarify the topic of namespaces for me.

      Partly, I guess, because I am not terribly far along in my learning, I had gotten the idea that a "package" was necessarily a completely separate file of stuff - that could then somehow be imported (and that a Module was "simply" a specific kind of package) and then accessed/used/referenced. I see now that among other things, it is more subtle than that.

        I had gotten the idea that a "package" was necessarily a completely separate file of stuff - that could then somehow be imported (and that a Module was "simply" a specific kind of package) and then accessed/used/referenced.
        You've got that impression because thats the standard way it's used :-) It normally makes not much real sense to put multiple packages in a single script file. Imagine you write a script where you put your package Astronomers; with a longish hash and package Constellations; with a longish hash and your code below in main. The other day you need both packages again for a second script. Then you copy and paste both packages into your new script file....an excellent source for bugs.

        Regarding the "longish hash" itself. It's a design flaw to have modules/packages that do nothing than containing data. It's better to save your data where it belongs, in a file or a database, and let you're code read it. That way it's far easier to copy with changes in your data.


        holli, /regexed monk/
Re: overview/tutorial on packages - creation and use
by andye (Curate) on Apr 21, 2007 at 21:04 UTC
    Hi chexmix,

    I don't think this is an ill-considered question at all; in fact I'd say it's rather an interesting one, particularly the issue of why using separate packages might be a good thing. So no need to beat yourself up, I think. ;)

    On the question itself: one simple reason might be that you intend to write some code that you're going to let other people use, maybe you'll be uploading it to CPAN, and you want to let other people use some particular function while not cluttering up their namespace, or getting them involved with other bothersome details of your module.

    For example: I just needed to round a number to the nearest integer. I'm using a CPAN module which someone else has kindly written, called Math::Round. All I need to know about it, really, is that it adds two function names (it 'exports' them), 'round' and 'nearest', so I can't have a function with that name. I don't need to know (for example) that it uses a variable called $halfhex - and in fact I didn't know that until I just looked for an example. ;) If I already had a variable in my script called $halfhex, that wouldn't be a problem.

    So anyway, it should be pretty obvious that this is a similar kind of thing to making variables local to a particular function, so they can't get messed around with elsewhere in your script.

    The more general issue, and (I think) the particularly interesting point behind your question, is why this is a good idea.

    There's some useful text at Wikipedia on Separation of concerns, Orthogonality and information hiding. Essentially the point is to keep parts of the program which do separate things as separate from one another as possible, to avoid screwing up one one of them when you're working on the other.

    The principle is that it's easier to keep track of what you're doing if your actions are limited to one particular area, and don't have consequences outside that area.

    An analogy that I've seen used is between the control of a helicopter, where moving each of the main controls requires a simultaneous matching move to the other controls to keep the aircraft stable, versus controlling a plane, where it's possible to change (for example) the direction of the plane without making changes to the power being used. The point being that controlling a plane is (apparently!) easier because the controls can be used 'orthogonally' from one another.

    There's a good essay in 'The Mythical Man-Month: Essays on Software Engineering' (ISBN 0-201-83595-9) which talks about this in more detail, I think. If you hunt about a bit you should be able to find some OO texts dealing with the reasons behind encapsulation, too.

    HTH!

    Best wishes, andye

    Update (2007-04-23): My book reference was wrong, I was actually thinking of 'The Pragmatic Programmer', ISBN 020161622X, in which the authors explain their analogy far better than I did:

    A Nonorthogonal System

    You're on a helicopter tour of the Grand Canyon when the pilot, who made the obvious mistake of eating fish for lunch, suddenly groans and faints. Fortunately, he left you hovering 100 feet above the ground. You rationalize that the collective pitch lever controls overall lift, so lowering it slightly will start a gentle descent to the ground.

    However, when you try it, you discover that life isn't that simple. The helicopter's nose drops, and you start to spiral down to the left. Suddenly you discover that you're flying a system where every control input has secondary effects. Lower the left-hand lever and you need to add compensating backward movement to the right-hand stick and push the right pedal. But then each of these changes affects all of the other controls again. Suddenly you're juggling an unbelievably complex system, where every change impacts all the other inputs. Your workload is phenomenal: your hands and feet are constantly moving, trying to balance all the interacting forces.

    Helicopter controls are decidedly not orthogonal.

    Footnote: Helicopters have four basic controls. The cyclic is the stick you hold in your right hand. Move it, and the helicopter moves in the corresponding direction. Your left hand holds the collective pitch lever. Pull up on this and you increase the pitch on all the blades, generating lift. At the end of the pitch lever is the throttle. Finally you have two foot pedals, which vary the amount of tail rotor thrust and so help turn the helicopter.

    (pp. 34-35)

    It goes on to talk about the specific benefits that can arise from orthogonality: easier code re-use, easier for different team members to work separately on separate parts of the project, easier testing, less tie-in to specific platforms (e.g. our DBI module helps us to write Perl programs which are fairly orthogonal in respect of the database used), resulting code less fragile.

      Actually, I can view your reply as a good tutorial called Why we use package. ;)

      I am trying to improve my English skills, if you see a mistake please feel free to reply or /msg me a correction
Re: overview/tutorial on packages - creation and use
by bcornett (Sexton) on Apr 24, 2007 at 12:29 UTC
    There is a good book on intermediate perl topics such as packages. -Ben
      I am reading it (the Alpaca book) now on Safari. Actually, I got very very stuck in Chapter 5 this morning, and this prompted me to type this node.

      I think I just need to relax and learn and set myself some doable projects ...

      Best,

      GB