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

OK. Here's one that lost me. What is happening in this constructor copied from Module::Starter::Simple, please?
sub new { my $class = shift; bless { @_ } => $class; }
Is that saying that each element of the argument array is in turn blessed? Or is it that a hash element with a key taken from the argument array and a value of the class used to call it is in turn blessed?

Or does { @_ } create an annoymous hash from the elements of the argument array and if so, how does that => $class fit in?

Sometimes perl seems to leave a little too much to my imagination.

-- Hugh

Replies are listed 'Best First'.
Re: What means: "bless { @_ } => $class;"?
by Thelonius (Priest) on Apr 24, 2006 at 00:48 UTC
    Or does { @_ } create an annoymous hash from the elements of the argument array and if so, how does that => $class fit in?
    The braces here create a reference to an anonymous hash. The curly braces are probably the most overloaded symbols in Perl. Sometimes the usage is even ambiguous and perl doesn't do what you would expect.

    => is essentially the same as a comma except that sometimes you don't need to quote what's on the left side of it (which isn't relevant here).

    You could also write this as:

    sub new { my $class = shift; my %self = @_; bless \%self, $class; }
    or
    sub new { my $class = shift; my $self = { @_ }; bless $self, $class; }
      Better than I'd have answered. Just an addition, to be complete.

      The return value of the sub is the last eval:ed statement, in this case the 'bless'. It returns the reference (new object).

      It is a common idiom to place the bless last in 'new' methods, so the new object is returned.

      (The one asking the question probably knows this, since it says so in the Camel book about 'bless'. But just to be safe.. the other part of the question is almost there in the Camel book, too.)

      Update:
      Surprising, but if merlyn says it is a pedagogical problem, I'll believe it. :-) (That would be Perl-only programmers? The "return last value by default" is quite Perl-specific, afaik?)

        It is a common idiom to place the bless last in 'new' methods, so the new object is returned.
        The disadvantage of that is that you cannot call methods within the constructor to pick up class-related or instance-related initialization information.

        However, that's fairly rare for simple demonstrations. Hence, most people haven't seen the fact that more often in "real life", bless is done fairly early in the constructor, usually as soon as the hashref is constructed.

        -- Randal L. Schwartz, Perl hacker
        Be sure to read my standard disclaimer if this is a reply.

Re: What means: "bless { @_ } => $class;"?
by davido (Cardinal) on Apr 24, 2006 at 02:29 UTC

    It's kind of surprising to me that this code exists in the "real world". Here's why. Any/All parameters passed to new() will find their way into the object's hash as key/value pairs. In my mind, that gives too much power to the caller, particularly for a public method (more on this later). It could even create potential issues down the road, similar to the kind of issues created by using the -s switch on the perl command line, wherein the script's invoker is able to create package globals in the script's main namespace simply by what is typed on the command line. ...ok, with the object oriented example you showed, the potential only exists to stamp on an individual object's internal namespace, but it still feels a little sleezy to me.

    The other problem is that any arguments passed to new() must come in pairs (key/value pairs), or you'll get a warning (assuming warnings are in effect). ...This is probably a good thing if you're intentionally creating key/value pairs in the object's internal namespace. But it does, once again, feel a little sleazy. In Perl Best Practices, if I recall, the conventional wisdom about passing key/value pairs to a subroutine is to pass them as an anonymous hash, rather than as a bare list.

    The last problem is that of legibility. You had to ask what it's doing. I had to think about it for a moment. It's not exactly clean, maintainable code. Clever, yes. But a little too clever.

    Now for some redemption: As I read the documentation for Module::Starter::Simple, I see that the new() method isn't intended for public use; it's intended to be invoked as an internal method, called by create_distro(). So the fact is, you probably shouldn't ever really need to be concerned with new(), and unless you're simply trying to learn a little from the module's code, you don't really need to worry about the implementation. That being the case however, new() probably ought to be called _new()... another recommendation supported by Perl Best Practices for marking internal (non-public) methods clearly. Once again, at first look I wouldn't have guessed that new() was intended to be an internal-use-only method. The POD draws attention to the fact, but it would make sense for it to be named with the leading underscore, the traditional way of calling out internal methods.

    Oh, you also asked about the => operator. Just think of it as a "fat comma". All it's doing in this case is acting as a comma. While it might be visually confusing in this context, I would guess that the module's author saw it as a clever way to visually demonstrate that the anonymous hash being blessed "belongs to" the class on the righthand side of the "comma arrow".


    Dave

Re: What means: "bless { @_ } => $class;"?
by hesco (Deacon) on Apr 24, 2006 at 02:19 UTC
    Thank you Thelonius for breaking it down and making it plain. Your two examples feel far more familiar to me than the sample that left me head scratching. One coding buddy of mine wrote back to a piece I sent from a set of slides from a talk from one of the YAPC's to say: "This is obfuscated code. I refuse to waste time on obfuscated code." I guess its cool to build a constructor on a single line and all. But I wasted an hour looking at this, when "bless { @_ }, $class;" would have immediately communicated to me. Cool as that was, and with all due respect to Andy Lester for his fine work on a very useful tool, but this certainly brought home some of the lessons about coding style I've ben reading in McConnell's "Code Complete", of late. (And my appreciation to which ever monk it was who sent me to that reading recommendation).

    -- Hugh

      I would argue that you didn't waste time.

      It can IMHO help readability to know that "=>" eq ",".

Re: What means: "bless { @_ } => $class;"?
by davorg (Chancellor) on Apr 24, 2006 at 13:25 UTC

    B::Deparse can be useful in situations like this.

    $ perl -MO=Deparse -e 'sub new { my $class = shift; bless { @_ } => $c +lass; }' sub new { my $class = shift @_; bless {@_}, $class; } -e syntax OK
    --
    <http://dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg