Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Should a constructor ever return undef?

by tall_man (Parson)
on Jul 11, 2003 at 01:16 UTC ( #273210=perlquestion: print w/ replies, xml ) Need Help??
tall_man has asked for the wisdom of the Perl Monks concerning the following question:

As a matter of object-oriented style, what do you think of a class constructor like this:
package MaybeADirectoryObject; use strict; sub new { my ($class, $dir) = @_; if(! -e $dir) { print "The directory $dir does not exist\n"; return; } my $self = {}; # Initialize $self using directory here... bless($self, $class); return $self; }
Another programmer in my shop did something like this, and a third programmer was caught by it when they set the return value of new() into a variable and called a method on it much later in the code.

Since I started object-oriented programming with C++, I find it very strange to return an undef from a constructor. I could see calling die and letting the caller handle the exception with an eval block, but returning an undef seems wrong to me.

What do you think?

Comment on Should a constructor ever return undef?
Download Code
Re: Should a constructor ever return undef?
by Zaxo (Archbishop) on Jul 11, 2003 at 01:36 UTC

    That's the convention in perl. One way to use it is like this,

    my $foo = MaybeADirectoryObject->new(@args) or die 'No object', $!; # ...
    A blessed reference does not evaluate false, so defined is not needed in the logic.

    The eval {die 'No Object' if $error} with $@ handling is really no cleaner. In fact, eval returns undef if block exit is by die-ing or other trappable error, and can be handled the same as the more direct code above.

    Update: I previously had the constructor wrapped in defined, but changed it and the description just as ++ctilmes posted his useful comment.

    The big difference between perl and C++ exception handling is that, in C++, catch clauses are the responsibility of the try block, while in perl they are the responsibility of the caller. That is a large conceptual gap, but is not so different in application.

    After Compline,
    Zaxo

      I like simply:
      my $foo = MaybeADirectoryObject->new(@args) or die "No object: $!";
      eval() catching exceptions seems more awkward to me.

      I would probably carp() instead of print in the constructor.

Re: Should a constructor ever return undef?
by IlyaM (Parson) on Jul 11, 2003 at 08:41 UTC
    Perl as OOP language is much more flexiable language than C++ and there is no really reason to not use this flexibility when it makes sence. Return under (or any other special value) or raising an exception as a sign of error is really just a matter of style. Best Practices for Exception Handling covers it so you may find it interesting.

    --
    Ilya Martynov, ilya@iponweb.net
    CTO IPonWEB (UK) Ltd
    Quality Perl Programming and Unix Support UK managed @ offshore prices - http://www.iponweb.net
    Personal website - http://martynov.org

Re: Should a constructor ever return undef?
by adrianh (Chancellor) on Jul 11, 2003 at 10:26 UTC

    In the general case I would prefer an exception to be thrown since I find that leads to better code (for some definition of better :-)

    The only situation where I would consider undef to be more appropriate is if the module would normally be used in a context where the constructor would be expected to fail - in which case "failure" isn't "exceptional" and might be clearer presented as normal control flow.

    As ever YMMV :-)

Re: Should a constructor ever return undef? (yes)
by grinder (Bishop) on Jul 11, 2003 at 14:19 UTC

    This is the general problem of resource acquisition. Sometimes you cannot test beforehand to see if an operation will succeed. The only way to know it to go ahead and try it.

    For instance, even in your constructor, although you test for the existence of a directory with -e (although personally I would test with -d), you cannot be sure that it isn't deleted or renamed between the time you test it and the time you use it. The chance is vanishingly small, but it is non-zero.

    C++ constructors don't make a separation between acquisition and initialisation, and you are soundly flamed in C++ circles if you propose

    foo_t foo = new Foo('/path/to/dir'); foo.init();

    ... the main complaint being that when foo is constructed it's ready for service ("what happens if the client forgets to call init()?" is the common observation).

    If a constructor fails, or can only partially initialise the object, there is no out-of-band channel to communicate this fact. To get around this problem was one of the main motivations for adding exception handling to the language.

    I quite like the fact that Perl object construction works the way it does; that it doesn't require exception handling in the simple case. Remember the dictum "Perl makes the easy things easy."

    You're quite comfortable with checking the result of an open or system (... well... you should be), so it should seem natural that you check the results of creating objects too. With the "do or die" idiom, it's quite easy to get the die part of the code out of the way, much cleaner than checking malloc and open in C, where the error checking drowns out the main action.

    _____________________________________________
    Come to YAPC::Europe 2003 in Paris, 23-25 July 2003.

      Ok, it looks like the consensus of most of the answers is that returning undef is normal. But I'd still like to make it harder for the unwary programmers to forget to check the return. I'm suggesting to my co-workers that constructors that can return undef be named "fallible_new" instead of just "new". That might be a little obnoxious, but it would help prevent bugs.
        Ok, it looks like the consensus of most of the answers is that returning undef is normal.

        Just because something is commonly accepted doesn't mean it's good ;-)

        But I'd still like to make it harder for the unwary programmers to forget to check the return.

        You might want to look at using the Fatal module. You can use this to force an exception to be thrown if undef is returned.

        However, if returning a false value on failure is actually causing problems for you I would strongly consider moving over to an exception throwing style.

Re: Should a constructor ever return undef?
by Jenda (Abbot) on Jul 11, 2003 at 15:13 UTC

    Mail::Sender (the newest version) allows you to specify what kind of error reporting do you want. It can either throw an exception (die), return an undef or return a negative error number. This of course affects all methods of the created object as well. Therefore the caller can use whatever feels best for him:

    eval { my $sender = Mail::Sender->new({on_errors => 'die', ...}); $sender->Open({...}); ... $sender->Close(); }; die "Failed to send the email: $@\n" if $@; #or my $sender = Mail::Sender->new({on_errors => 'undef', ...}) or die "Failed to send the email: failed creating the object - $Mail +::Sender::Error\n" $sender->Open({...}) or die "Failed to send the email: $Mail::Sender::Error\n" ... $sender->Close() or die "Failed to send the email: $Mail::Sender::Error\n"; #or ...
    You can do something similar.

    Anyway ... I would not want some object to print whetever error messages it pleases into the STDOUT. I would not want them in the STDERR either, but even that would be better.

    Jenda
    Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
       -- Rick Osborne

    Edit by castaway: Closed small tag in signature

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://273210]
Approved by broquaint
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (6)
As of 2014-12-29 05:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (184 votes), past polls