uwevoelker has asked for the wisdom of the Perl Monks concerning the following question:
In the Integer class I usepackage base_class; my $parameter_config = { mandatory => {type => 'boolean', default => 0, valid => 0}, }; sub valid_parameter { my @param = @_; foreach (@param) { if (defined $parameter_config->{$_}) { $parameter_config->{$_}->{valid} = 1; } else { die "Parameter $_ not known"; } } return 1; } sub new { # and so on }; 1;
to enable the parameter 'mandatory'. I have written a test suite and it works. But when I use another datatype (String) and do the same with other parameters, they both use the same variables from the base class.&CCS::Data::Datatype::base_class::valid_parameter( qw(mandatory));
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: OO - problem with inheritance
by IlyaM (Parson) on Jan 14, 2002 at 20:07 UTC | |
And in your classes you should call valid_parameter as method: Subclasses which need other configuration of parameters just override method parameter_config.
-- | [reply] [d/l] [select] |
by uwevoelker (Pilgrim) on Jan 14, 2002 at 20:30 UTC | |
thank you for your fast answer. Did I got you right, that when I want to change other configuration parameters like this which is taken from my String class, I need to override your sub parameter_config in this way? But I also need the other parameters from base class (like min => 0 and valid => 0 in this case). Or could I do something like this: My classes not only inherit from base_class.pm. There are also datatypes that inherit from other datatypes. Such as Text inherits from String (but no direct base_class) and PrimaryKey inherits from Integer. Is such inheritance with one of this configuration methods combineable? My goal is, that I can add new parameters only in base_class (let's say has_double_letters or max_number / min_number) and all the datatypes need only to "activate" this new parameters via the ->valid_parameter(qw(mandatory max_number)) call. Thanks, Uwe | [reply] [d/l] [select] |
by IlyaM (Parson) on Jan 14, 2002 at 20:58 UTC | |
This should work if you want to register your parameters in base_class. BTW you don't need to override parameter_config at all in this case because SUPER->parameter_config returns hash reference stored in $parameter_config variable in base class. So next two lines do affect hash used by base_class. If it is not desired effect you should clone that hash: Update: Fixed usage of wrong syntax (SUPER->method instead of __PACKAGE__->SUPER::method)
-- | [reply] [d/l] [select] |
by uwevoelker (Pilgrim) on Jan 14, 2002 at 21:14 UTC | |
by uwevoelker (Pilgrim) on Jan 16, 2002 at 23:27 UTC | |
by IlyaM (Parson) on Jan 17, 2002 at 16:50 UTC | |
|
Re: OO - problem with inheritance
by frag (Hermit) on Jan 14, 2002 at 20:27 UTC | |
I think you'll find perltootc - Tom's OO Tutorial for Class Data in Perl very useful, in particular the section Inheritance Concerns. Borrowing code from that, you can use something like this:
To initialize the package-specific %parameter_config, throw in similar magic into &base_class::new. -- Frag.
| [reply] [d/l] |
by uwevoelker (Pilgrim) on Jan 14, 2002 at 20:47 UTC | |
I would like the accessors _and_ data inherit. In base_class is the big $parameter_config hashref. And there is a constructor new() which execlusively deals with this hashref. He gets his values by $parameter_config->{..}{..} and so on. But the other modules, which inherit from base_class only submit their changes to that huge config-hashref. Because this can't be done directly, I wrote two subroutines in base_class: valid_parameter and config_parameter. I want them to store the additional information in this hashref. But - and here is my problem - this hashref should be unique for each datatype/class. So I would like to access the hashref in base_class but the contents should be specific to the calling class. I agree, that this is very naive. Now I'm searching for an other approach. Have you written my reply to Ilya's answer? I would like to use the last method: copy the hash and change it a little bit. But because it's an hashref, I think this won't work... To your suggestion: I need the %parameter_config hash before new() is called, because new() needs this information to figure out, if the parameters given to new() are correct. So I need code I can run when the class is loaded. Thank you, good bye, Uwe | [reply] |
by frag (Hermit) on Jan 14, 2002 at 21:43 UTC | |
I'm a little confused about what you're doing. You want each change submitted to the base_class's %parameter_config for confirmation; after that, the actual values get stored in each subclass's own %parameter_config, right? If so, just change your accessors so that before fiddling with %sub_class::parameter_config it first messes with %base_class::parameter_config, to do whatever checking/storing you want done there, and then store the data in each individual subclass's hash. (Or, if you follow your new approach, replace "fiddling with %base_class::parameter_config" with "call validation methods from ValidateNewParameter". Same principle.) I need the %parameter_config hash before new() is called, because new() needs this information to figure out, if the parameters given to new() are correct. So I need code I can run when the class is loaded. OK, so put something like this at the start of each subclass: And now each subclass has its own copy of %parameter_config. Just make sure that &base_class::parameter_config returns a copy of the hash. -- Frag.
| [reply] [d/l] |
by uwevoelker (Pilgrim) on Jan 14, 2002 at 21:56 UTC | |
by IlyaM (Parson) on Jan 14, 2002 at 22:08 UTC | |
| |
|
new idea - please comment on this
by uwevoelker (Pilgrim) on Jan 14, 2002 at 21:14 UTC | |
Because the only goal for this $parameter_config hashref is to validate the parameters given to the constructor new() I could write a class ValidateNewParameter.pm. The base_class creates a new ValidateNewParameter object and stores lots of parameters in it. And all the derived datatypes clone this object and add only there changes. I think this could work! And I can even reuse this behaviour in other modules. Also, base_class gets cleaner. What do you think about this idea? Have I overseen something important? Thank you very much | [reply] |
by IlyaM (Parson) on Jan 14, 2002 at 21:30 UTC | |
-- | [reply] |
by uwevoelker (Pilgrim) on Jan 14, 2002 at 21:37 UTC | |
Thank you for your comment. | [reply] |
|
super(params)
by djantzen (Priest) on Jan 15, 2002 at 07:52 UTC | |
This is definitely a hangover from Java, but whenever I do inheritance in Perl, I write the code so that the parent constructor is called from the child class' constructor. In Java, every time you extend a class, whether you say so explicitly or not, you instantiate everything all the way up the hierarchy up to java.lang.Object. In Perl I often see people use inheritance with methods only; that is, they inherit the behavior but not the data. To me, both are necessary for object oriented inheritance. My suggestion is to write the general constructor in the base class with a default value for the parameter checking. If a subclass needs something different, it calls the base class constructor with the proper parameters. In Java, this is super(params), in Perl the child constructor would say: my ($class, $whatever) = @_; my %params = (); # new params to use instead of parent's params my $this = new base_class(%params); # create a new parent bless($this, $class); # rebless into the current package | [reply] [d/l] |
by IlyaM (Parson) on Jan 15, 2002 at 19:12 UTC | |
Note that this variant doesn't hardcode baseclass name. BTW I strongly advice against using $this in Perl code. Most Perl programmers are too get used to $self. I recall than in the company where I worked until recenly we have one programmer (who was Java fan but liked Perl too) who used $this in his code. It was big PITA for everybody who had to edit that code. Fingers just type $self and only later you release (when you see Global symbol "$self" requires explicit package name) that it should be $this. After several such accidents we just told him that $this is forbidden :) Anyway there is nothing wrong in using same constructor in all classes as long as it deffers object initialization to some methods which are overriden in subclasses. Actually it is very common practice and not only in Perl.
-- | [reply] [d/l] [select] |
by frag (Hermit) on Jan 15, 2002 at 23:43 UTC | |
As for $this vs. $self -- it seems that should be a local style standard, and not a global Perl-wide proscription. So long as it's consistent inside a given project, and easily s///able, use $dohickey, $The_Monster, or $Frank. TMTOWTNI. -- Frag.
| [reply] [d/l] |
by djantzen (Priest) on Jan 16, 2002 at 07:54 UTC | |
Okay point taken. However this business with '$self' is truly not something that ought to be mandated across all projects, because while it may be a common idiom in the Perl community (most likely due to the nice phrase 'my $self'), for those of us that work in multiple OO languages it is not the norm. I routinely have to switch between the two, and from experience I declare: it's no big whoop. | [reply] [d/l] |
by frag (Hermit) on Jan 15, 2002 at 23:19 UTC | |
Ugly and hypothetical, but something to be aware of. On second thought, better still: always make any parameter checking in the constructors throw a fatal error. Note such errors in development and change the parent's constructor to play nice. -- Frag.
| [reply] [d/l] [select] |
|
Re: OO - problem with inheritance
by dmmiller2k (Chaplain) on Jan 15, 2002 at 21:14 UTC | |
After reading all of the posts herein, it struck me that you want a separate instance of %parameter_config per derived class, yet shared among all objects of the derived class type. For clarification, assuming you had three classes derived from the base, e.g., Int, String and Float. There would be exactly three instances of %parameter_config (kept somewhere -- read on), regardless of how many Int, String or Float objects you create. Each of the %parameter_config things has in common some basic info, plus some class-specific extra stuff added by each subclass. If this describes your problem, then perhaps I have a solution. Create a class, say, ParamConfig.pm, which consists basically of a blessed hash (%parameter_config ) containing the basic info required by all types. Add one more hash element: parent_type. In the constructor (new method) of this class, accept a parameter, parent_type, which is used to initialize the parent_type hash element. Now, in your base class (from which you will derive Int, String, Float, etc.), you would have code like this: In your derived class (say, Int), you would have something like the following code:
This scheme turns instances of ParamConfig into class-level closures (i.e., singletons), share among all members of the derived classes. Update: the use ParamConfig; belongs in the subclass, not the base class. dmm If you GIVE a man a fish you feed him for a dayBut, TEACH him to fish and you feed him for a lifetime | [reply] [d/l] [select] |
by uwevoelker (Pilgrim) on Jan 16, 2002 at 22:20 UTC | |
you are absolutely right! This is what I wanted. And with the help of IlyaM and frag I started coding my own ParamConfig class yesterday. I have called it Parameter::Validate. If you are interested, I will publish the source code and test script here. I know, the test script is a bit small, but I have only written one or two before. So I'm not familiar with the style of test scripts. And this is the test script: I would like to hear comments to my code. Feedback is very important for me. Please feel free to criticize me! Thank you, Uwe | [reply] [d/l] [select] |