On Tue, 8 Aug 2000 14:22:20 -0500 , Garrett Goebel wrote:

>What's the conventional wisdom on creating a module that supports both an OO
>and non-OO interface? Are there any CORE or CPAN modules to serve as a
>textbook, or is the anwser "Don't do that"? 
>
>I've got some code that checks the first parameter passed to see if it is a
>reference, assumes any reference is an object reference... and then proceeds
>accordingly. -It feels pretty sloppy, but it works.

Gee, I wonder what this is doing on the Perl6 mailing lists. But, maybe
there are some lessons to be learned, so...

My idea is: "Don't do it". Let me point to just one example: CGI.pm.
Probably one of the most used modules, I might add. Open the source, and
scroll down till you find the definition for self_or_default, around
line 317 ($VERSION = 2.56). Oh hell, here it is:

        sub self_or_default {
            return @_ if defined($_[0]) && (!ref($_[0])) &&
              ($_[0] eq 'CGI');
            unless (defined($_[0]) && 
                    (ref($_[0]) eq 'CGI' || UNIVERSAL::isa($_[0],'CGI'))
                # slightly optimized for common case
            ) {
                $Q = $CGI::DefaultClass->new unless defined($Q);
                unshift(@_,$Q);
            }
            return @_;
        }

Excuse me for the rewrapping. This sub is called at the start of every
single method, I think. It serves to distinguish between a plain sub
call, and a class or method call. If it's a method call, the name of the
"default class" is prepended to the arguments list.

This is a bug waiting to happen. Suppose you call it as a function, but
with a literal string:

        $x = param('x');        # Will work
        $cgi = param('CGI');    # Oops! Major goof here!

It will barf on the latter, because the sub "self_or_default" will think
it is called as a class method, but it isn't.

Lesson to be learned: this is a bug caused by poor design. Perhaps, a
special global variable -- local'ized, of course -- e.g. $SELF, ought to
have been set before the sub is called, to either the object (object
method) or class name (class method); or undef(), if called as a regular
function. The object/class should not have been unshifted unto @_.

Let's do better with Perl6.

p.s. Gee, if Perl6 is going to be so radically different than Perl5,
perhaps we need a new pragma:

        use perl6;

or, in contrast:

        use perl5;

which could turn on/off the backward compatibility mode.

-- 
        Bart.

Reply via email to