Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

ferreira (5993)

ferreira
  (email not shown publicly)
http://www.ferreira.triang.net/

Just another Brazilian Perl hacker.

Journal of ferreira (5993)

Friday December 28, 2007
12:01 PM

The need for SUPER

[ #35228 ]

Also known as "The trap of SUPER::method"

I never have grokked SUPER and what exactly it could do for me. Until I wrote Class::Constructor::Factory.

Class::Constructor::Factory is a helper module to prevent me to spend time writing constructors after using a module like Class::Accessor (and siblings) that gave me for free handy accessors/mutators for object fields. Those modules also gave me a constructor for free. But I am never happy with constructors without a way to specify defaults when initial field values are not given.

So C::C::F is a step towards a more automated way to get better constructors for free and, in a near future, to write classes with less effort. Actually, using the 0.001 version of the module looks like this:

package Foo;

use Class::Constructor::Factory;
use base qw( Class::Accessor Class::Constructor::Factory );

__PACKAGE__->mk_constructor0({
  foo => 42,
  bar => 'fourty-two',
});
__PACKAGE__->mk_accessors(qw( foo bar ));

The thing is that C::C::F augments the actual constructor provided by the IS-A chain of the new package with handling of defaults. So a closure is built and then installed into &Foo::new to work out the wanted magic.

my $foo = Foo->new();
is( $foo->foo, 42 );
is( $foo->bar, 'fourty-two' );

That is rather straightforward and involved code which looked like this:

package Class::Constructor::Factory;

...

sub make_constructor0 {
  my $self = shift;
  ...

  # return a closure
  return sub {
    my $self = shift;
    ...
    return $self->SUPER::new->( $self, \%f ); # XXX the offender
  };
}

I must say that this code is deceptively simple and wrong. Because ->SUPER::new tried to invoke the &new of Class::Constructor::Factory superclasses (which does not exist). I understood why by reading the docs of SUPER and perlobj. The relevant quote is:

"It is important to note that SUPER refers to the superclass(es) of the current package and not to the superclass(es) of the object."

So even after the closure was installed into the Foo namespace, ->SUPER::new yet referred to the superclass of the package where the code was compiled, not doing what I wanted.

The solution is to use SUPER and then rewrite the offender code line as:

    return $self->super('new')->( $self, \%f );

After this, the &new is searched correctly among the superclasses of the object and everything is just fine.

This entry is just to remind me that ->SUPER::method and dynamic code generation (or equivalently dealing with closures in namespaces other than where they were compiled) is at least misleading. I don't claim to have understood all the issues SUPER may address, but I learned something. Thanks, chromatic! And maybe this trap may be turned off in the future by toogling a feature in a future Perl 5 version.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.