trying to export some utility methods, and struggling

trying to export some utility methods, and struggling

am 07.09.2007 10:00:56 von bugbear

Dear All;
I'm trying to make a module to deal with
Widgets (not really, of course)

My design (in object terms) involves
a WidgetBasher, a WidgetManip base class,
and a few Widget sub-classes (WidgetManipA, WidgetManipB ...).

The WidgetBasher class has moderately
complex behaviour and coding, but is
also extensively configurable via WidgetsManips;
the WidgetDoer constructor takes an
array (ref) of WidgetManips.

My intention for the user (also me!)
is to be able to
use WidgetBasher;

and then have the option of making
new WidgetManip sub-classes (if needed),
and then instantiating WidgetBashers
with arrays of (instantiated) WidgetManip
classes.

However, in the problem domain,
I also want the module to make some utility
methods and variables available; I would
like these to be avaiable (nearly) globally,
in that they are of use in the implementation of WidgetBasher,
the implementation of an WidgetManip sub-class,
and of great use to anybody (the user) working
on Widgets.

All of the object stuff I have working happily;
indeed it's rather trivial.

But I cannot for the life of me get my
"utility stuff" where I want it (everywhere!)

As a further requirment, I would ideally
like all this to reside in a single module file.

I have tried rather a lot of variations/permutations
of EXPORT, import, package, BEING { import ... }; etc,
and have come up empty.

If anyone can help I'd be grateful.

BugBear

Re: trying to export some utility methods, and struggling

am 07.09.2007 12:27:12 von paduille.4061.mumia.w+nospam

On 09/07/2007 03:00 AM, bugbear wrote:
> [...]
> I also want the module to make some utility
> methods and variables available; I would
> like these to be avaiable (nearly) globally,
> in that they are of use in the implementation of WidgetBasher,
> the implementation of an WidgetManip sub-class,
> and of great use to anybody (the user) working
> on Widgets.
> [...]

Although it's not illegal to export functions from OO modules in Perl,
it's not such a great idea because you have a much more powerful system
for sharing code if you're using objects.

I suggest abandoning the Exporter and just making the utility routines
class methods, e.g.:

#!/usr/bin/perl
package WidgetBasher;
use strict;
use warnings;

sub utility_function {
my $class = shift;
print "Utility function called (from $class)\n";
}

package WidgetManip;
use base 'WidgetBasher';

package WidgetDoer;
use base 'WidgetBasher';

package main;

# Let's say we're back in the main program now.

WidgetBasher->utility_function();
WidgetManip->utility_function();
WidgetDoer->utility_function();

__HTH__

Re: trying to export some utility methods, and struggling

am 07.09.2007 13:27:14 von bugbear

(reponse at bottom)

Mumia W. wrote:
> On 09/07/2007 03:00 AM, bugbear wrote:
>> [...]
>> I also want the module to make some utility
>> methods and variables available; I would
>> like these to be avaiable (nearly) globally,
>> in that they are of use in the implementation of WidgetBasher,
>> the implementation of an WidgetManip sub-class,
>> and of great use to anybody (the user) working
>> on Widgets.
>> [...]
>
> Although it's not illegal to export functions from OO modules in Perl,
> it's not such a great idea because you have a much more powerful system
> for sharing code if you're using objects.

More powerful, agreed, but in some cases less convenient,
or more verbose.

> I suggest abandoning the Exporter and just making the utility routines
> class methods, e.g.:
>
> #!/usr/bin/perl
> package WidgetBasher;
> use strict;
> use warnings;
>
> sub utility_function {
> my $class = shift;
> print "Utility function called (from $class)\n";
> }
>
> package WidgetManip;
> use base 'WidgetBasher';

No; WidgetManips should not extend WidgetBashers.
Think of WidgetBasher as a food processor,
and WidgetManips as optional attachements.

A "manip" is not a "basher" (or vise versa)

I quite possibly didn't make this clear.

>
> package WidgetDoer;
> use base 'WidgetBasher';
>
> package main;
>
> # Let's say we're back in the main program now.
>
> WidgetBasher->utility_function();
> WidgetManip->utility_function();
> WidgetDoer->utility_function();

Yep, that works, but that's almost exactly what I'm trying to avoid.
I don't want to be forced to have an instance of a class
just to call a utility;

I am aware of the various uses of OO code (I've spent 15 years
on large projects in both Java and C++), but this is not a large
project.

BugBear

Re: trying to export some utility methods, and struggling

am 07.09.2007 17:28:33 von Sherm Pendley

