Re: How to implement both object->method and module::function interfa ce?

[email protected] (Bart Lateur) Tue, 08 Aug 2000 23:36:38 +0200
Newsgroups perl.perl6.stdlib
Organization MediaMind
Message-ID <[email protected]>
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.