perl-diddler has asked for the wisdom of the Perl Monks concerning the following question:

I was thinking about how in use statements one can sometimes pass configuration options to the module being used.

Say I use a module to implement encapsulated variables in a hash. Maybe one modules wants it to use integer math on the vars. The same Data-encap-mod, might be asked to use extended precision with another mode.

I.e. the base class handles the match, but passing it 'flags' can change the way it functions.

Then I though -- well I can't really store it by calling pack because over it might be a Math-ops that add operations to the Data mod case. It *seems* like I cannot store flags simple based on the calling package, since I might have

int-ops -> Vars main-< extended-precis-ops -> Vars

In each case, Vars might be passed a different config var, but Vars would only would only exist once.

Then I thought about storing the flags in the caller. But that simply pushes the same problem up a level, since elsewhere in the program one could have the same subtree as is under main.

Then I started wondering if they only way to store such options would be in the context of the entire call tree -- but that sounds overly complicated, so I'm wondering if I am missing something.

Is my example clear enough -- have other run into this? It's almost like I need to have my 'use vars' statement return a reference which seems pretty non-standard.

Ideas?

Replies are listed 'Best First'.
Re: Design question: storing package 'flags'.
by Corion (Patriarch) on Jul 09, 2015 at 08:03 UTC

    If you want to have different contexts/configurations, return them as values and don't have use trickery. Follow the example of (say) XML::LibXML , Spreadsheet::ParseExcel and DBI, which give you a "handle" or a "parser" that you configure and then run.