bugbear writes:

> (reponse at bottom)

That's where we expect it to be - no need to point it out.

> Mumia W. wrote:
>
>> # Let's say we're back in the main program now.
>>
>> WidgetBasher->utility_function();
>> WidgetManip->utility_function();
>> WidgetDoer->utility_function();
>
> Yep, that works, but that's almost exactly what I'm trying to avoid.
> I don't want to be forced to have an instance of a class
> just to call a utility;

Good thing that calling a class method doesn't force that.

> I am aware of the various uses of OO code (I've spent 15 years
> on large projects in both Java and C++)

And in all that time you've never heard of class methods?

Astonishing.

sherm--

--
Web Hosting by West Virginians, for West Virginians: http://wv-www.net
Cocoa programming in Perl: http://camelbones.sourceforge.net

Re: trying to export some utility methods, and struggling

am 07.09.2007 21:01:10 von paduille.4061.mumia.w+nospam

On 09/07/2007 06:27 AM, bugbear wrote:
> [...]
> I am aware of the various uses of OO code (I've spent 15 years
> on large projects in both Java and C++), but this is not a large
> project.
>

Okay. What is causing you confusion then? Using the Exporter is too easy.

Without showing any code, you'll probably only get the most general
answers possible.

Re: trying to export some utility methods, and struggling

am 07.09.2007 23:09:13 von Anno Siegel

On 2007-09-07 10:00:56 +0200, bugbear said:

> Dear All;
> I'm trying to make a module to deal with
> Widgets (not really, of course)
>
> My design (in object terms) involves
> a WidgetBasher, a WidgetManip base class,
> and a few Widget sub-classes (WidgetManipA, WidgetManipB ...).
>
> The WidgetBasher class has moderately
> complex behaviour and coding, but is
> also extensively configurable via WidgetsManips;
> the WidgetDoer constructor takes an
> array (ref) of WidgetManips.
>
> My intention for the user (also me!)
> is to be able to
> use WidgetBasher;
>
> and then have the option of making
> new WidgetManip sub-classes (if needed),
> and then instantiating WidgetBashers
> with arrays of (instantiated) WidgetManip
> classes.
>
> However, in the problem domain,
> I also want the module to make some utility
> methods and variables available; I would
> like these to be avaiable (nearly) globally,
> in that they are of use in the implementation of WidgetBasher,
> the implementation of an WidgetManip sub-class,
> and of great use to anybody (the user) working
> on Widgets.
>
> All of the object stuff I have working happily;
> indeed it's rather trivial.
>
> But I cannot for the life of me get my
> "utility stuff" where I want it (everywhere!)
>
> As a further requirment, I would ideally
> like all this to reside in a single module file.

That often requires some extra fiddling with BEGIN blocks
and/or re-ordering the sequence of packages.

> I have tried rather a lot of variations/permutations
> of EXPORT, import, package, BEING { import ... }; etc,
> and have come up empty.

It isn't *that* hard. If you really want to combine importation
and classes, you can do that. Here is one way:

#!/path/to/perl
use strict; use warnings; $| = 1;

WidgetBasher::util1();
WidgetBasher::util2();
exit;

BEGIN {{

### WidgetBasher Class
package WidgetBasher;
Util->import();

# more WidgetBasher code

### Utilitiy package
package Util;
use base 'Exporter';

BEGIN { our @EXPORT = qw( util1 util2) }

sub util1 { print "util1\n" }
sub util2 { print "util2\n" }

}}

Obviously, the utilities could be imported into other Widget-related
classes defined in the same file.

The "big" BEGIN block is only necessary to be able to begin the script
with executable code (instead of class/package definitions). The nested
BEGIN is necessary because the Utility package comes after the class
definition of WidgetBasher.

Anno

Re: trying to export some utility methods, and struggling

am 07.09.2007 23:42:14 von Anno Siegel

On 2007-09-07 13:27:14 +0200, bugbear said:

