http://www.perlmonks.org?node_id=673919

Sixtease has asked for the wisdom of the Perl Monks concerning the following question:

Dear fellows,

I'm making a computational-linguistic application (finding clauses in sentences). The whole thing is a perl module and it has a "train_model" function, which will accept training data and train and save a model. The model itself is pluggable. It's a class, the name of which is in a configuration file or provided to the "new" method. The training itself is then delegated to the model class by calling its train method.

However, the model may need to peek at the various configuration I have stored in the main object. So, when calling the model's train method, I would like its first parameter to be actually the main object. The model class is not instantiated (it needn't even provide a "mew" method - just "train" and "tag") and I only have the name of the class.

I could either make the object think he's an instance of the model class (by blessing its copy or setting local @ISA) or I could explicitly call the train function by no strict 'refs'; &"$model_class::train"($self, training_data) or make a change to the overall design.

What do you think?

A skeleton of the layout:

directory content:

MainApp.pm MyModel.pm config

config:

model:MyModel option:Value

MyModel.pm:

sub train { my ($himself, $training_data) = @_; my $option = $himself->{'option'}; ... }

in MainApp.pm:

sub new { my ($class, $conf_file) = @_ my $options = read_conf($conf_file); # now $options == {model=>'MyModel',option=>'Value'} eval "require $options->{model}"; return bless $options, $class; } sub train_model { my ($self, $raw_data) = @_; my $data = do_magic_with($raw_data); #Either: no strict 'refs'; &"$self->{model}::train"($self, $data); #Or: my $model = $self; bless $model, $self->{'model'}; $model->train($data); #Or: { local @ISA = $self->{model}; $self->train($data); } }
use strict; use warnings; print "Just Another Perl Hacker\n";

Replies are listed 'Best First'.
Re: OO Design Question
by Sixtease (Friar) on Mar 13, 2008 at 07:42 UTC

    Heh, as usual, formulating the question made me reveal an answer. I'll require the models to provide a "new" method, and say

    my $model = $self->{'model'}->new($self); $model->train($data);

    Other suggestions are of course most welcome!

    use strict; use warnings; print "Just Another Perl Hacker\n";
      I see a red herring my $model = $self->{'model'}->new($self);
Re: OO Design Question
by plobsing (Friar) on Mar 14, 2008 at 06:00 UTC
    In stead of holding onto the model name, you could hold on to the resources that the model gives you. In this case (simplification?) its just one sub that you keep around and dispatch to.
    new { my ($class, $conf_file) = @_; my $opts = read_conf( $conf_file ); $opts->{model_trainer} = eval sprintf q{ require %s; \&%s::train }, ($opts->{model}) x 2; # ... validation ... bless $opts, $class; } sub train { my $self = shift; my $data = voodoo( shift ); $self->{model_trainer}->( $self, $data ); }
    I don't really like using eval much. There's probably a better way to get a hard ref to the train function, but I don't see it right now.