in reply to Re: Ordering of parameters - Re^9: Converting Unicode
in thread Converting Unicode
No you are not. BUT pause a moment and think if those variables are just general configuration, settings which can span hundreds of variables. For example, often my subs require a verbosity value and a logger object (or filehandle) to dump debugging information. I can code these two variables into the signature of any sub. And call the sub like: distance($from, $to, $verbosity, $logger). The last two are optional though, if they are undef then it just logs nothing.
Inevitably, at some future time I need to refactor and add another parameter, let's say $timeout, and converting the sub to distance($from, $to, $verbosity, $logger, $timeout). It is a headache to refactor all my code to accommodate this new variable.
In the above, verbosity, logger are optional. The way I handle the complexity is to call them system-wide configuration. And put them into a hash. This hash is created at runtime by reading a configuration file:
$config = { verbosity => 3, logger => new Logger(), ... # hundreds of configuration settings };
And it is now passed around the subs like distance($from, $to, $config). If I need to add a new config variable like timeout, there is no big refactoring. Or, the refactoring is the same but now it is optional and can be done just for those subs that need the new setting, as the needs change.
But then I need to sometimes override a config setting for just one sub, e.g. the timeout. So, why not pass a hash(ref)? Something like this:
$params = { from => ..., to => ..., # override the timeout of the system-wide config timeout => ..., # this is the config read from file config => { verbosity => 3, logger => ..., timeout => 5, ... } }; sub distance { my $params = shift; # the timeout value will be the config's unless # caller passed their own value to temporarily override it my $timeout = exists($params->{timeout}) ? $params->{timeout} : $params->{config}->{timeout} ; ... # similarly, I return back multiple values in a hash(ref) return { errormsg => 'nothing', status => 1, # all OK! distance => 42 }; } # call it my $ret = distance($params); die $ret->{errormsg} unless $ret->{status} == 1;
Now, suppose that a sub needs to save some results for access by other subs to be run later. Well, why not save that into the config under $config->{stash}->{results-of-distance} = { ... }
But what I am showing here is just reinventing the OOP wheel:
# I am skipping some boilerplate package Calc; sub new { my ($configfile, ...) = @_; my $config = read_configfile($configfile); my $internal_data = { config => $config, stash => {} }; # bless etc. } sub distance { my ($internal_data, $params) = @_; # internal_data holds config, # $params holds from, to and anything to override # config just for the life of this call ... # optionally save results to the stash $internal_data->{stash}->{distance} = 42; # return something back return { errormsg => 'nothing', status => 1, # correct distance => 42 }; }
And you use this as:
my $calcobj = Calc->new('settings.config'); my $res = $calcobj->distance({ from => ..., to => ..., # optionally temporarily # override system-wide config setting timeout => ..., });
In the above example you do not have anything global which should be anathema to any programmer.
All data is inside the object, encapsulated so-to-speak. You can have two of those objects running alongside each with a different configuration file. Pass these objects around and you pass: 1) their config data, 2) their state (stash), 3) their logic (subs, algorithms).
I hope that was gentle. Note that I used hashrefs.
bw, bliako
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^3: Ordering of parameters - Re^9: Converting Unicode
by Polyglot (Chaplain) on Dec 22, 2023 at 08:47 UTC | |
by Bod (Parson) on Dec 22, 2023 at 16:19 UTC | |
by hippo (Archbishop) on Dec 22, 2023 at 09:15 UTC | |
by bliako (Abbot) on Dec 22, 2023 at 11:33 UTC |