in reply to Re^2: Perl OO: switch package context.
in thread Perl OO: switch package context.

I said I wouldn't show it, but I suppose I will since you're sharing...
sub UNIVERSAL::new { my $class = caller() . "::" . shift; $class->new(@_); }
It works by catching calls to new() on a package that doesn't have a new() defined. We're expecting this to mean the package doesn't really exist, and is instead the suffix of the full package name. We get the beginning of the package name from the package we called it in (caller()) and join it with the suffix (the first argument to new()), and use that as the package name. Example:
package A::B::C; sub new { print "A::B::C new @_\n" } package A::B; C->new(10); # C->new calls UNIVERSAL::new('C', 10) # caller() returns 'A::B' (the package we were in) # UNIVERSAL::new calls A::B::C->new(10)
I'll take my 20 lashes now.

(Double update: merlyn pointed out in a reply that my code is still an infinite loop, so I've readjusted it.) Update: to prevent infinite loops, I changed the code to:

sub UNIVERSAL::new { my $pkg = shift; my ($class, $file, $line) = caller; my $class = "${class}::$pkg"; my $new = $class->can('new'); return $class->$new(@_) if $new != \&UNIVERSAL::new; die qq{Can't locate object method "new" via packages $pkg or $class +at $file line $line.\n};
Gawrsh, now it's lookin' purty.

Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart

Replies are listed 'Best First'.
Re^4: Perl OO: switch package context.
by merlyn (Sage) on May 14, 2005 at 13:36 UTC
    my $new = $class->can('new'); return $class->$new(@_) if $new;
    How does that prevent infinite loops? Won't "can" return the entry in UNIVERSAL now? What you should do is set local $I_AM_INSIDE_UNIVERSAL_NEW = 1, and then detect that for a loopback detection.

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

      Ah, my bad. I hadn't even created the package, so can() returned false. I could use your method, but I'll opt for:
      return $class->$new(@_) if $new != \&UNIVERSAL::new;

      Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
      How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart