in reply to Is it ok to mix functional and oo programming in one package?

I'd avoid mixing the two models.

If I really needed an imperative interface and an OO interface, I'd be inclined to make an imperative wrapper for an OO library. I'm not 100% sure about how I'd handle the details. I think you'd have to do some autoloading of subroutines.

For example, if I call ImpWrapper::foo(), then ImpWrapper::AUTOLOAD would need to check to see if its global object has a method foo(). If so, we would create ImpWrapper::foo() and have it delegate to  $iw_global_obj->foo().

My AUTOLOAD-fu is not really that good, so to be sure of this approach, I'd have to spend more time than I have investigating it. But it seems like it should work pretty well, as long as you don't do anything crazy, like reblessing your wrapper's object into a different class.

I can imagine a general ImpWrap module that allows you to do something like:

package Imperative::TheObject; use ImpWrap TheObject => ( name => foo, address => '123 A Street', foo => 'bar', );

Then ImpWrap would create a TheObject object, and put it into the Imperative::TheObject namespace. ImpWrap would also insert an appropriate AUTOLOAD routine.

If I ever thought I might need such a thing, it might be an interesting project.


TGI says moo

Replies are listed 'Best First'.
Re^2: Is it ok to mix functional and oo programming in one package?
by TGI (Parson) on Oct 20, 2007 at 06:30 UTC

    Here's a first pass at what I was talking about above:

    use strict; use warnings; package ImpWrap; sub import { my $this = shift; my $class = shift; my $method = shift; my $caller = (caller)[0]; warn "Importing $class/$method from $caller\n"; my $obj = $class->$method(@_); { no strict 'refs'; my $autoload = sub { our $AUTOLOAD; my ($al_method) = $AUTOLOAD =~ /::([^:]*)$/g; if ( $class->can( $al_method ) ) { *{ $AUTOLOAD } = sub { $obj->$al_method( @_ ); }; goto &{$AUTOLOAD}; } else { require Carp; Carp::croak "Undefined subroutine $AUTOLOAD"; } }; # Insert AUTOLOAD function; warn "Setting autoload\n"; *{ "$caller\::AUTOLOAD" } = $autoload; } } package Fuz; use Data::Dumper; sub bizzle { my $self = shift; print "bizzle: $self\n"; print Dumper $self; } sub new { my $class = shift; bless {@_}, $class; } package Foo; our @ISA = ('Fuz'); package IW::Foo; import ImpWrap 'Foo', 'new', (1..4); package IW::Fuz; import ImpWrap 'Fuz', 'new', (11..20); package main; IW::Foo::bizzle(); IW::Fuz::bizzle(); IW::Foo::Grazzle();

    I'm sure there are lots of things this doesn't do quite right yet. I know it doesn't handle autoloads in the wrapped object class properly. Or inherited autoloads.

    The main thing is that it seems to work for basic usage. I create an AUTOLOAD function for the wrapper package that is a closure around the wrapped object. As a result, any class methods will be called as instance methods. I could make it possible to define a list of class methods to call by name, methods to skip, and so forth, by adding appropriate argument handling to the import subroutine.

    Anyhow, this is just a start. I'd like to get proper handling of AUTOLOADs in wrapped objects (with inheritance) and any other gotchas I can think of handled. Any suggestions are welcome.


    TGI says moo