in reply to Re^2: Questions about sharing code
in thread Questions about sharing code

First off, your second option doesn't compile.

As for the difference between the first and the third, you need to seriously look at maintenance for the answer. For all the code in a given file, you can do a search for "sub foo" and find out what foo does. But, if it's a subroutine from another module, you can't easily find it. If there's just one Mycommonroutines, then you know where it is. But, what if there are 2? 5? 10? It gets a little hairier.

It is for this reason that I and other CPAN authors have started using the following meme:

# Explicitly state nothing will be imported use Scalar::Util (); # Call the function with the complete name Scalar::Util::weaken( $some_ref );

For functions like weaken(), this may seem like overkill. But, this kind of habit will help maintainers because it becomes a flag to say "I didn't write this code in this file and this is where you can find it." And, conversely, if it doesn't have a prepended location, then it must be in this file somewhere. Any kind of hint like that will help your maintainer. Remember - code as if the guy who sees you code after you knows where you live and likes to swing axes.


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?

Replies are listed 'Best First'.
Re^4: Questions about sharing code (@EXPORT_OK++)
by tye (Sage) on Nov 28, 2007 at 17:28 UTC

    I still boggle at this idea. Much better would be:

    use Scalar::Util qw( weaken ); # ... weaken( $some_ref );

    For one, it abstracts the idea of weaken() so that you can easily replace it with a wrapper if you later need to wrap Scalar::Util::weaken() or use a weaken() from a different module (which improves the maintainability of your code). It makes the code easier to "parse by translating the shapes that form characters" instead of having to repeatedly be distracted by "parsing by translating the shapes that form characters" these long names, you can just "parse by translating the shapes that form characters" the perfectly descriptive "weaken" name; like using "read"/"reading" in place of the long quoted phrases above. It makes it easier to tell why Scalar::Util is being used. It confirms at compile time that the desired function is actually provided by the module and is not just meant for internal use or use as a method (something that isn't even clear to the person reading the code as you wrote it). It means that mistyping the subroutine name doesn't accidentally call an internal routine or method from that module. It allows the module to decide to not even load functionality that is not going to be used (or other, more advanced techniques such as maintaining backward compatability more conveniently).

    Module names need to be globally unique and so should be relatively long and descriptive, which is why I always try to make it so my module names only need to be mentioned once for them to be used. Repeating a magic string constant (the module name) over and over in your code does not make it easier to maintain. Do you avoid defining constants because it makes the code easier to maintain if the person reading the code can immediately see the value of the constant because the 7 is right there in front of their face? Or do you name your constants like SUNDAY_0, MONDAY_1, ... to get the best of both worlds?

    Repeating the source of the function at every invocation makes about as much sense to me as naming your local subroutines "sub frob_line237" so everyone will know which line to jump to in order to find the definition of the function.

    - tye        

      And all of those reasons are great reasons. The reason I do it for all my OO CPAN modules (and most of mine are OO) is that I don't want $obj->weaken() to be a possibility. Particularly if weaken() is a method in my base class.

      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?

        There are more problems than that. This is why I usually write classes with separate packages for class methods, object methods, and utility functionsmethods. Unfortunately, caller and thus SUPER: and its ilk are still too stupid to deal with code that actually prevents such method confusion:

        package My::Class::_implement; use Scalar::Util qw( weaken ); sub My::Class::new { # ... } sub My::Class::Object::method { # ... weaken( $someRef ); # ... }

        Yes, you can abstract out having to re-type class names fairly easily; this is just a quick example.

        - tye        

      I see dragonchild's point, but I think yours, tye is "cleaner". Maybe this is retro and a bit unhackerish, but I just add a remark after calling a sub from another module:

      weaken( $some_ref ); #from Scalar::Util

      Anyway, thanks to both of ye for getting me back on the right path with @Export.


      —Brad
      "The important work of moving the world forward does not wait to be done by perfect men." George Eliot