> (reponse at bottom)
>
> Mumia W. wrote:
>> On 09/07/2007 03:00 AM, bugbear wrote:
>>> [...]
>>> I also want the module to make some utility
>>> methods and variables available; I would
>>> like these to be avaiable (nearly) globally,
>>> in that they are of use in the implementation of WidgetBasher,
>>> the implementation of an WidgetManip sub-class,
>>> and of great use to anybody (the user) working
>>> on Widgets.
>>> [...]
>>
>> Although it's not illegal to export functions from OO modules in Perl,
>> it's not such a great idea because you have a much more powerful system
>> for sharing code if you're using objects.
>
> More powerful, agreed, but in some cases less convenient,
> or more verbose.
>
>> I suggest abandoning the Exporter and just making the utility routines
>> class methods, e.g.:
>>
>> #!/usr/bin/perl
>> package WidgetBasher;
>> use strict;
>> use warnings;
>>
>> sub utility_function {
>> my $class = shift;
>> print "Utility function called (from $class)\n";
>> }
>>
>> package WidgetManip;
>> use base 'WidgetBasher';
>
> No; WidgetManips should not extend WidgetBashers.
> Think of WidgetBasher as a food processor,
> and WidgetManips as optional attachements.
> A "manip" is not a "basher" (or vise versa)

That may be true, but both yould conceivably "be" Utils.

The "is a" metaphor for inheritance relations only carries
so far. A Person class could inherit from Name, Address,
and Occupation (say). In the intuitive sense a person "is"
none of these things, but the OO implementation is perfectly
sane.

Since both WidgetManip and WidgetBasher want to use a common
set of utilites, they share some behavior. The OO way to
implement that would be subclassing.

> I quite possibly didn't make this clear.
>
>>
>> package WidgetDoer;
>> use base 'WidgetBasher';
>>
>> package main;
>>
>> # Let's say we're back in the main program now.
>>
>> WidgetBasher->utility_function();
>> WidgetManip->utility_function();
>> WidgetDoer->utility_function();
>
> Yep, that works, but that's almost exactly what I'm trying to avoid.
> I don't want to be forced to have an instance of a class
> just to call a utility;

You aren't, and Mumia's code doesn't. These are class method calls
and no instantiation is involved.

> I am aware of the various uses of OO code (I've spent 15 years
> on large projects in both Java and C++), but this is not a large
> project.

What passes for Perl OO is rather different from what more
dedicated OO languages offer. Far less is regulated by the system,
(in fact, the implementation is incomplete). That results in more
freedom, for instance allowing mixed OO and exportation. It also
includes the freedom to create incompatible classes and mess things
up in other ways.

Anno

Re: trying to export some utility methods, and struggling

am 10.09.2007 10:52:21 von bugbear

Sherm Pendley wrote:
> bugbear writes:
>
>> (reponse at bottom)
>
> That's where we expect it to be - no need to point it out.
>
>> Mumia W. wrote:
>>
>>> # Let's say we're back in the main program now.
>>>
>>> WidgetBasher->utility_function();
>>> WidgetManip->utility_function();
>>> WidgetDoer->utility_function();
>> Yep, that works, but that's almost exactly what I'm trying to avoid.
>> I don't want to be forced to have an instance of a class
>> just to call a utility;
>
> Good thing that calling a class method doesn't force that.
>
>> I am aware of the various uses of OO code (I've spent 15 years
>> on large projects in both Java and C++)
>
> And in all that time you've never heard of class methods?
>
> Astonishing.

It would be if true, but I *have* heard of class methods.

I am aware of the possibility of doing
BasherUtility::utility_function();

I am also aware of Perl's helpful
facility (called "Exporter", you may have heard
of it) that makes calling externally defined
function more convenient, and it is
this that I wish to exploit.

BugBear

Re: trying to export some utility methods, and struggling

am 10.09.2007 11:10:14 von bugbear

Since I'm not making myself clear (enough), here's
a fairly disembodied version of what I would like to achieve.

Here's my trivial package:

#!/usr/bin/perl

package U;
use base 'Exporter';
use vars qw(@EXPORT);

@EXPORT = qw($glob1 util1 util2);

our $glob1;

sub util1 {
}

sub util2 {
}

sub new {
my ($class, $name) = @_;
my $self = bless {}, $class;
return $self;
}

package X;

sub new {
my ($class, $name) = @_;
my $self = bless {}, $class;
return $self;
}

sub xmethod {
util1();
print $glob1;
}

1;

Here's my trivial use of the package:

#!/usr/bin/perl
use strict;
use warnings;

use U;

util1();

my $u = U->new();

my $x = X->new();

$x->xmethod();

This does *NOT* run successfully; the use of util1() in xmethod gives
Undefined subroutine &X::util1 called at U.pm line 32. Everything
else is as I desire it.

What I would like is to avoid this error, whilst keeping
other properties of the module (especially single file, and no inheritence from
U to X)

I feel it should just be some lines involving EXPORT and IMPORT and BEGIN,
and possibly putting the utils into their own package, but I just can't get it.

BugBear (who has hopefully made himself a little clearer)

Re: trying to export some utility methods, and struggling

am 10.09.2007 12:17:47 von Sherm Pendley

bugbear writes:

> Sherm Pendley wrote:
>> bugbear writes:
>>
>>> (reponse at bottom)
>>
>> That's where we expect it to be - no need to point it out.
>>
>>> Mumia W. wrote:
>>>
>>>> # Let's say we're back in the main program now.
>>>>
>>>> WidgetBasher->utility_function();
>>>> WidgetManip->utility_function();
>>>> WidgetDoer->utility_function();
>>> Yep, that works, but that's almost exactly what I'm trying to avoid.
>>> I don't want to be forced to have an instance of a class
>>> just to call a utility;
>>
>> Good thing that calling a class method doesn't force that.
>>
>>> I am aware of the various uses of OO code (I've spent 15 years
>>> on large projects in both Java and C++)
>>
>> And in all that time you've never heard of class methods?
>>
>> Astonishing.
>
> It would be if true, but I *have* heard of class methods.

Then why are you making bogus claims about being "forced to have an instance
of a class just to call a utility?"

> I am aware of the possibility of doing
> BasherUtility::utility_function();

That's not a class method, it's a plain non-OO function in a package.

Between thinking you need to instantiate an object to call a class method,
and not knowing the difference between a method and a function, it appears
from where I'm sitting that you're far less aware than you claim to be, at
least where Perl's OO is concerned.

> I am also aware of Perl's helpful
> facility (called "Exporter", you may have heard
> of it)

Of course I've heard of it, and used it - might I remind you, I'm not the
one asking for help here.

> that makes calling externally defined
> function more convenient, and it is
> this that I wish to exploit.

OK then. Have a look at "perldoc Exporter" - there's an example of how to
use it at the very top:

package YourModule;
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(munge frobnicate); # symbols to export on request

Then, users of your module would say:

use YourModule qw(munge frobnicate);

What part of this isn't working for you?

sherm--

--
Web Hosting by West Virginians, for West Virginians: http://wv-www.net
Cocoa programming in Perl: http://camelbones.sourceforge.net

Re: trying to export some utility methods, and struggling

am 10.09.2007 15:04:51 von paduille.4061.mumia.w+nospam

On 09/10/2007 04:10 AM, bugbear wrote:
> Since I'm not making myself clear (enough), here's
> a fairly disembodied version of what I would like to achieve.
>
> Here's my trivial package:
>
> #!/usr/bin/perl
>
> package U;
> use base 'Exporter';
> use vars qw(@EXPORT);
>
> @EXPORT = qw($glob1 util1 util2);
>
> our $glob1;
>
> sub util1 {
> }
>
> sub util2 {
> }
>
> sub new {
> my ($class, $name) = @_;
> my $self = bless {}, $class;
> return $self;
> }
>
> package X;
>

What happens when you add this line under "package X" ?

U->import;


> sub new {
> my ($class, $name) = @_;
> my $self = bless {}, $class;
> return $self;
> }
>
> sub xmethod {
> util1();
> print $glob1;
> }
>
> 1;
> [...]
>
> BugBear (who has hopefully made himself a little clearer)

Yes, much clearer.

Re: trying to export some utility methods, and struggling

am 10.09.2007 17:44:02 von Anno Siegel

On 2007-09-10 10:52:21 +0200, bugbear said:

> Sherm Pendley wrote:
>> bugbear writes:
>>
>>> (reponse at bottom)
>>
>> That's where we expect it to be - no need to point it out.
>>
>>> Mumia W. wrote:
>>>
>>>> # Let's say we're back in the main program now.
>>>>
>>>> WidgetBasher->utility_function();
>>>> WidgetManip->utility_function();
>>>> WidgetDoer->utility_function();
>>> Yep, that works, but that's almost exactly what I'm trying to avoid.
>>> I don't want to be forced to have an instance of a class
>>> just to call a utility;
>>
>> Good thing that calling a class method doesn't force that.
>>
>>> I am aware of the various uses of OO code (I've spent 15 years
>>> on large projects in both Java and C++)
>>
>> And in all that time you've never heard of class methods?
>>
>> Astonishing.
>
> It would be if true, but I *have* heard of class methods.
>
> I am aware of the possibility of doing
> BasherUtility::utility_function();

That's not calling utility_function as a class method, just
a fully qualified sub call. It doesn't follow inheritance,
and it doesn't deliver the class name as an argument.

The class method call is

BasherUtility->utility_function();

which does these things.

[...]

Anno