Re: Design question: storing package 'flags'.
by Monk::Thomas (Friar) on Jul 09, 2015 at 11:41 UTC

    Is this correct?: You want a module that can be configured to do stuff differently depending on how it's configured. And you may want to have two or more of these configurations at the same time in the same program. (Otherwise you probably wouldn't worry about clashing variables.)

    To me it seems like you want an object/class. 'instance1' of the object does it this way, 'instance2' of the object does it that way. The customization can then be done during class initialization and then you pass the class instance around and do stuff.

    The following code is only for illustrative purposes. It is incomplete and will not compile. Assume 'Find::Files' is an actual module and does whatever you want it to do.

    # first instance sub magic1 { ... } my $obj1 = Find::Files( 'function' => \&magic1 ); # let's do some magic! $obj1->find_and_call_function('/tmp'); # ------------------------------------------------ # second instance # can be in the same file or in another module sub magic2 { ... } my $obj2 = Find::Files( 'function' => \&magic2 ); # let's do some other magic! $obj2->find_and_call_function('/tmp');
      @Monk:Thomas asked: Is this correct?

      Um, I think you forgot the part where the parameters are passed in the use statement, so their values are available in the 2nd pass.

      This is about the smallest snip I could create. It's a totally *concocted* case but one that does illustrate some of the things I was talking about.

      I think I've gotten the answer to my question -- since no one jumped up and said "oh yeah, use the XXYZ module" or "why don't you just use the "%+" operator that is made for things like this...(i.e. I was thinking this was hard, and wanted to make sure I wasn't missing something). But in the following example,


      main "is a" Data::Vars and is a 'Derived'.
      Derived "is a" Data::Vars and is a Basic.
      Basic "is a" Data::Vars. All are assigning their values to members of the 'struct' that has member's labeled 'one', 'two', 'three'...eight.

      'Derived' tries to assign something to 'eight' at definition time, and 'nine' at execution time. The attempt to assign a value to eight creates no error or warning by default with the idea that it might be legal in a more 'base' class (though was thinking of having a need for a flag (!!!) that might tell it to give an error anyway). I.e. the module might change it's configured behavior based on parameters.

      As a whole, in this while 'main', Derived, and Basic try to assign to the 'blessed HASH' $p:

      • 'main' assign Roman numerals
      • Derived assigns floating point numerals w/".2" added to their named value.
      • Basic tries to assign arabic numerals
      Since they don't all assign to the same members of the set, one can see the precedence of the inheritance and a sample 'motive' for wanting to pass the flags/params along with normal params == i.e. it would be much more useful if I could pass ':format=float|arabic' as a flag and have the data converted at runtime rather than being hard-coded as it is in this example. Here's the code:
      #!/usr/bin/env perl use warnings; use strict; { package Basic; use warnings; use strict; use mem; use P; our @flags; use mem (@flags = qw(one two three four five) ); use Data::Vars \@flags, {one=>1, two=>2, three=>3, four=>4, five=>5} +; sub Decimal() { my $p=shift; P "\nDecimal:p=%s", $p; my $q=__PACKAGE__->new(); $q->three="change 3 to 33/11"; P "Decimal: (one, two, three)=(%s, %s, %s)", $q->one, $q->two, $q- +>three; } } { package Derived; use warnings; use strict; use mem; use P; our @ISA; use mem (&{sub() {push @ISA, q(Basic)}}); use Data::Vars [qw(one two seven)], {one=>1.2, two=>2.2, seven=>7.2, eight=>8.2}; sub new ($) { my $p = shift; my $c=$p||ref $p; bless $p = Basic->new(@_), $c unless ref $p; $p = $p->Data::Vars::new($p); } sub Float() { my $p=shift; P "\nFloat:p=%s", $p; my $q=__PACKAGE__->new(); $q->three="Float: 3.3"; $q->four="Float: Derived 4.4"; my $val = eval { $q->nine="Float: 9.9"; }; if ($@) { P "\nassign to nine got:\n%s\n", $@; } P "Float:q=%s", $q; } 1} package main; use warnings; use strict; use P; use Data::Vars [ qw(one three four) ]; bless my $p = __PACKAGE__->new({one=>'I', three=>'III', four=>'IV'}); P "main:1: p=%s", $p; $p = Derived->new($p); P "main:2: %s", $p; $p->Decimal; $p->Float;

      And it's output:

      > perl multiuse.pl main:1: p=main{four=>"IV", one=>'I', three=>"III"} main:2: Derived{five=>5, four=>"IV", one=>1.20, seven=>7.20, three=>"I +II", two=>2.20} Decimal:p=Derived{five=>5, four=>"IV", one=>1.20, seven=>7.20, three=> +"III", two=>2.20} Decimal: (one, two, three)=(1, 2, change 3 to this txt) Float:p=Derived{five=>5, four=>"IV", one=>1.20, seven=>7.20, three=>"I +II", two=>2.20} assign to nine got: Can't locate object method "nine" via package "Derived" at multiuse.pl + line 37. eval {...} called at multiuse.pl line 37 Derived::Float(Derived=HASH(0x8e5648)) called at multiuse.pl line 56 Float:q=Derived{five=>5, four=>"Float: Derived 4.4", one=>1.20, seven= +>7.20, three=>"Float: 3.3", two=>2.20}

      Comments: ...

      Sorry... ran out of hit points again. Some of the comments and my rational should be more clear now (crossing fingers).... I do understand that this could be a bigger pain that I might want, BUT, I really wanted the 'flags' to mostly pass true/false values (debug, 'useperlonly'...etc).. but then I got to thinking why I shouldn't support other values... and if I didn't, how much might I flagellate myself for laziness. ;-/

      Hope the above isn't too bad to look at... I just realized, that it won't run because Data::Vars isn't in CPAN. It's not that it is buggy, in fact it is fairly mature, but I don't consider it ready until I'm sure I've solved issues *exactly* like this -- the need to pass different flags for different behaviors at runtime.

      If enough people want to try it, I think I can not have it index by CPAN if I put a letter in the VERSION? But I didn't want you to be in the dark about what I was trying to do and why, so forced myself to at least type up this much and create a simple demo case.

      -l

        I'm trying to wrap my head around this and I'm wondering whether you are trying to reinvent objects / classes. The phrase 'available for the second pass' sounds very suspicious. Additionally you already play around with @ISA and blessed.

        Have you read about object orientation in general and Moose / Moo in particular?

Re: Design question: storing package 'flags'.
by Anonymous Monk on Jul 09, 2015 at 08:00 UTC

    Is my example clear enough -- have other run into this? It's almost like I need to have my 'use vars' statement return a reference which seems pretty non-standard. Ideas?

    No, it isn't clear what you're talking about (what you're doing, what you're asking, is the problem organization of implementation...).

    Sounds like you're using a lot of global vars in a kind of overloaded way (everything is "Foo") but it means different things in different contexts...

    The typical way (say log4perl) is to give things names, the things that need to be unique have unique, other things share names

    But this is only a guess

Re: Design question: storing package 'flags'.
by Anonymous Monk on Jul 09, 2015 at 08:06 UTC

    You talk about use but then mention a base class - is your design OO or not? Could you maybe show some short example code to demonstrate the situation you're talking about?

      That's because in one (or more cases) I do setup-work at BEGIN time, so that any invalid references are caught @compile time. I'm not thinking of 1 particular or specific use case, but several use cases that seem related, but that *could* have different design needs -- so I want to find an orthogonal design that accommodates various usages including ones I may not have thought of yet.

      As a simple example of a simple OO usage w/'use'

      use Data::Vars [qw(one two three answer)], {one=>1, two=>2, three=>3}; my $p=Data::Vars=>new(); $p->answer=$p->one+$p->two*$p->three; P "answer=%s", $p->answer; answer=7
      Will have to think of more situation as I'm getting tired right now...