Guideline RP4: Do not repeat effectively isomorphic code fragments
Going further still with isomorphic code fragments, what if there is a statement that differs in content beyond just a value? That is, previously we've considered two code fragments that could be parameterized to be identical. But how about if we have 10 lines of code in two areas, the only difference being that one has a print statement in the middle, while the other does not (or has a different statement perhaps). You can add logic, via parameters, to restore an isomorphic structure. If, for example, you have a function f with statements A, B, C, D="print abc", E, F and a second with A, B, C, D="store abc", E, F, add a parameter -- f(choice) -- so statement D becomes "if (choice==a) then print abc else store abc".
The example below provides a more real-world study. Here we show three different common means of reading a text file, and we create an isomorphism by using three parameters--not two as you might think at first glance.
# read $file1 as a string... my $string = undef; if (open(READER, $file1)) { local $/; $string = <READER>; close(READER); } # read $file2 as an array... my @arr1 = (); if (open(READER, $file2)) { @arr1 = <READER>; close(READER); } # read $file3 as an array AND remove line terminators... my @arr2 = (); if (open(READER, $file2)) { @arr2 = <READER>; chomp(@arr2) close(READER); } # process $string and arrays @arr1 and @arr2...
sub readFile { my ($fileName, $chompIt) = @_; my $contents = undef; my @contents = (); local *READER; if (open(READER, $fileName)) { if (wantarray) { @contents = <READER>; chomp(@contents) if $chompIt; } else { local $/; $contents = <READER>; } close(READER); } return wantarray ? @contents : $contents; } my $contents = readFile($file1); my @contents = readFile($file2);
The user can direct the function to truncate line endings or not via the chompIt parameter. The second parameter is, of course, the filename, rather than having it hardcoded. Did you spot the third "parameter"? It is implicit--the calling context. Based on whether the context is scalar or array, the function behaves differently.