Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Re: Re^2: USE or Require?

by l2kashe (Deacon)
on Jul 24, 2003 at 13:58 UTC ( [id://277540]=note: print w/replies, xml ) Need Help??


in reply to Re^2: USE or Require?
in thread USE or Require?

I attempt to maintain a consistant paradigm. If I need to use the functionality from another module, I instantiate an object and use the defined API. If I need a series of objects, I instantiate them in my constructor and store them in my constructor. I guess only exporting new which is kind of redundant anyway, is bascially stating "Here is the way I would like you to come in, see that API over there, that's for you". If people end up editing the source to export more, or set up inheritance, more power to them.

Granted it's not the only way to do it by any means, and I give up some functionality, but I prefer the consistancy in all my code produced for this company. In my current position, each module produced is pretty close to the bottom of the food chain. I think if I were providing slightly more generic modules the case may be different, but in the present situation its not necessarily the best solution.

use perl;

Replies are listed 'Best First'.
Re^4: USE or Require?
by adrianh (Chancellor) on Jul 24, 2003 at 14:38 UTC

    Sorry - don't understand :-) Could you show some code that shows how exporting new() is useful?

      exporting new isn't useful. Its there more to say to the user of the module, this is the way in. I'm in the camp that doesn't like namespace pollution, so I try to push my bias along to the next person. Either A) they will instantiate via the constructor, or B) they will have to fully qualify all calls via Package::Name::function

      They will either use my module or not. Generally I encapsulate as much functionality as is reasonable in the module. I don't go overboard and include everything, unless its really needed (generally it isn't). The scope of the modules are also pretty closely tied to particular applications used on the network.

      Im not quite sure why people aren't happy with my opinion on the topic. I find code written $obj->method(args) far cleaner, than trying to guess where the function or method is coming from. Since this is the case, part of my best practices is doing use Blah (); unless I simply can't (File::Find and Carp come to mind). My reasoning for only putting new in export_ok, is to simply let people know that the only thing that can be imported, if they want anything at all is the new method and since its in export_ok and not export they have to ask for it explicitly (which generally won't happen). I don't go in for the "shotgun to keep people out of the livingroom" mentality. I only document the public API. I tend to not do class inheritance. If I need functionality from multiple packages, then I encapsulate within my object in the constructor. (i.e $obj->{'socket'} = IO::Socket::INET->new()).

      demerphq's thoughts are interesting, but my reasoning is much more shallow. If anything gets imported from a module of mine, then it won't overwrite anything in the end user's namespace. plain as that. It might not be the best mentality, nor the most technically sound reasoning, but my code looks consistant across the board (both in the scripts themselves and the modules I've written here), which makes it much easier for myself to maintain. On top of that the next person who comes along will be able to readily pick my style out, learn my idiosyncracies fairly quickly, and know what to expect in modules and scripts.

      I wouldn't mind some feedback on what people's reasons are for not liking my view, as I'm trying to become slightly more refined in what I say. I have no "traditional" edjucation in computing or programming, but I've been at this since '99 and feel I have a solid background. Though hanging around the monastary has helped refine the way I frame my thoughts, I still feel like an outsider in terms of the appropriate lingo/vocabulary sometimes. I tend to be able to follow and use new concepts fairly easily. What I don't do well is communicate via text (voice Im slightly better at). So whats the beef?

      use perl;

        exporting new isn't useful. Its there more to say to the user of the module, this is the way in. I'm in the camp that doesn't like namespace pollution, so I try to push my bias along to the next person. Either A) they will instantiate via the constructor, or B) they will have to fully qualify all calls via Package::Name::function

        I wasn't having a go at ya - honest! I was attempting to understand you're motivations for having new() in EXPORT_OK, indeed for using Exporter in an OO module at all. Typically an OO constructor wouldn't work if imported into another package.

        I'm in complete agreement with your goal of making your code use intentions explicit in the code itself. However, I don't think that putting new() in EXPORT_OK is going to act as a useful cue in the way that you think.

        Normally an OO module will not use Exporter at all. If I see an EXPORT_OK my assumption will be that the code isn't OO - exactly the opposite of the point you're trying to get across.

        You just gave off a few whiffs of bad practice and I'd like to clarify just what you mean. There are some wrong answers here and I'm hoping you'll either confirm or deny that you're being sane.

        Exporting new() so it can be used as a function and not just as a method.

        use l2kashe 'new'; my $o = new; $o->foo( ... ); # Vs use l2kashe; my $o = l2kashe->new; $o->foo( ... );

        This is bad practice for a number of reasons. I'll cover whatever comes to mind just now. Keep in mind that I'm internally recoiling from the really hideous things you've brought to mind here.

        'new' is the common name for a constructor method. If the importing code already had a 'new' method or function then you've just overwritten the module's own new() method. 'use warnings "redefine"' will catch this and throw a warning but it won't produce a fatal error. In fact, because use() happens at compile time, which version of new() remains in your user's code is up to the order in which they were mentioned.

        use l2kashe; # The importing new() dies sub new { ... } # This one stays # Vs sub new { ... } # The original new() dies use l2kashe; # This one overwrites

        The expectation is that the constructor is tied to the class it originates in. Your constructor will have to hard code the originating class so that it can still reference l2kashe instead of wherever it was copied to. We all know hard coding data like this is poor form.

        sub new { bless {}, shift } # Vs sub new { bless {}, __PACKAGE__} # or maybe even: sub new { bless {}, 'l2kashe' }

        Your constructor has to function as a method and a function now. This is highly irregular and is one of the funkiest things that CGI.pm does. You have to include code in new() that decides whether $_[0] is the class name it should use (if it was called as a method) or whether it is just the first parameter (if it was called as a function). Properly done, the first argument is always the class name. That detail is handled by calling the constructor as a method - this is why you often see code that looks like this

        sub new { bless { @_ }, shift }

        In your case you have to distinguish between strings that are class names and strings that are parameters. Its possible but you've now eliminated the class name as an available value to the first parameter.

        sub new { my $class_or_parameter = shift; if ( $class ne __PACKAGE__ ) { unshift @_, $class_or_package; } bless { @_ }, __PACKAGE__; }

        You also intimated that maybe your other functions/methods also are expected to be called as both functions or methods. In this case you have to be even tricker and introduce significant evil to all of your code.

        sub something { my $self_or_parameter = shift; if ( ref $self_or_parameter eq __PACKAGE__ ) { unshift @_, $self_or_parameter; } ... }

        For the moment anyway, I can't see anything but really evil things down this path. Object oriented perl code just does not use Exporter. There is 100% no need for it. the expectation is that your constructor is a method call using the class on the left side of the arrow: SomeClass->new. Some people argue you should be able to do $o->new, I'll not address that but certainly out is SomeClass::new. Additionally, all of your methods that are not constructors are always called as methods and always with the left side being the object in question. So $o->method, never SomeClass->method or SomeClass::method.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://277540]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2024-04-23 21:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found