Re: Questions about sharing code
by perrin (Chancellor) on Nov 27, 2007 at 14:21 UTC
|
In general, I prefer not to import or export anything. I find it confusing when I look at the code later, and I don't mind verbose function calls when they give me extra documentation about where things came from.
However, inheritance may not be the right choice for sharing OO code. Only use inheritance as a way to model behavior of an object, not as a way to simply share code. If you just need to share some code but the behaviors in it don't make sense as an inherent behavior of the object you want to use them from, rethink your object model and figure out what concepts are not being modeled. You may need a new class, which the other classes call or delegate to.
Sometimes I even resort to the dreaded "Foo::Util" class for things that don't fit nicely anywhere else. It's still better than using inheritance just for access to some methods. | [reply] |
Re: Questions about sharing code
by dragonchild (Archbishop) on Nov 27, 2007 at 15:27 UTC
|
There are a few modules on CPAN that I use over and over and over. Every single one of them exports a set of functions.
- Scalar::Util
- List::Util
- List::MoreUtils
- File::Temp
- File::Path
- FindBin
The one module that I should use more that I don't (and won't unless forced to) is File::Spec. I HATE the pseudo-OO interface with an absolute passion. Oh, I understand why it was written that way and I'm not sure I would've written it differently under the hood. But, the UI just sucks so badly that it hurts.
There are also a few modules on CPAN that I use a lot that provide an OO interface. This is because there is state information that needs to be preserved.
Yes - CGI is OO. The functional interface is an absolutely horrid and I refuse to use it.
The point is that you should provide a functional interface if they are side-effect-free functions. If there is data that needs to be preserved across function calls, then you should provide an object.
My criteria for good software:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] |
|
|
| [reply] |
|
|
Yes, I have, but that's not a good example of an egregious interface. And, it begs the question "Why isn't that the default interface?"
My criteria for good software:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] |
|
|
Thanks dragonchild for the examples. It really helps to see what others are doing.
So, what I'm hearing is: unless what I am doing is specifically OO or needing inheritance, I should just rely on the non-OO-Export method.
Correct?
—Brad "The important work of moving the world forward does not wait to be done by perfect men." George Eliot
| [reply] |
|
|
Use the right abstraction for the job. OO is a great pattern to work in, but it has a cost associated with it. Use it when necessary.
Here's another way to look at it - C doesn't have any OO built into the language (leaving aside C++ for the moment). Yet, most stuff is written in C. Yeah, some of it could benefit from OO, but how well would math.h or stdio.h really benefit from it? Those are state-free functions. OO is for tagging state with behavior. If you have no state, then why OO?
My criteria for good software:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] |
|
|
| [reply] [d/l] [select] |
|
|
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:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] [d/l] |
|
|
|
|
|
|
|
Re: Questions about sharing code
by moritz (Cardinal) on Nov 27, 2007 at 14:34 UTC
|
I don't really understand why you want to change from procedural to OO interface. If you don't have a good reason to switch, don't.
The general advise is to use a procedural interface when the functions in a module don't work on the same data.
If you have many subs sub1, sub2, ... in your module, and you call them all like sub1($data, @other_args); sub2($data, @other_args); it might be high time to pull $data into an object.
If not, simply stay where you are. | [reply] [d/l] [select] |
Re: Questions about sharing code
by Your Mother (Archbishop) on Nov 27, 2007 at 23:18 UTC
|
I'm gonna agree with perrin (typical!) and disagree, partially, with dragonchild (WTF OMG).
For straight function code I've taken to doing things like-
use HTML::Entities ();
... HTML::Entities::encode_entities($whatever);
Because I can't stand reading code later that is hard to follow or potentially sends you to the wrong package with much confusion. With cutting+pasting and knowing your IDE, fully qualifying stuff is easy to type and much easier to follow later.
For OO, the name space is carried in the object so, no problems.
Also, I find using CGI.pm's OO interface goofy. The main non-aesthetic difference is that your code will run slower as OO. Otherwise, CGI::param() is no different from $cgi->param(). It's great to have CGI.pm's objects when you need to sling objects around (like in TT2 or something), but many, most I've written, CGIs are standalone in a way that makes imperative code easier to read and much easier to type.
use CGI;
my $cgi= CGI->new();
print $cgi->header();
# etc...
| [reply] [d/l] [select] |